Files
goirsdk/eventutils/eventutils_linux.go
T

178 lines
3.8 KiB
Go

//go:build linux && cgo
package mmaputils
/*
#include <semaphore.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
static inline void* open_posix_semaphore(const char* name) {
sem_t* sem = sem_open(name, O_CREAT, 0666, 0);
if (sem == SEM_FAILED) {
return NULL;
}
return (void*)sem;
}
static inline void close_posix_semaphore(void* sem_ptr) {
if (sem_ptr != NULL) {
sem_close((sem_t*)sem_ptr);
}
}
static inline int timed_wait_posix_semaphore(void* sem_ptr, long timeout_ms) {
if (sem_ptr == NULL) {
return -1;
}
sem_t* sem = (sem_t*)sem_ptr;
// Drain the semaphore
while (sem_trywait(sem) == 0) {}
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout_ms / 1000;
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
}
int res;
do {
res = sem_timedwait(sem, &ts);
} while (res == -1 && errno == EINTR); // Retry if interrupted by Go GC/scheduler
return res;
}
static inline int signal_posix_semaphore(const char* name) {
if (name == NULL) {
return -1;
}
sem_t* sem = sem_open(name, 0);
if (sem == SEM_FAILED) {
return -1;
}
int res = sem_post(sem);
sem_close(sem);
return res;
}
static inline int post_posix_semaphore(void* sem_ptr) {
if (sem_ptr != NULL) {
return sem_post((sem_t*)sem_ptr);
}
return -1;
}
static inline int unlink_posix_semaphore(const char* name) {
if (name == NULL) {
return -1;
}
return sem_unlink(name);
}
*/
import "C"
import (
"fmt"
"strings"
"time"
"unsafe"
"github.com/ESilva15/goirsdk/sharedMem"
)
type utils struct {
semName string
sem unsafe.Pointer
}
func newUtils() (*utils, error) {
return &utils{}, nil
}
func (u *utils) Close() {
if u.sem != nil {
C.close_posix_semaphore(u.sem)
u.sem = nil
}
}
// OpenMemMap returns a Reader interface that can be used to read the data
// No need to encapsulate it
func OpenMemMap(name string, size uint32) (Reader, error) {
file, err := sharedMem.Open(name, size)
if err != nil {
return nil, fmt.Errorf("failed to open `%s` with err: %+v", name, err)
}
return file, nil
}
// OpenEvent creates or connects to a Unix socket for event signaling on Linux
func (u *utils) OpenEvent(eventName string) error {
u.semName = "/" + strings.TrimPrefix(eventName, "/")
cName := C.CString(u.semName)
defer C.free(unsafe.Pointer(cName))
sem := C.open_posix_semaphore(cName)
if sem == nil {
return fmt.Errorf("failed to open POSIX semaphore: %s", u.semName)
}
u.sem = sem
return nil
}
func (u *utils) OpenBroadcastChannel(name string) error {
// No-op or log stub on Linux
return nil
}
// CheckValidDataEvent waits for a pulse byte sent over the socket
func (u *utils) CheckValidDataEvent(timeout time.Duration) bool {
if u.sem == nil {
return false
}
ms := C.long(timeout.Milliseconds())
res := C.timed_wait_posix_semaphore(u.sem, ms)
return res == 0
}
func (u *utils) SendBroadcastMessage(id, p1, p2 uintptr) error {
return nil
}
func (u *utils) SignalEvent() error {
if u.sem == nil {
return fmt.Errorf("u.sem is not set")
}
C.post_posix_semaphore(u.sem)
return nil
}
func signalEvent(name string) {
semName := "/" + strings.TrimPrefix(name, "/")
cName := C.CString(semName)
defer C.free(unsafe.Pointer(cName))
C.signal_posix_semaphore(cName)
}
func cleanupEvent(name string) {
semName := "/" + strings.TrimPrefix(name, "/")
cName := C.CString(semName)
defer C.free(unsafe.Pointer(cName))
C.unlink_posix_semaphore(cName)
}