From c8aa6570c14dfc64ccfafd2c73a924bebc227a56 Mon Sep 17 00:00:00 2001 From: Youvedeep Singh Date: Thu, 28 Dec 2017 14:31:57 +0530 Subject: [PATCH] kernel: POSIX: Compatibility layer for pthread APIs. This patch provides pthread APIs for POSIX 1003.1 PSE52 standard. Signed-off-by: Youvedeep Singh --- arch/posix/include/posix_cheats.h | 35 ++ include/posix/pthread.h | 94 ++++++ include/posix/sched.h | 33 ++ include/posix/sys/types.h | 19 +- kernel/CMakeLists.txt | 2 + kernel/Kconfig | 16 +- kernel/posix/CMakeLists.txt | 1 + kernel/posix/pthread.c | 537 ++++++++++++++++++++++++++++++ 8 files changed, 731 insertions(+), 6 deletions(-) create mode 100644 include/posix/sched.h create mode 100644 kernel/posix/pthread.c diff --git a/arch/posix/include/posix_cheats.h b/arch/posix/include/posix_cheats.h index cfa6727d02..ae2420515c 100644 --- a/arch/posix/include/posix_cheats.h +++ b/arch/posix/include/posix_cheats.h @@ -30,7 +30,9 @@ #define pthread_condattr_t zap_pthread_condattr_t #define pthread_barrier_t zap_pthread_barrier_t #define pthread_barrierattr_t zap_pthread_barrierattr_t +#define pthread_attr_t zap_pthread_attr_t +/* Condition variables */ #define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__) #define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__) #define pthread_cond_signal(...) zap_pthread_cond_signal(__VA_ARGS__) @@ -39,6 +41,7 @@ #define pthread_cond_timedwait(...) zap_pthread_cond_timedwait(__VA_ARGS__) #define pthread_condattr_init(...) zap_pthread_condattr_init(__VA_ARGS__) #define pthread_condattr_destroy(...) zap_pthread_condattr_destroy(__VA_ARGS__) +/* Mutex */ #define pthread_mutex_init(...) zap_pthread_mutex_init(__VA_ARGS__) #define pthread_mutex_destroy(...) zap_pthread_mutex_destroy(__VA_ARGS__) #define pthread_mutex_lock(...) zap_pthread_mutex_lock(__VA_ARGS__) @@ -48,6 +51,7 @@ #define pthread_mutexattr_init(...) zap_pthread_mutexattr_init(__VA_ARGS__) #define pthread_mutexattr_destroy(...) \ zap_pthread_mutexattr_destroy(__VA_ARGS__) +/* Barrier */ #define pthread_barrier_wait(...) zap_pthread_barrier_wait(__VA_ARGS__) #define pthread_barrier_init(...) zap_pthread_barrier_init(__VA_ARGS__) #define pthread_barrier_destroy(...) zap_pthread_barrier_destroy(__VA_ARGS__) @@ -55,6 +59,37 @@ #define pthread_barrierattr_destroy(...) \ zap_pthread_barrierattr_destroy(__VA_ARGS__) +/* pthread */ +#define pthread_attr_init(...) zap_pthread_attr_init(__VA_ARGS__) +#define pthread_attr_destroy(...) zap_pthread_attr_destroy(__VA_ARGS__) +#define pthread_attr_getschedparam(...) \ + zap_pthread_attr_getschedparam(__VA_ARGS__) +#define pthread_attr_getstack(...) zap_pthread_attr_getstack(__VA_ARGS__) +#define pthread_attr_getstacksize(...) \ + zap_pthread_attr_getstacksize(__VA_ARGS__) +#define pthread_equal(...) zap_pthread_equal(__VA_ARGS__) +#define pthread_self(...) zap_pthread_self(__VA_ARGS__) +#define pthread_getschedparam(...) zap_pthread_getschedparam(__VA_ARGS__) +#define pthread_exit(...) zap_pthread_exit(__VA_ARGS__) +#define pthread_join(...) zap_pthread_join(__VA_ARGS__) +#define pthread_detach(...) zap_pthread_detach(__VA_ARGS__) +#define pthread_cancel(...) zap_pthread_cancel(__VA_ARGS__) +#define pthread_attr_getdetachstate(...) \ + zap_pthread_attr_getdetachstate(__VA_ARGS__) +#define pthread_attr_setdetachstate(...) \ + zap_pthread_attr_setdetachstate(__VA_ARGS__) +#define pthread_attr_setschedparam(...) \ + zap_pthread_attr_setschedparam(__VA_ARGS__) +#define pthread_attr_setschedpolicy(...)\ + zap_pthread_attr_setschedpolicy(__VA_ARGS__) +#define pthread_attr_getschedpolicy(...)\ + zap_pthread_attr_getschedpolicy(__VA_ARGS__) + +#define pthread_attr_setstack(...) zap_pthread_attr_setstack(__VA_ARGS__) +#define pthread_create(...) zap_pthread_create(__VA_ARGS__) +#define pthread_setcancelstate(...) zap_pthread_setcancelstate(__VA_ARGS__) +#define pthread_setschedparam(...) zap_pthread_setschedparam(__VA_ARGS__) + #endif /* CONFIG_ARCH_POSIX */ #endif diff --git a/include/posix/pthread.h b/include/posix/pthread.h index 58c743b54f..a452e07477 100644 --- a/include/posix/pthread.h +++ b/include/posix/pthread.h @@ -7,6 +7,7 @@ #ifndef __PTHREAD_H__ #define __PTHREAD_H__ +#include #ifdef CONFIG_NEWLIB_LIBC #include #else @@ -20,6 +21,46 @@ struct timespec { #endif /* CONFIG_NEWLIB_LIBC */ #include "sys/types.h" +#include "sched.h" + +enum pthread_state { + /* The thread is running and joinable. */ + PTHREAD_JOINABLE = 0, + /* The thread is running and detached. */ + PTHREAD_DETACHED, + /* A joinable thread exited and its return code is available. */ + PTHREAD_EXITED, + /* The thread structure is unallocated and available for reuse. */ + PTHREAD_TERMINATED +}; + +struct posix_thread { + struct k_thread thread; + + /* Exit status */ + void *retval; + + /* Pthread cancellation */ + int cancel_state; + int cancel_pending; + struct k_sem cancel_lock_sem; + pthread_mutex_t cancel_lock; + + /* Pthread State */ + enum pthread_state state; + pthread_mutex_t state_lock; + struct k_sem state_lock_sem; + pthread_cond_t state_cond; +}; + +/* Pthread detach/joinable */ +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +/* Pthread cancellation */ +#define _PTHREAD_CANCEL_POS 0 +#define PTHREAD_CANCEL_ENABLE (0 << _PTHREAD_CANCEL_POS) +#define PTHREAD_CANCEL_DISABLE (1 << _PTHREAD_CANCEL_POS) static inline s32_t _ts_to_ms(const struct timespec *to) { @@ -359,4 +400,57 @@ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *); int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); */ +/* Base Pthread related APIs */ + +/** + * @brief Obtain ID of the calling thread. + * + * The results of calling this API from threads not created with + * pthread_create() are undefined. + * + * See IEEE 1003.1 + */ +static inline pthread_t pthread_self(void) +{ + return (pthread_t)k_current_get(); +} + + +/** + * @brief Compare thread IDs. + * + * See IEEE 1003.1 + */ +static inline int pthread_equal(pthread_t pt1, pthread_t pt2) +{ + return (pt1 == pt2); +} + +int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); +int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); +int pthread_attr_init(pthread_attr_t *attr); +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_getschedparam(const pthread_attr_t *attr, + struct sched_param *schedparam); +int pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param); +int pthread_attr_getstack(const pthread_attr_t *attr, + void **stackaddr, size_t *stacksize); +int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, + size_t stacksize); +void pthread_exit(void *retval); +int pthread_join(pthread_t thread, void **status); +int pthread_cancel(pthread_t pthread); +int pthread_detach(pthread_t thread); +int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, + void *(*threadroutine)(void *), void *arg); +int pthread_setcancelstate(int state, int *oldstate); +int pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *schedparam); +int pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param); + #endif /* __PTHREAD_H__ */ diff --git a/include/posix/sched.h b/include/posix/sched.h new file mode 100644 index 0000000000..8f066c353a --- /dev/null +++ b/include/posix/sched.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __POSIX_SCHED_H__ +#define __POSIX_SCHED_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include_next + +/* Cooperative scheduling policy */ +#ifndef SCHED_FIFO +#define SCHED_FIFO 0 +#endif /* SCHED_FIFO */ + +/* Priority based prempetive scheduling policy */ +#ifndef SCHED_RR +#define SCHED_RR 1 +#endif /* SCHED_RR */ + +struct sched_param { + int priority; /* Thread execution priority */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __POSIX_SCHED_H__ */ diff --git a/include/posix/sys/types.h b/include/posix/sys/types.h index 327d640a59..a9e7bff5df 100644 --- a/include/posix/sys/types.h +++ b/include/posix/sys/types.h @@ -12,11 +12,24 @@ extern "C" { #endif -#ifdef CONFIG_NEWLIB_LIBC #include_next -#endif /* CONFIG_NEWLIB_LIBC */ #ifdef CONFIG_PTHREAD_IPC + +/* Thread attributes */ +typedef struct pthread_attr_t { + int priority; + void *stack; + size_t stacksize; + u32_t flags; + u32_t delayedstart; + u32_t schedpolicy; + s32_t detachstate; + u32_t initialized; +} pthread_attr_t; + +typedef void *pthread_t; + /* Mutex */ typedef struct pthread_mutex { struct k_sem *sem; @@ -26,7 +39,7 @@ typedef struct pthread_mutexattr { int unused; } pthread_mutexattr_t; -/* Confition Variables */ +/* Condition variables */ typedef struct pthread_cond { _wait_q_t wait_q; } pthread_cond_t; diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 7aa9d15084..c2a196895c 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -25,7 +25,9 @@ add_library(kernel smp.c ) +if (CONFIG_PTHREAD_IPC) target_include_directories(kernel PRIVATE ${PROJECT_SOURCE_DIR}/include/posix) +endif (CONFIG_PTHREAD_IPC) target_sources_ifdef(CONFIG_INT_LATENCY_BENCHMARK kernel PRIVATE int_latency_bench.c) target_sources_ifdef(CONFIG_STACK_CANARIES kernel PRIVATE compiler_stack_protect.c) target_sources_ifdef(CONFIG_SYS_CLOCK_EXISTS kernel PRIVATE timer.c) diff --git a/kernel/Kconfig b/kernel/Kconfig index 93e25d80d1..71bc17608b 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -500,9 +500,19 @@ config PTHREAD_IPC prompt "POSIX pthread IPC API" default n help - This enables a mostly-standards-compliant implementation of - the pthread mutex, condition variable and barrier IPC - mechanisms. + This enables a mostly-standards-compliant implementation of + the pthread mutex, condition variable and barrier IPC + mechanisms. + +if PTHREAD_IPC +config MAX_PTHREAD_COUNT + int + prompt "Maximum pthread count in POSIX application" + default 5 + range 0 255 + help + Mention maximum number of threads in POSIX compliant application. +endif endmenu menu "Security Options" diff --git a/kernel/posix/CMakeLists.txt b/kernel/posix/CMakeLists.txt index a82c866d8d..189d7bf0c6 100644 --- a/kernel/posix/CMakeLists.txt +++ b/kernel/posix/CMakeLists.txt @@ -2,3 +2,4 @@ target_sources(kernel PRIVATE posix/pthread_common.c) target_sources(kernel PRIVATE posix/pthread_cond.c) target_sources(kernel PRIVATE posix/pthread_mutex.c) target_sources(kernel PRIVATE posix/pthread_barrier.c) +target_sources(kernel PRIVATE posix/pthread.c) diff --git a/kernel/posix/pthread.c b/kernel/posix/pthread.c new file mode 100644 index 0000000000..36dfd72675 --- /dev/null +++ b/kernel/posix/pthread.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "ksched.h" +#include "wait_q.h" + +#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +#define PTHREAD_CANCELED ((void *) -1) + +static const pthread_attr_t init_pthread_attrs = { + .priority = K_LOWEST_APPLICATION_THREAD_PRIO, + .stack = NULL, + .stacksize = 0, + .flags = PTHREAD_INIT_FLAGS, + .delayedstart = K_NO_WAIT, + .schedpolicy = SCHED_RR, + .detachstate = PTHREAD_CREATE_JOINABLE, + .initialized = true, +}; + +/* Memory pool for pthread space */ +K_MEM_POOL_DEFINE(posix_thread_pool, sizeof(struct posix_thread), + sizeof(struct posix_thread), CONFIG_MAX_PTHREAD_COUNT, 4); +static bool is_posix_prio_valid(u32_t priority, int policy) +{ + if ((policy == SCHED_RR && + priority <= CONFIG_NUM_PREEMPT_PRIORITIES) || + (policy == SCHED_FIFO && + priority < CONFIG_NUM_COOP_PRIORITIES)) { + return true; + } + + return false; +} + +static u32_t zephyr_to_posix_priority(s32_t z_prio, int *policy) +{ + u32_t prio; + + if (z_prio < 0) { + *policy = SCHED_FIFO; + prio = -1 * (z_prio + 1); + } else { + *policy = SCHED_RR; + prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio); + } + + return prio; +} + +static s32_t posix_to_zephyr_priority(u32_t priority, int policy) +{ + s32_t prio; + + if (policy == SCHED_FIFO) { + /* Zephyr COOP priority starts from -1 */ + prio = -1 * (priority + 1); + } else { + prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority); + } + + return prio; +} + +/** + * @brief Set scheduling parameter attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *schedparam) +{ + int priority = schedparam->priority; + + if (!attr || !attr->initialized) { + return EINVAL; + } + + if (is_posix_prio_valid(priority, attr->schedpolicy) == false) { + return ENOTSUP; + } + + attr->priority = priority; + return 0; +} + +/** + * @brief Set stack attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, + size_t stacksize) +{ + if (stackaddr == NULL) { + return EACCES; + } + + attr->stack = stackaddr; + attr->stacksize = stacksize; + return 0; +} + +static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) +{ + void * (*fun_ptr)(void *) = arg3; + + fun_ptr(arg1); + pthread_exit(NULL); +} + +/** + * @brief Create a new thread. + * + * Pthread attribute should not be NULL. API will return Error on NULL + * attribute value. + * + * See IEEE 1003.1 + */ +int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, + void *(*threadroutine)(void *), void *arg) +{ + s32_t prio; + pthread_mutexattr_t att; + pthread_condattr_t cond_attr; + struct posix_thread *thread; + struct k_mem_block block; + + /* + * FIXME: Pthread attribute must be non-null and it provides stack + * pointer and stack size. So even though POSIX 1003.1 spec accepts + * attrib as NULL but zephyr needs it initialized with valid stack. + */ + if (!attr || !attr->initialized || !attr->stack || !attr->stacksize) { + return EINVAL; + } + + prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy); + + if (k_mem_pool_alloc(&posix_thread_pool, &block, + sizeof(struct posix_thread), 100) == 0) { + memset(block.data, 0, sizeof(struct posix_thread)); + thread = block.data; + } else { + /* Insuffecient resource to create thread*/ + return EAGAIN; + } + + thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags; + thread->state = attr->detachstate; + thread->cancel_pending = 0; + thread->state_lock.sem = &thread->state_lock_sem; + pthread_mutex_init(&thread->state_lock, &att); + thread->cancel_lock.sem = &thread->cancel_lock_sem; + pthread_mutex_init(&thread->cancel_lock, &att); + pthread_cond_init(&thread->state_cond, &cond_attr); + + *newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack, + attr->stacksize, + (k_thread_entry_t) + zephyr_thread_wrapper, + (void *)arg, NULL, + threadroutine, prio, + (~K_ESSENTIAL & attr->flags), + attr->delayedstart); + return 0; +} + + +/** + * @brief Set cancelability State. + * + * See IEEE 1003.1 + */ +int pthread_setcancelstate(int state, int *oldstate) +{ + struct posix_thread *pthread = (struct posix_thread *) pthread_self(); + + if (state != PTHREAD_CANCEL_ENABLE && + state != PTHREAD_CANCEL_DISABLE) { + return EINVAL; + } + + *oldstate = pthread->cancel_state; + + pthread_mutex_lock(&pthread->cancel_lock); + pthread->cancel_state = state; + pthread_mutex_unlock(&pthread->cancel_lock); + + if (state == PTHREAD_CANCEL_ENABLE && pthread->cancel_pending) { + pthread_exit((void *)PTHREAD_CANCELED); + } + + return 0; +} + +/** + * @brief Cancel execution of a thread. + * + * See IEEE 1003.1 + */ +int pthread_cancel(pthread_t pthread) +{ + struct posix_thread *thread = (struct posix_thread *) pthread; + + if (thread == NULL || thread->state == PTHREAD_TERMINATED) { + return ESRCH; + } + + pthread_mutex_lock(&thread->cancel_lock); + thread->cancel_pending = 1; + + if (thread->cancel_state == PTHREAD_CANCEL_ENABLE) { + if (thread->state == PTHREAD_DETACHED) { + thread->state = PTHREAD_TERMINATED; + pthread_mutex_unlock(&thread->cancel_lock); + } else { + thread->retval = PTHREAD_CANCELED; + pthread_mutex_unlock(&thread->cancel_lock); + pthread_mutex_lock(&thread->state_lock); + thread->state = PTHREAD_EXITED; + pthread_cond_broadcast(&thread->state_cond); + pthread_mutex_unlock(&thread->state_lock); + } + + k_thread_abort((k_tid_t) thread); + } else { + pthread_mutex_unlock(&thread->cancel_lock); + } + + return 0; +} + +/** + * @brief Set thread scheduling policy and parameters. + * + * See IEEE 1003.1 + */ +int pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ + k_tid_t *thread = (k_tid_t *)pthread; + int new_prio; + + if (thread == NULL) { + return ESRCH; + } + + if (policy != SCHED_RR && policy != SCHED_FIFO) { + return EINVAL; + } + + new_prio = posix_to_zephyr_priority(param->priority, policy); + + if (is_posix_prio_valid(new_prio, policy) == false) { + return EINVAL; + } + + k_thread_priority_set(*thread, new_prio); + return 0; +} + +/** + * @brief Initialise threads attribute object + * + * See IEEE 1003.1 + */ +int pthread_attr_init(pthread_attr_t *attr) +{ + + if (attr->initialized == true) { + return EBUSY; + } + + *attr = init_pthread_attrs; + + return 0; +} + +/** + * @brief Get thread scheduling policy and parameters + * + * See IEEE 1003.1 + */ +int pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param) +{ + k_tid_t thread = (k_tid_t)pthread; + u32_t priority = k_thread_priority_get(thread); + + param->priority = zephyr_to_posix_priority(priority, policy); + return 0; +} + +/** + * @brief Terminate calling thread. + * + * See IEEE 1003.1 + */ +void pthread_exit(void *retval) +{ + struct posix_thread *self = (struct posix_thread *)pthread_self(); + + /* Make a thread as cancelable before exiting */ + pthread_mutex_lock(&self->cancel_lock); + if (self->cancel_state == PTHREAD_CANCEL_DISABLE) { + self->cancel_state = PTHREAD_CANCEL_ENABLE; + } + + pthread_mutex_unlock(&self->cancel_lock); + + pthread_mutex_lock(&self->state_lock); + if (self->state == PTHREAD_JOINABLE) { + self->retval = retval; + self->state = PTHREAD_EXITED; + self->retval = retval; + pthread_cond_broadcast(&self->state_cond); + } else { + self->state = PTHREAD_TERMINATED; + } + + pthread_mutex_unlock(&self->state_lock); + k_thread_abort((k_tid_t)self); +} + +/** + * @brief Wait for a thread termination. + * + * See IEEE 1003.1 + */ +int pthread_join(pthread_t thread, void **status) +{ + struct posix_thread *pthread = (struct posix_thread *) thread; + int ret = 0; + + if (pthread == NULL) { + return ESRCH; + } + + pthread_mutex_lock(&pthread->state_lock); + + if (pthread->state == PTHREAD_JOINABLE) { + pthread_cond_wait(&pthread->state_cond, &pthread->state_lock); + } + + if (pthread->state == PTHREAD_EXITED) { + if (status) { + *status = pthread->retval; + } + } else if (pthread->state == PTHREAD_DETACHED) { + ret = EINVAL; + } else { + ret = ESRCH; + } + + pthread_mutex_unlock(&pthread->state_lock); + return ret; +} + +/** + * @brief Detach a thread. + * + * See IEEE 1003.1 + */ +int pthread_detach(pthread_t thread) +{ + struct posix_thread *pthread = (struct posix_thread *) thread; + int ret = 0; + + if (pthread == NULL) { + return ESRCH; + } + + pthread_mutex_lock(&pthread->state_lock); + + switch (pthread->state) { + case PTHREAD_JOINABLE: + pthread->state = PTHREAD_DETACHED; + /* Broadcast the condition. + * This will make threads waiting to join this thread continue. + */ + pthread_cond_broadcast(&pthread->state_cond); + break; + case PTHREAD_EXITED: + pthread->state = PTHREAD_TERMINATED; + /* THREAD has already exited. + * Pthread remained to provide exit status. + */ + break; + case PTHREAD_TERMINATED: + ret = ESRCH; + break; + default: + ret = EINVAL; + break; + } + + pthread_mutex_unlock(&pthread->state_lock); + return ret; +} + +/** + * @brief Get detach state attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + if (!attr || !attr->initialized) { + return EINVAL; + } + + *detachstate = attr->detachstate; + return 0; +} + +/** + * @brief Set detach state attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + if (!attr || !attr->initialized || + (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE)) { + return EINVAL; + } + + attr->detachstate = detachstate; + return 0; +} + + +/** + * @brief Get scheduling policy attribute in Thread attributes. + * + * See IEEE 1003.1 + */ +int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + if (!attr || !attr->initialized) { + return EINVAL; + } + + *policy = attr->schedpolicy; + return 0; +} + + +/** + * @brief Set scheduling policy attribute in Thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + if (!attr || !attr->initialized || + (policy != SCHED_RR && policy != SCHED_FIFO)) { + return EINVAL; + } + + attr->schedpolicy = policy; + return 0; +} + +/** + * @brief Get stack size attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + if (!attr || !attr->initialized) { + return EINVAL; + } + + *stacksize = attr->stacksize; + return 0; + +} + +/** + * @brief Get stack attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getstack(const pthread_attr_t *attr, + void **stackaddr, size_t *stacksize) +{ + if (!attr || !attr->initialized) { + return EINVAL; + } + + *stackaddr = attr->stack; + *stacksize = attr->stacksize; + return 0; +} + +/** + * @brief Get thread attributes object scheduling parameters. + * + * See IEEE 1003.1 + */ +int pthread_attr_getschedparam(const pthread_attr_t *attr, + struct sched_param *schedparam) +{ + if (!attr || !attr->initialized) { + return EINVAL; + } + + schedparam->priority = attr->priority; + return 0; +} + +/** + * @brief Destroy thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_destroy(pthread_attr_t *attr) +{ + if (attr && attr->initialized) { + attr->initialized = false; + return 0; + } + + return EINVAL; +} +