From 52c2fdbdd9aa446aa7e9c55e581212ccb6e22629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Mon, 19 Jan 2026 18:40:35 +0100 Subject: [PATCH 1/6] semaphores: add semaphoreTryDown and semaphoreCount functions JIRA: RTOS-1088 --- include/sys/threads.h | 6 +++ sys/semaphore.c | 95 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/include/sys/threads.h b/include/sys/threads.h index cfb8ab9f..ed647055 100644 --- a/include/sys/threads.h +++ b/include/sys/threads.h @@ -113,12 +113,18 @@ extern int semaphoreCreate(semaphore_t *s, unsigned int v); extern int semaphoreDown(semaphore_t *s, time_t timeout); +extern int semaphoreTryDown(semaphore_t *s); + + extern int semaphoreUp(semaphore_t *s); extern int semaphoreDone(semaphore_t *s); +extern int semaphoreCount(semaphore_t *s); + + extern int phCondCreate(handle_t *h, const struct condAttr *attr); diff --git a/sys/semaphore.c b/sys/semaphore.c index cf300714..4cdb6459 100644 --- a/sys/semaphore.c +++ b/sys/semaphore.c @@ -3,32 +3,58 @@ * * Semaphores * - * Copyright 2012, 2017, 2018 Phoenix Systems + * Copyright 2012, 2017, 2018, 2026 Phoenix Systems * Copyright 2006 Pawel Pisarczyk - * Author: Pawel Pisarczyk, Aleksander Kaminski + * Author: Pawel Pisarczyk, Aleksander Kaminski, Michal Lach * * This file is part of Phoenix-RTOS. * * %LICENSE% */ +#include #include #include #include +#include #include #include +int semaphoreCount(semaphore_t *s) +{ + int ret = 0, count = 0; + + if (s == NULL) { + return -EINVAL; + } + + ret = mutexTry(s->mutex); + if (ret != EOK) { + return 0; + } + + count = s->v; + assert(count >= 0); /* s->v is unsigned, we don't want to overflow */ + mutexUnlock(s->mutex); + + return count; +} + + int semaphoreCreate(semaphore_t *s, unsigned int v) { - if (s == NULL) + if (s == NULL || v > SEM_VALUE_MAX) { return -EINVAL; + } - if (mutexCreate(&s->mutex) != EOK) + if (mutexCreate(&s->mutex) != EOK) { return -ENOMEM; + } - if (condCreate(&s->cond) != EOK) + if (condCreate(&s->cond) != EOK) { return -ENOMEM; + } s->v = v; @@ -41,8 +67,9 @@ int semaphoreDown(semaphore_t *s, time_t timeout) int err = EOK; time_t now, when = 0; - if (s == NULL) + if (s == NULL) { return -EINVAL; + } if (timeout) { gettime(&now, NULL); @@ -56,16 +83,19 @@ int semaphoreDown(semaphore_t *s, time_t timeout) break; } - if ((err = condWait(s->cond, s->mutex, timeout)) == -ETIME) + if ((err = condWait(s->cond, s->mutex, timeout)) == -ETIME) { break; + } if (timeout) { gettime(&now, NULL); - if (now >= when) + if (now >= when) { timeout = 1; - else + } + else { timeout = when - now; + } } } mutexUnlock(s->mutex); @@ -74,31 +104,62 @@ int semaphoreDown(semaphore_t *s, time_t timeout) } +int semaphoreTryDown(semaphore_t *s) +{ + int ret = EOK; + + if (s == NULL) { + return -EINVAL; + } + + ret = mutexTry(s->mutex); + if (ret != EOK) { + return ret; + } + + else if (s->v <= 0) { + ret = -EAGAIN; + } + else { + --s->v; + } + + mutexUnlock(s->mutex); + return ret; +} + + int semaphoreUp(semaphore_t *s) { - if (s == NULL) + int ret = EOK; + + if (s == NULL) { return -EINVAL; + } mutexLock(s->mutex); - condSignal(s->cond); if (s->v == (unsigned int)-1) { - mutexUnlock(s->mutex); - return -EAGAIN; + ret = -EAGAIN; + } + else if (s->v + 1 > SEM_VALUE_MAX) { + ret = -EOVERFLOW; + } + else { + ++s->v; } - ++s->v; mutexUnlock(s->mutex); - - return EOK; + return ret; } int semaphoreDone(semaphore_t *s) { - if (s == NULL) + if (s == NULL) { return -EINVAL; + } resourceDestroy(s->mutex); resourceDestroy(s->cond); From 7cf9daf5429b6a5f7757570ff3820bd522c5d55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Wed, 7 Jan 2026 17:44:50 +0100 Subject: [PATCH 2/6] posix: implement sem_* family functions JIRA: RTOS-1088 --- include/semaphore.h | 61 ++++++ include/sys/semaphore.h | 26 +++ posix/Makefile | 2 +- posix/sem.c | 419 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 include/semaphore.h create mode 100644 include/sys/semaphore.h create mode 100644 posix/sem.c diff --git a/include/semaphore.h b/include/semaphore.h new file mode 100644 index 00000000..73076e46 --- /dev/null +++ b/include/semaphore.h @@ -0,0 +1,61 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * POSIX implementation - semaphores + * + * Copyright 2026 Phoenix Systems + * Author: Michał Lach + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include + +#define SEM_FAILED ((sem_t *)0xDAAB0000) +#define SEM_VALUE_MAX UINT_MAX + +typedef struct _sem_t { + /* clang-format off */ + enum { smNamed, smUnnamed } type; + /* clang-format on */ + + union { + semaphore_t unnamed; + oid_t named; + }; +} sem_t; + +extern int sem_wait(sem_t *sem); + + +extern int sem_trywait(sem_t *sem); + + +extern int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict abs_timeout); + + +extern int sem_getvalue(sem_t *restrict sem, int *restrict value); + + +extern int sem_post(sem_t *sem); + + +extern int sem_close(sem_t *sem); + + +extern sem_t *sem_open(const char *name, int oflag, ... /* mode_t mode, unsigned int value */); + + +extern int sem_unlink(const char *name); + + +extern int sem_destroy(sem_t *sem); + + +extern int sem_init(sem_t *sem, int pshared, unsigned int value); diff --git a/include/sys/semaphore.h b/include/sys/semaphore.h new file mode 100644 index 00000000..0c2b57e5 --- /dev/null +++ b/include/sys/semaphore.h @@ -0,0 +1,26 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * POSIX implementation - semaphores + * + * Copyright 2026 Phoenix Systems + * Author: Michał Lach + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include + +#define SEMAPHORE_PATH ("/dev/posix/sem/") +#define SEMCTL_PATH ("/dev/posix/semctl") +#define SEMAPHORE_MAX_COUNT (128) +#define SEMAPHORE_NAME_MAX (NAME_MAX - sizeof(SEMAPHORE_PATH) - 1) + +#define SEM_UP _IO('s', 0x1) +#define SEM_DOWN _IO('s', 0x2) +#define SEM_DOWN_TRY _IO('s', 0x3) +#define SEM_DOWN_TIMEOUT _IOW('s', 0x4, time_t) diff --git a/posix/Makefile b/posix/Makefile index e4d46467..722f2876 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -5,4 +5,4 @@ # Author: Pawel Pisarczyk # -OBJS += $(addprefix $(PREFIX_O)posix/, stubs.o utils.o idtree.o) +OBJS += $(addprefix $(PREFIX_O)posix/, stubs.o utils.o idtree.o sem.o) diff --git a/posix/sem.c b/posix/sem.c new file mode 100644 index 00000000..a37c94ca --- /dev/null +++ b/posix/sem.c @@ -0,0 +1,419 @@ +/* + * Phoenix-RTOS + * + * libphoenix + * + * POSIX implementation - semaphores + * + * Copyright 2026 Phoenix Systems + * Author: Michal Lach + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int sem_open_msg(sem_t *sem) +{ + int ret = EOK; + msg_t msg = { + .type = mtOpen, + .oid = sem->named, + }; + + ret = msgSend(sem->named.port, &msg); + if (ret == EOK) { + ret = msg.o.err; + } + + return ret; +} + + +static int sem_down_msg(sem_t *sem, bool try, time_t timeout) +{ + int ret = EOK; + msg_t msg = { + .type = mtDevCtl, + .oid = sem->named, + }; + ioctl_in_t *data; + + data = (ioctl_in_t *)&msg.i.raw; + if (try) { + data->request = SEM_DOWN_TRY; + } + else if (timeout > 0) { + data->request = SEM_DOWN_TIMEOUT; + *((time_t *)data->data) = timeout; + } + else { + data->request = SEM_DOWN; + } + + ret = msgSend(sem->named.port, &msg); + if (ret == EOK) { + ret = msg.o.err; + } + + return ret; +} + + +static int sem_create_msg(const char *name, int value, oid_t *oid) +{ + int ret = EOK; + oid_t semctl; + msg_t msg; + + ret = lookup(SEMCTL_PATH, NULL, &semctl); + if (ret != EOK) { + return ret; + } + + memset(&msg, 0, sizeof(msg)); + msg.type = mtCreate; + msg.oid = semctl; + msg.i.create.type = value; + msg.i.create.mode = 0; + msg.i.data = name; + msg.i.size = strlen(name) + 1; + + ret = msgSend(semctl.port, &msg); + if (ret == EOK) { + *oid = msg.o.create.oid; + ret = msg.o.err; + } + + return ret; +} + + +static int sem_lookup(const char *name, oid_t *sem) +{ + int ret = EOK; + DIR *dirp; + char *path; + struct dirent *dent; + oid_t oid; + + dirp = opendir(SEMAPHORE_PATH); + if (dirp == NULL) { + /* posixsrv has yet not initialized the semaphore subsystem */ + return -ENODEV; + } + + path = (char *)malloc(PATH_MAX); + if (path == NULL) { + closedir(dirp); + return -ENOMEM; + } + + for (;;) { + errno = 0; + dent = readdir(dirp); + if (dent == NULL) { + closedir(dirp); + free(path); + ret = -ENOENT; + break; + } + + if (strcmp(name, dent->d_name) == 0) { + strlcpy(path, SEMAPHORE_PATH, PATH_MAX); + strlcat(path, dent->d_name, PATH_MAX); + ret = lookup(path, NULL, &oid); + assert(ret == EOK); + *sem = oid; + closedir(dirp); + free(path); + ret = EOK; + break; + } + } + + return ret; +} + + +sem_t *sem_open(const char *name, int oflag, ...) +{ + va_list list; + int err = EOK; + mode_t mode = 0; + unsigned int value = 0; + sem_t *sem; + + (void)mode; + + if (name == NULL || strlen(name) > SEMAPHORE_NAME_MAX) { + SET_ERRNO(-EINVAL); + return SEM_FAILED; + } + + sem = (sem_t *)malloc(sizeof(*sem)); + if (sem == NULL) { + SET_ERRNO(-ENOMEM); + return SEM_FAILED; + } + + sem->type = smNamed; + + if ((oflag & O_CREAT) != 0U) { + va_start(list, oflag); + mode = va_arg(list, mode_t); + value = va_arg(list, unsigned int); + va_end(list); + } + + if ((oflag & O_CREAT) != 0U && (oflag & O_EXCL) != 0U) { + err = sem_create_msg(name, value, &sem->named); + } + else { + err = sem_lookup(name, &sem->named); + if ((oflag & O_CREAT) != 0U && err != EOK) { + err = sem_create_msg(name, value, &sem->named); + } + } + + if (err != EOK) { + SET_ERRNO(err); + free(sem); + return SEM_FAILED; + } + + err = sem_open_msg(sem); + if (err != EOK) { + SET_ERRNO(err); + free(sem); + return SEM_FAILED; + } + + return sem; +} + + +int sem_wait(sem_t *sem) +{ + int ret = EOK; + + if (sem == NULL) { + ret = -EINVAL; + } + + if (sem->type == smNamed) { + ret = sem_down_msg(sem, false, 0); + } + else if (sem->type == smUnnamed) { + ret = semaphoreDown(&sem->unnamed, 0); + } + else { + ret = -EINVAL; + } + + return SET_ERRNO(ret); +} + + +int sem_trywait(sem_t *sem) +{ + int ret = EOK; + + if (sem == NULL) { + ret = -EINVAL; + } + + if (sem->type == smNamed) { + ret = sem_down_msg(sem, true, 0); + } + else if (sem->type == smUnnamed) { + ret = semaphoreTryDown(&sem->unnamed); + } + else { + ret = -EINVAL; + } + + return SET_ERRNO(ret); +} + + +int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict abs_timeout) +{ + int ret = EOK; + time_t timeout = 0, now = 0, offs = 0; + + gettime(&now, &offs); + now += offs; + + timeout += abs_timeout->tv_sec * 1000000 + abs_timeout->tv_nsec / 1000; + timeout -= now; + + if (sem == NULL) { + ret = -EINVAL; + } + + if (sem->type == smNamed) { + ret = sem_down_msg(sem, false, timeout); + } + else if (sem->type == smUnnamed) { + ret = semaphoreDown(&sem->unnamed, timeout); + if (ret == -ETIME) { + ret = -ETIMEDOUT; + } + } + else { + ret = -EINVAL; + } + + return SET_ERRNO(ret); +} + + +int sem_post(sem_t *sem) +{ + int ret = EOK; + msg_t msg = { 0 }; + ioctl_in_t *data; + + if (sem == NULL) { + return SET_ERRNO(-EINVAL); + } + + if (sem->type == smNamed) { + msg.type = mtDevCtl; + msg.oid = sem->named; + data = (ioctl_in_t *)msg.i.raw; + data->request = SEM_UP; + ret = msgSend(sem->named.port, &msg); + if (ret == EOK) { + ret = msg.o.err; + } + } + else if (sem->type == smUnnamed) { + ret = semaphoreUp(&sem->unnamed); + } + else { + ret = -EINVAL; + } + + return SET_ERRNO(ret); +} + + +int sem_getvalue(sem_t *restrict sem, int *restrict value) +{ + int ret = EOK; + msg_t msg; + + if (sem == NULL) { + return SET_ERRNO(-EINVAL); + } + + if (sem->type == smNamed) { + memset(&msg, 0, sizeof(msg)); + msg.type = mtGetAttr; + msg.oid = sem->named; + ret = msgSend(sem->named.port, &msg); + if (ret == EOK && value != NULL) { + *value = msg.o.attr.val; + } + } + else if (sem->type == smUnnamed) { + ret = semaphoreCount(&sem->unnamed); + if (ret > 0) { + if (value != NULL) { + *value = ret; + } + ret = EOK; + } + } + else { + ret = -EINVAL; + } + + return SET_ERRNO(ret); +} + + +int sem_close(sem_t *sem) +{ + int ret = EOK; + msg_t msg; + + if (sem == NULL || sem->type != smNamed) { + return SET_ERRNO(-EINVAL); + } + + msg.type = mtClose; + msg.oid = sem->named; + ret = msgSend(sem->named.port, &msg); + + return SET_ERRNO(ret); +} + + +int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + int ret = EOK; + sem_t new = { 0 }; + + if (pshared != 0) { + ret = -ENOSYS; + } + else if (sem == NULL) { + ret = -EINVAL; + } + else { + new.type = smUnnamed; + ret = semaphoreCreate(&new.unnamed, value); + } + + *sem = new; + + return SET_ERRNO(ret); +} + + +int sem_destroy(sem_t *sem) +{ + int ret = -EINVAL; + + if (sem != NULL && sem->type == smUnnamed) { + ret = semaphoreDone(&sem->unnamed); + } + + return SET_ERRNO(ret); +} + + +int sem_unlink(const char *name) +{ + int ret = EOK; + oid_t oid; + msg_t msg; + + ret = sem_lookup(name, &oid); + if (ret == EOK) { + msg.type = mtDestroy; + msg.oid = oid; + ret = msgSend(oid.port, &msg); + } + + return SET_ERRNO(ret); +} From 6bee49905540d76f5beade0f7dd154d1bfd48aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Mon, 2 Feb 2026 02:06:18 +0100 Subject: [PATCH 3/6] sem: move SEM_VALUE_MAX to sys/semaphore.h It might be better to keep OS specific constants in corresponding sys/ headers JIRA: RTOS-1088 --- include/semaphore.h | 4 ++-- include/sys/semaphore.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/semaphore.h b/include/semaphore.h index 73076e46..332acccd 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -16,9 +16,9 @@ #include #include #include +#include -#define SEM_FAILED ((sem_t *)0xDAAB0000) -#define SEM_VALUE_MAX UINT_MAX +#define SEM_FAILED ((sem_t *)0xDAAB0000) typedef struct _sem_t { /* clang-format off */ diff --git a/include/sys/semaphore.h b/include/sys/semaphore.h index 0c2b57e5..ac9e9897 100644 --- a/include/sys/semaphore.h +++ b/include/sys/semaphore.h @@ -13,12 +13,14 @@ * %LICENSE% */ +#include #include #define SEMAPHORE_PATH ("/dev/posix/sem/") #define SEMCTL_PATH ("/dev/posix/semctl") #define SEMAPHORE_MAX_COUNT (128) #define SEMAPHORE_NAME_MAX (NAME_MAX - sizeof(SEMAPHORE_PATH) - 1) +#define SEM_VALUE_MAX INT_MAX #define SEM_UP _IO('s', 0x1) #define SEM_DOWN _IO('s', 0x2) From d7c5d40241046e609d8e94d72afb973656a9e02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Tue, 10 Feb 2026 14:13:38 +0100 Subject: [PATCH 4/6] include/semaphore.h: remove unused struct name JIRA: RTOS-1088 --- include/semaphore.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/semaphore.h b/include/semaphore.h index 332acccd..28b47f09 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -20,7 +20,7 @@ #define SEM_FAILED ((sem_t *)0xDAAB0000) -typedef struct _sem_t { +typedef struct { /* clang-format off */ enum { smNamed, smUnnamed } type; /* clang-format on */ From f3710e3c9b94f4ea24aa72aa602ed0d22ca2d0b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Tue, 10 Feb 2026 14:14:11 +0100 Subject: [PATCH 5/6] include/sys/semaphore.h: remove parentheses from string constants JIRA: RTOS-1088 --- include/sys/semaphore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sys/semaphore.h b/include/sys/semaphore.h index ac9e9897..187f1030 100644 --- a/include/sys/semaphore.h +++ b/include/sys/semaphore.h @@ -16,8 +16,8 @@ #include #include -#define SEMAPHORE_PATH ("/dev/posix/sem/") -#define SEMCTL_PATH ("/dev/posix/semctl") +#define SEMAPHORE_PATH "/dev/posix/sem/" +#define SEMCTL_PATH "/dev/posix/semctl" #define SEMAPHORE_MAX_COUNT (128) #define SEMAPHORE_NAME_MAX (NAME_MAX - sizeof(SEMAPHORE_PATH) - 1) #define SEM_VALUE_MAX INT_MAX From 239fd04b84d7fc28913a977c69f680037d4d2bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lach?= Date: Tue, 10 Feb 2026 15:31:03 +0100 Subject: [PATCH 6/6] poxix/sem: consistently return -ENODEV if posixsrv isn't initialized JIRA: RTOS-1088 --- posix/sem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posix/sem.c b/posix/sem.c index a37c94ca..87a012cb 100644 --- a/posix/sem.c +++ b/posix/sem.c @@ -84,7 +84,7 @@ static int sem_create_msg(const char *name, int value, oid_t *oid) ret = lookup(SEMCTL_PATH, NULL, &semctl); if (ret != EOK) { - return ret; + return -ENODEV; } memset(&msg, 0, sizeof(msg));