lib: cmsis_rtos_v2: Join and detach support

Implements osThreadJoin and osThreadDetach.

This implementation uses a semaphore to signal when a thread is
exiting so any join operations are signalled to continue. It supports
multiple join operations on a single thread, and ensures joins are
aborted if a thread is detached.

Signed-off-by: Carlos Stuart <carlosstuart1970@gmail.com>
This commit is contained in:
Carlos Stuart 2019-02-06 17:26:35 +00:00 committed by Anas Nashif
commit f5f450eeee
2 changed files with 87 additions and 4 deletions

View file

@ -52,9 +52,13 @@ static inline u32_t cmsis_to_zephyr_priority(u32_t c_prio)
static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
{
struct cv2_thread *tid = arg2;
void * (*fun_ptr)(void *) = arg3;
fun_ptr(arg1);
tid->has_joined = TRUE;
k_sem_give(&tid->join_guard);
}
void *is_cmsis_rtos_v2_thread(void *thread_id)
@ -157,7 +161,7 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg,
this_thread_num = atomic_inc((atomic_t *)&thread_num);
tid = &cv2_thread_pool[this_thread_num];
tid->state = attr->attr_bits;
tid->attr_bits = attr->attr_bits;
if (attr->stack_mem == NULL) {
__ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE > 0,
@ -184,13 +188,15 @@ osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg,
sys_dlist_append(&thread_list, &tid->node);
k_sem_init(&tid->join_guard, 0, 1);
tid->has_joined = FALSE;
(void)k_thread_create(&tid->z_thread,
stack, stack_size,
(k_thread_entry_t)zephyr_thread_wrapper,
(void *)arg, NULL, threadfunc,
(void *)arg, tid, threadfunc,
prio, 0, K_NO_WAIT);
if (attr->name == NULL) {
strncpy(tid->name, init_thread_attrs.name,
sizeof(tid->name) - 1);
@ -417,6 +423,77 @@ osStatus_t osThreadResume(osThreadId_t thread_id)
return osOK;
}
/**
* @brief Detach a thread (thread storage can be reclaimed when thread
* terminates).
*/
osStatus_t osThreadDetach(osThreadId_t thread_id)
{
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
return osErrorParameter;
}
if (k_is_in_isr()) {
return osErrorISR;
}
if (_is_thread_cmsis_inactive(&tid->z_thread)) {
return osErrorResource;
}
__ASSERT(tid->attr_bits != osThreadDetached,
"Thread already detached, behaviour undefined.");
tid->attr_bits = osThreadDetached;
k_sem_give(&tid->join_guard);
return osOK;
}
/**
* @brief Wait for specified thread to terminate.
*/
osStatus_t osThreadJoin(osThreadId_t thread_id)
{
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
osStatus_t status = osError;
if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
return osErrorParameter;
}
if (k_is_in_isr()) {
return osErrorISR;
}
if (_is_thread_cmsis_inactive(&tid->z_thread)) {
return osErrorResource;
}
if (tid->attr_bits != osThreadJoinable) {
return osErrorResource;
}
if (!tid->has_joined) {
if (k_sem_take(&tid->join_guard, K_FOREVER) != 0) {
__ASSERT(0, "Failed to take from join guard.");
}
k_sem_give(&tid->join_guard);
}
if (tid->has_joined && (tid->attr_bits == osThreadJoinable)) {
status = osOK;
} else {
status = osErrorResource;
}
return status;
}
/**
* @brief Terminate execution of current running thread.
*/
@ -427,6 +504,8 @@ __NO_RETURN void osThreadExit(void)
__ASSERT(!k_is_in_isr(), "");
tid = osThreadGetId();
k_sem_give(&tid->join_guard);
k_thread_abort((k_tid_t)&tid->z_thread);
CODE_UNREACHABLE;
@ -451,6 +530,8 @@ osStatus_t osThreadTerminate(osThreadId_t thread_id)
return osErrorResource;
}
k_sem_give(&tid->join_guard);
k_thread_abort((k_tid_t)&tid->z_thread);
return osOK;
}

View file

@ -20,7 +20,9 @@ struct cv2_thread {
struct k_poll_event poll_event;
u32_t signal_results;
char name[16];
u32_t state;
u32_t attr_bits;
struct k_sem join_guard;
char has_joined;
};
struct cv2_timer {