diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 25009dc88bc..566fd63f1fb 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -37,14 +37,13 @@ typedef unsigned long timer_t; /* Thread attributes */ struct pthread_attr { - int priority; void *stack; - uint32_t stacksize; - uint32_t flags; - uint32_t delayedstart; - uint32_t schedpolicy; - int32_t detachstate; - uint32_t initialized; + uint16_t stacksize; + int8_t priority; + uint8_t schedpolicy: 2; + bool initialized: 1; + bool cancelstate: 1; + bool detachstate: 1; }; #if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ || defined(CONFIG_ARCMWDT_LIBC) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index ccb1c71a4bd..d380e691d66 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -19,9 +19,14 @@ extern "C" { #endif -/* Pthread detach/joinable */ -#define PTHREAD_CREATE_DETACHED 0 -#define PTHREAD_CREATE_JOINABLE 1 +/* + * Pthread detach/joinable + * Undefine possibly predefined values by external toolchain headers + */ +#undef PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED 1 +#undef PTHREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_JOINABLE 0 /* Pthread resource visibility */ #define PTHREAD_PROCESS_PRIVATE 0 diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index e809b539c6a..207236e085c 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -18,6 +18,17 @@ #include #include +#define ZEPHYR_TO_POSIX_PRIORITY(_zprio) \ + (((_zprio) < 0) ? (-1 * ((_zprio) + 1)) : (CONFIG_NUM_PREEMPT_PRIORITIES - (_zprio)-1)) + +#define POSIX_TO_ZEPHYR_PRIORITY(_prio, _pol) \ + (((_pol) == SCHED_FIFO) ? (-1 * ((_prio) + 1)) \ + : (CONFIG_NUM_PREEMPT_PRIORITIES - (_prio)-1)) + +#define DEFAULT_PTHREAD_PRIORITY \ + POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY) +#define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO) + LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE @@ -26,9 +37,18 @@ LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); #define DYNAMIC_STACK_SIZE 0 #endif -#define _pthread_cancel_pos LOG2(PTHREAD_CANCEL_DISABLE) +/* The maximum allowed stack size (for this implementation) */ +#define PTHREAD_STACK_MAX (UINT16_MAX + 1) -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +static inline size_t __get_attr_stacksize(const struct pthread_attr *attr) +{ + return attr->stacksize + 1; +} + +static inline void __set_attr_stacksize(struct pthread_attr *attr, size_t size) +{ + attr->stacksize = size - 1; +} struct __pthread_cleanup { void (*routine)(void *arg); @@ -45,6 +65,9 @@ enum posix_thread_qid { POSIX_THREAD_DONE_Q, }; +/* only 2 bits in struct pthread_attr for schedpolicy */ +BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2)); + BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1)); @@ -60,18 +83,13 @@ static struct k_spinlock pthread_pool_lock; static int pthread_concurrency; static const struct pthread_attr init_pthread_attrs = { - .priority = 0, .stack = NULL, .stacksize = 0, - .flags = PTHREAD_INIT_FLAGS, - .delayedstart = 0, -#if defined(CONFIG_PREEMPT_ENABLED) - .schedpolicy = SCHED_RR, -#else - .schedpolicy = SCHED_FIFO, -#endif - .detachstate = PTHREAD_CREATE_JOINABLE, + .priority = DEFAULT_PTHREAD_PRIORITY, + .schedpolicy = DEFAULT_PTHREAD_POLICY, .initialized = true, + .cancelstate = PTHREAD_CANCEL_ENABLE, + .detachstate = PTHREAD_CREATE_JOINABLE, }; /* @@ -201,35 +219,27 @@ static bool is_posix_policy_prio_valid(uint32_t priority, int policy) static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) { - uint32_t prio; - if (z_prio < 0) { - *policy = SCHED_FIFO; - prio = -1 * (z_prio + 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES); + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_COOP_PRIORITIES); } else { - *policy = SCHED_RR; - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio - 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_PREEMPT_PRIORITIES); + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES); } - return prio; + *policy = (z_prio < 0) ? SCHED_FIFO : SCHED_RR; + return ZEPHYR_TO_POSIX_PRIORITY(z_prio); } static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) { - int32_t prio; - if (policy == SCHED_FIFO) { - /* Zephyr COOP priority starts from -1 */ + /* COOP: highest [CONFIG_NUM_COOP_PRIORITIES, -1] lowest */ __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); - prio = -1 * (priority + 1); } else { + /* PREEMPT: lowest [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1] highest */ __ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES); - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1); } - return prio; + return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); } /** @@ -242,8 +252,8 @@ int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param * struct pthread_attr *attr = (struct pthread_attr *)_attr; int priority = schedparam->sched_priority; - if ((attr == NULL) || (attr->initialized == 0U) || - (is_posix_policy_prio_valid(priority, attr->schedpolicy) == false)) { + if (attr == NULL || !attr->initialized || + is_posix_policy_prio_valid(priority, attr->schedpolicy == false)) { LOG_ERR("Invalid pthread_attr_t or sched_param"); return EINVAL; } @@ -266,8 +276,13 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi return EACCES; } + if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { + LOG_ERR("Invalid stacksize %zu", stacksize); + return EINVAL; + } + attr->stack = stackaddr; - attr->stacksize = stacksize; + __set_attr_stacksize(attr, stacksize); return 0; } @@ -279,8 +294,9 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr) } /* caller-provided thread stack */ - if (attr->initialized == 0U || attr->stack == NULL || attr->stacksize == 0) { - LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or is of size 0"); + if (!attr->initialized || attr->stack == NULL || attr->stacksize == 0 || + __get_attr_stacksize(attr) < PTHREAD_STACK_MIN) { + LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or invalid size"); return false; } @@ -290,19 +306,6 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr) return false; } - /* require a valid detachstate */ - if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE || - attr->detachstate == PTHREAD_CREATE_DETACHED)) { - LOG_ERR("Invalid detachstate %d", attr->detachstate); - return false; - } - - /* we cannot create an essential thread (i.e. one that may not abort) */ - if ((attr->flags & K_ESSENTIAL) != 0) { - LOG_ERR("Cannot create an essential thread"); - return false; - } - return true; } @@ -431,11 +434,12 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou if (attr == NULL) { attr = &attr_storage; - attr->stacksize = DYNAMIC_STACK_SIZE; - attr->stack = - k_thread_stack_alloc(attr->stacksize, k_is_user_context() ? K_USER : 0); + BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); + __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); + attr->stack = k_thread_stack_alloc(__get_attr_stacksize(attr), + k_is_user_context() ? K_USER : 0); if (attr->stack == NULL) { - LOG_ERR("Unable to allocate stack of size %u", attr->stacksize); + LOG_ERR("Unable to allocate stack of size %u", DYNAMIC_STACK_SIZE); return EAGAIN; } LOG_DBG("Allocated thread stack %p", attr->stack); @@ -454,9 +458,7 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou sys_dlist_append(&run_q, &t->q_node); t->qid = POSIX_THREAD_RUN_Q; t->detachstate = attr->detachstate; - if ((BIT(_pthread_cancel_pos) & attr->flags) != 0) { - t->cancel_state = PTHREAD_CANCEL_ENABLE; - } + t->cancel_state = attr->cancelstate; t->cancel_pending = false; sys_slist_init(&t->key_list); sys_slist_init(&t->cleanup_list); @@ -491,10 +493,8 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou /* spawn the thread */ k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, (void *)arg, threadroutine, - IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) - : NULL, - posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags, - K_MSEC(attr->delayedstart)); + IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, + posix_to_zephyr_priority(attr->priority, attr->schedpolicy), 0, K_NO_WAIT); if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { /* wait for the spawned thread to cross our barrier */ @@ -664,15 +664,16 @@ int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_para * * See IEEE 1003.1 */ -int pthread_attr_init(pthread_attr_t *attr) +int pthread_attr_init(pthread_attr_t *_attr) { + struct pthread_attr *const attr = (struct pthread_attr *)_attr; if (attr == NULL) { LOG_ERR("Invalid attr pointer"); return ENOMEM; } - (void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t)); + (void)memcpy(attr, &init_pthread_attrs, sizeof(struct pthread_attr)); return 0; } @@ -747,7 +748,7 @@ void pthread_exit(void *retval) CODE_UNREACHABLE; } - /* Make a thread as cancelable before exiting */ + /* Mark a thread as cancellable before exiting */ key = k_spin_lock(&pthread_pool_lock); self->cancel_state = PTHREAD_CANCEL_ENABLE; k_spin_unlock(&pthread_pool_lock, key); @@ -870,7 +871,7 @@ int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } @@ -887,8 +888,9 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) { struct pthread_attr *attr = (struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U) || - (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) { + if ((attr == NULL) || (attr->initialized == false) || + ((detachstate != PTHREAD_CREATE_DETACHED) && + (detachstate != PTHREAD_CREATE_JOINABLE))) { return EINVAL; } @@ -939,11 +941,11 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } - *stacksize = attr->stacksize; + *stacksize = __get_attr_stacksize(attr); return 0; } @@ -960,11 +962,11 @@ int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) return EINVAL; } - if (stacksize < PTHREAD_STACK_MIN) { + if (stacksize == 0 || stacksize < PTHREAD_STACK_MIN || stacksize > PTHREAD_STACK_MAX) { return EINVAL; } - attr->stacksize = stacksize; + __set_attr_stacksize(attr, stacksize); return 0; } @@ -977,12 +979,12 @@ int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t { const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; } *stackaddr = attr->stack; - *stacksize = attr->stacksize; + *stacksize = __get_attr_stacksize(attr); return 0; } @@ -995,7 +997,7 @@ int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param * { struct pthread_attr *attr = (struct pthread_attr *)_attr; - if ((attr == NULL) || (attr->initialized == 0U)) { + if ((attr == NULL) || (attr->initialized == false)) { return EINVAL; }