diff --git a/include/golioth/golioth_sys.h b/include/golioth/golioth_sys.h index e3556c84c..98370a0d8 100644 --- a/include/golioth/golioth_sys.h +++ b/include/golioth/golioth_sys.h @@ -52,6 +52,19 @@ bool golioth_sys_sem_give(golioth_sys_sem_t sem); void golioth_sys_sem_destroy(golioth_sys_sem_t sem); int golioth_sys_sem_get_fd(golioth_sys_sem_t sem); +/*-------------------------------------------------- + * Signals + *------------------------------------------------*/ + +// Opaque handle for signal +typedef void *golioth_sys_signal_t; + +golioth_sys_signal_t golioth_sys_signal_create(void); +bool golioth_sys_signal_poll(golioth_sys_signal_t sig, int32_t ms_to_wait); +bool golioth_sys_signal_raise(golioth_sys_signal_t sig); +void golioth_sys_signal_reset(golioth_sys_signal_t sig); +void golioth_sys_signal_destroy(golioth_sys_signal_t sig); + /*-------------------------------------------------- * Software Timers *------------------------------------------------*/ diff --git a/port/freertos/golioth_sys_freertos.c b/port/freertos/golioth_sys_freertos.c index 64978809a..8cba1d670 100644 --- a/port/freertos/golioth_sys_freertos.c +++ b/port/freertos/golioth_sys_freertos.c @@ -83,6 +83,59 @@ int golioth_sys_sem_get_fd(golioth_sys_sem_t sem) return -1; } +/*-------------------------------------------------- + * Signals + *------------------------------------------------*/ + +golioth_sys_signal_t golioth_sys_signal_create(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +bool golioth_sys_signal_poll(golioth_sys_signal_t sig, int32_t ms_to_wait) +{ + if (!sig) + { + return false; + } + + TickType_t ticks_to_wait = (ms_to_wait < 0 ? portMAX_DELAY : pdMS_TO_TICKS(ms_to_wait)); + + return (pdPASS == ulTaskNotifyTake(pdTRUE, ticks_to_wait)); +} + +bool golioth_sys_signal_raise(golioth_sys_signal_t sig) +{ + if (!sig) + { + return false; + } + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + vTaskNotifyGiveFromISR((TaskHandle_t) sig, &xHigherPriorityTaskWoken); + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + return true; +} + +void golioth_sys_signal_reset(golioth_sys_signal_t sig) +{ + if (!sig) + { + return; + } + + xTaskNotifyStateClear((TaskHandle_t) sig); +} + +void golioth_sys_signal_destroy(golioth_sys_signal_t sig) +{ + /* We didn't allocate any memory for TaskHandle_t */ + (void) sig; + return; +} + /*-------------------------------------------------- * Software Timers *------------------------------------------------*/ diff --git a/port/linux/golioth_sys_linux.c b/port/linux/golioth_sys_linux.c index 634316c37..ea888b4df 100644 --- a/port/linux/golioth_sys_linux.c +++ b/port/linux/golioth_sys_linux.c @@ -183,6 +183,83 @@ int golioth_sys_sem_get_fd(golioth_sys_sem_t sem) return SEM_TO_FD(sem); } +/*-------------------------------------------------- + * Signals + *------------------------------------------------*/ + +struct condition_and_mutex +{ + pthread_cond_t cond; + pthread_mutex_t lock; +}; + +golioth_sys_signal_t golioth_sys_signal_create(void) +{ + struct condition_and_mutex *sig = golioth_sys_malloc(sizeof(struct condition_and_mutex)); + pthread_cond_init(&sig->cond, NULL); + pthread_mutex_init(&sig->lock, NULL); + return (golioth_sys_signal_t) sig; +} + +bool golioth_sys_signal_poll(golioth_sys_signal_t sig, int32_t ms_to_wait) +{ + if (!sig) + { + return false; + } + + int ret = 0; + struct condition_and_mutex *signal = sig; + struct timespec abstime; + + pthread_mutex_lock(&signal->lock); + + if (ms_to_wait < 0) + { + ret = (0 == pthread_cond_wait(&signal->cond, &signal->lock)); + goto signal_poll_finish; + } + + clock_gettime(CLOCK_REALTIME, &abstime); + + if (ms_to_wait) + { + abstime.tv_sec += ms_to_wait / 1000; + abstime.tv_nsec += (ms_to_wait % 1000) * 1000000; + } + + ret = (0 == pthread_cond_timedwait(&signal->cond, &signal->lock, &abstime)); + +signal_poll_finish: + pthread_mutex_unlock(&signal->lock); + return ret; +} + +bool golioth_sys_signal_raise(golioth_sys_signal_t sig) +{ + if (!sig) + { + return false; + } + + struct condition_and_mutex *signal = sig; + return (0 == pthread_cond_signal(&signal->cond)); +} + +void golioth_sys_signal_reset(golioth_sys_signal_t sig) +{ + /* There is nothing to reset */ + return; +} + +void golioth_sys_signal_destroy(golioth_sys_signal_t sig) +{ + struct condition_and_mutex *signal = sig; + pthread_cond_destroy(&signal->cond); + pthread_mutex_destroy(&signal->lock); + golioth_sys_free(sig); +} + /*-------------------------------------------------- * Software Timers *------------------------------------------------*/ diff --git a/port/zephyr/golioth_sys_zephyr.c b/port/zephyr/golioth_sys_zephyr.c index a1aeb65a0..65078c119 100644 --- a/port/zephyr/golioth_sys_zephyr.c +++ b/port/zephyr/golioth_sys_zephyr.c @@ -130,6 +130,58 @@ int golioth_sys_sem_get_fd(golioth_sys_sem_t sem) return SEM_TO_FD(sem); } +/*-------------------------------------------------- + * Signals + *------------------------------------------------*/ + +golioth_sys_signal_t golioth_sys_signal_create(void) +{ + struct k_poll_signal *sig = golioth_sys_malloc(sizeof(struct k_poll_signal)); + k_poll_signal_init(sig); + return sig; +} + +bool golioth_sys_signal_poll(golioth_sys_signal_t sig, int32_t ms_to_wait) +{ + if (!sig) + { + return false; + } + + k_timeout_t timeout = (ms_to_wait <= GOLIOTH_SYS_WAIT_FOREVER ? K_FOREVER : K_MSEC(ms_to_wait)); + + struct k_poll_event events[1] = { + K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, sig), + }; + + k_poll(events, 1, timeout); + + int signaled, result; + k_poll_signal_check(sig, &signaled, &result); + + return (signaled != 0 ? true : false); +} + +bool golioth_sys_signal_raise(golioth_sys_signal_t sig) +{ + return (0 == k_poll_signal_raise(sig, 0)); +} + +void golioth_sys_signal_reset(golioth_sys_signal_t sig) +{ + if (!sig) + { + return; + } + + k_poll_signal_reset(sig); +} + +void golioth_sys_signal_destroy(golioth_sys_signal_t sig) +{ + golioth_sys_free(sig); +} + /*-------------------------------------------------- * Software Timers *------------------------------------------------*/