From 6d69ded31b3afcba29290c7380e5c3cad53bdb8c Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Tue, 21 Jul 2026 18:54:28 +0200 Subject: [PATCH 1/2] !sys/threads.h: declare mutexConsistent and mutexPrioCieiling syscalls TASK: RTOS-1399 --- include/sys/threads.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/sys/threads.h b/include/sys/threads.h index d5113427..2d0a501c 100644 --- a/include/sys/threads.h +++ b/include/sys/threads.h @@ -104,6 +104,12 @@ extern int mutexLock2(handle_t h1, handle_t h2); extern int mutexTry(handle_t h); +extern int mutexConsistent(handle_t h); + + +extern int mutexPrioCeiling(handle_t h, int prioceiling); + + extern int mutexUnlock(handle_t h); From 73eab799f06047dd5af5b14103e90a17e50fea4f Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Tue, 21 Jul 2026 18:53:21 +0200 Subject: [PATCH 2/2] pthread: implement mutexattrs, mutex_consistent and mutex_{get,set}prioceiling TASK: RTOS-1399 --- include/pthread.h | 44 ++++++++- pthread/pthread.c | 231 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 244 insertions(+), 31 deletions(-) diff --git a/include/pthread.h b/include/pthread.h index c55c1d2d..98aec2c1 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -35,9 +35,9 @@ extern "C" { #define PTHREAD_EXPLICIT_SCHED 0 #define PTHREAD_INHERIT_SCHED 1 -#define PTHREAD_PRIO_NONE 0 -#define PTHREAD_PRIO_INHERIT 1 -#define PTHREAD_PRIO_PROTECT 2 +#define PTHREAD_PRIO_NONE PH_LOCK_PROTO_NOINHERIT +#define PTHREAD_PRIO_INHERIT PH_LOCK_PROTO_INHERIT +#define PTHREAD_PRIO_PROTECT PH_LOCK_PROTO_PRIOCEILING #define PTHREAD_PROCESS_SHARED 0 #define PTHREAD_PROCESS_PRIVATE 1 @@ -52,6 +52,9 @@ extern "C" { #define PTHREAD_MUTEX_RECURSIVE PH_LOCK_RECURSIVE #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + #define PTHREAD_ONCE_INIT 1 #define PTHREAD_CANCEL_DISABLE 0 @@ -160,12 +163,21 @@ int pthread_mutex_destroy(pthread_mutex_t *); int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict mutex, int *__restrict prioceiling); + + +int pthread_mutex_setprioceiling(pthread_mutex_t *__restrict mutex, int prioceiling, int *__restrict old_ceiling); + + int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_consistent(pthread_mutex_t *mutex); + + int pthread_mutex_unlock(pthread_mutex_t *); @@ -175,7 +187,31 @@ int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_init(pthread_mutexattr_t *attr); -int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict attr, int *__restrict prioceiling); + + +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling); + + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict attr, int *__restrict protocol); + + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); + + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict attr, int *__restrict pshared); + + +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); + + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict attr, int *__restrict robust); + + +int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust); + + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict attr, int *__restrict type); int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); diff --git a/pthread/pthread.c b/pthread/pthread.c index 9fd464d7..e80b206c 100644 --- a/pthread/pthread.c +++ b/pthread/pthread.c @@ -24,6 +24,8 @@ #define ALIGN(value, size) ((((value) + (size) - 1) / (size)) * (size)) +#define PRIO_DEFAULT 4 + #define PTHREAD_ONCE_DONE 0 #define PTHREAD_ONCE_IN_PROGRESS 2 #define PTHREAD_COND_CLOCK_DEFAULT CLOCK_MONOTONIC @@ -101,7 +103,7 @@ typedef struct _pthread_cleanup_t { static const pthread_attr_t pthread_attr_default = { .stackaddr = NULL, .schedpolicy = SCHED_RR, - .priority = 4, + .priority = PRIO_DEFAULT, .detachstate = PTHREAD_CREATE_JOINABLE, .inheritsched = PTHREAD_INHERIT_SCHED, .stacksize = ALIGN(PTHREAD_STACK_MIN, PAGE_SIZE), @@ -218,7 +220,7 @@ static int pthread_create_main(void) int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) + void *(*start_routine)(void *), void *arg) { const pthread_attr_t *attrs = &pthread_attr_default; @@ -549,8 +551,8 @@ __attribute__((noreturn)) void pthread_exit(void *value_ptr) } -#define DECLARE_PTHREAD_ATTR_GET_EX(attr_name, attr_type, res, body) \ - int pthread_attr_get##attr_name(const pthread_attr_t *__restrict attr, attr_type *__restrict res) \ +#define DECLARE_PTHREAD_ATTR_GET_EX(attr_class, attr_name, attr_type, res, body) \ + int pthread_##attr_class##_get##attr_name(const pthread_##attr_class##_t *__restrict attr, attr_type *__restrict res) \ { \ if (attr == NULL || (res) == NULL) { \ return EINVAL; \ @@ -560,11 +562,11 @@ __attribute__((noreturn)) void pthread_exit(void *value_ptr) } \ return 0; \ } -#define DECLARE_PTHREAD_ATTR_GET(attr_name, attr_type, res) DECLARE_PTHREAD_ATTR_GET_EX(attr_name, attr_type, res, { *(res) = attr->attr_name; }) +#define DECLARE_PTHREAD_ATTR_GET(attr_name, attr_type, res) DECLARE_PTHREAD_ATTR_GET_EX(attr, attr_name, attr_type, res, { *(res) = attr->attr_name; }) DECLARE_PTHREAD_ATTR_GET(stackaddr, void *, stackaddr); DECLARE_PTHREAD_ATTR_GET(stacksize, size_t, stacksize); -DECLARE_PTHREAD_ATTR_GET_EX(schedparam, struct sched_param, param, { param->sched_priority = attr->priority; }); +DECLARE_PTHREAD_ATTR_GET_EX(attr, schedparam, struct sched_param, param, { param->sched_priority = attr->priority; }); DECLARE_PTHREAD_ATTR_GET(schedpolicy, int, policy); DECLARE_PTHREAD_ATTR_GET(detachstate, int, detachstate); DECLARE_PTHREAD_ATTR_GET(guardsize, size_t, guardsize); @@ -616,23 +618,23 @@ int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, - size_t stacksize) + size_t stacksize) { return pthread_attr_setstackaddr(attr, stackaddr) | - pthread_attr_setstacksize(attr, stacksize); + pthread_attr_setstacksize(attr, stacksize); } int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, - size_t *stacksize) + size_t *stacksize) { return pthread_attr_getstackaddr(attr, stackaddr) | - pthread_attr_getstacksize(attr, stacksize); + pthread_attr_getstacksize(attr, stacksize); } int pthread_attr_setschedparam(pthread_attr_t *attr, - const struct sched_param *param) + const struct sched_param *param) { if (attr == NULL || param == NULL) { return EINVAL; @@ -739,15 +741,19 @@ int pthread_setschedprio(pthread_t thread, int prio); int pthread_getschedparam(pthread_t thread, int *policy, - struct sched_param *__restrict param); + struct sched_param *__restrict param); int pthread_setschedparam(pthread_t thread, int policy, - const struct sched_param *param); + const struct sched_param *param); static int pthread_mutex_lazy_init(pthread_mutex_t *mutex) { + if (mutex == NULL) { + return -EINVAL; + } + int err = 0; if (mutex->initialized == 0) { mutexLock(pthread_common.mutex_cond_init_lock); @@ -767,7 +773,16 @@ static int pthread_mutex_lazy_init(pthread_mutex_t *mutex) int pthread_mutex_init(pthread_mutex_t *__restrict mutex, const pthread_mutexattr_t *__restrict attr) { int err; + + if (mutex == NULL) { + return EINVAL; + } + if (attr == NULL) { + /* + * POSIX-DEVIATION: POSIX says that mutexes should have PTHREAD_PRIO_NONE by + * default. Phoenix has PTHREAD_PRIO_INHERIT instead. + */ err = mutexCreate(&mutex->mutexh); } else { @@ -777,6 +792,50 @@ int pthread_mutex_init(pthread_mutex_t *__restrict mutex, const pthread_mutexatt if (err == 0) { mutex->initialized = 1; } + + return -err; +} + + +int pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict mutex, int *__restrict prioceiling) +{ + if (prioceiling == NULL) { + return EINVAL; + } + + int err = pthread_mutex_lazy_init((pthread_mutex_t *)mutex); + if (err < 0) { + return -err; + } + + err = mutexPrioCeiling(mutex->mutexh, -1); + if (err >= 0) { + *prioceiling = err; + err = EOK; + } + + return -err; +} + + +int pthread_mutex_setprioceiling(pthread_mutex_t *__restrict mutex, int prioceiling, int *__restrict old_ceiling) +{ + if (old_ceiling == NULL) { + return EINVAL; + } + + int err = pthread_mutex_lazy_init(mutex); + if (err < 0) { + return -err; + } + + err = mutexPrioCeiling(mutex->mutexh, prioceiling); + + if (err >= 0) { + *old_ceiling = err; + err = EOK; + } + return -err; } @@ -785,7 +844,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) { int err = pthread_mutex_lazy_init(mutex); - if (err == 0) { + if (err == EOK) { err = mutexLock(mutex->mutexh); } @@ -836,40 +895,158 @@ int pthread_mutex_destroy(pthread_mutex_t *mutex) int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { - return 0; + return attr == NULL ? EINVAL : EOK; } int pthread_mutexattr_init(pthread_mutexattr_t *attr) { + if (attr == NULL) { + return EINVAL; + } + attr->type = PTHREAD_MUTEX_DEFAULT; - return 0; + attr->robust = PTHREAD_MUTEX_STALLED; + /* + * POSIX-DEVIATION: POSIX says that mutexes should have PTHREAD_PRIO_NONE by + * default. Phoenix has PTHREAD_PRIO_INHERIT instead. (Same as in pthread_mutex_init()) + */ + attr->protocol = PTHREAD_PRIO_INHERIT; + attr->prioceiling = PRIO_DEFAULT; + + return EOK; } -int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) +#define DECLARE_PTHREAD_MUTEXATTR_GET(attr_name, attr_type, res) DECLARE_PTHREAD_ATTR_GET_EX(mutexattr, attr_name, attr_type, res, { *(res) = attr->attr_name; }) +DECLARE_PTHREAD_MUTEXATTR_GET(prioceiling, int, prioceiling); +DECLARE_PTHREAD_MUTEXATTR_GET(protocol, int, protocol); +DECLARE_PTHREAD_MUTEXATTR_GET(robust, int, robust); +DECLARE_PTHREAD_MUTEXATTR_GET(type, int, type); + + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict attr, int *__restrict pshared) { - *type = attr->type; - return 0; + if (attr == NULL || pshared == NULL) { + return EINVAL; + } + + *(pshared) = PTHREAD_PROCESS_PRIVATE; + + return EOK; } -int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) { - int err = EINVAL; + int err = EOK; + sched_info_t info; - /* clang-format off */ - if ((type == PTHREAD_MUTEX_NORMAL) || (type == PTHREAD_MUTEX_ERRORCHECK) || - (type == PTHREAD_MUTEX_RECURSIVE) || (type == PTHREAD_MUTEX_DEFAULT)) { - /* clang-format on */ + if (attr == NULL) { + return EINVAL; + } - attr->type = type; - err = 0; + /* + * POSIX-DEVIATION: POSIX says that prioceiling should be in range of allowed + * SCHED_FIFO priorities. Kernel currently doesn't support SCHED_FIFO, so + * check against SCHED_RR priorities instead. + */ + if (schedInfo(getpid(), SCHED_RR, &info) < 0) { + return EINVAL; } + + if (prioceiling > info.maxPriority || prioceiling < info.minPriority) { + return EINVAL; + } + + attr->prioceiling = prioceiling; + + return err; +} + + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) +{ + int err = EOK; + + if (attr == NULL) { + return EINVAL; + } + + if (protocol != PTHREAD_PRIO_NONE && protocol != PTHREAD_PRIO_INHERIT && protocol != PTHREAD_PRIO_PROTECT) { + return EINVAL; + } + + attr->protocol = protocol; + return err; } +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + if (attr == NULL) { + return EINVAL; + } + + /* TODO: commodify with the rest of pshared setters */ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) { + return EINVAL; + } + + /* OS-LIMITATION: PTHREAD_PROCESS_SHARED not supported */ + if (pshared == PTHREAD_PROCESS_SHARED) { + return ENOTSUP; + } + + return EOK; +} + + +int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust) +{ + if (attr == NULL) { + return EINVAL; + } + + if (robust != PTHREAD_MUTEX_STALLED && robust != PTHREAD_MUTEX_ROBUST) { + return EINVAL; + } + + attr->robust = robust; + + return EOK; +} + + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + if (attr == NULL) { + return EINVAL; + } + + if (type != PTHREAD_MUTEX_NORMAL && type != PTHREAD_MUTEX_ERRORCHECK && type != PTHREAD_MUTEX_RECURSIVE && type != PTHREAD_MUTEX_DEFAULT) { + return EINVAL; + } + + attr->type = type; + + return EOK; +} + + +int pthread_mutex_consistent(pthread_mutex_t *mutex) +{ + int err = pthread_mutex_lazy_init(mutex); + + if (err == EOK) { + err = mutexConsistent(mutex->mutexh); + } + + return -err; +} + + int sched_yield(void) { return -usleep(0);