diff --git a/lib/cmsis_rtos_v2/thread.c b/lib/cmsis_rtos_v2/thread.c index 7fd97208301..db23706e64f 100644 --- a/lib/cmsis_rtos_v2/thread.c +++ b/lib/cmsis_rtos_v2/thread.c @@ -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; } diff --git a/lib/cmsis_rtos_v2/wrapper.h b/lib/cmsis_rtos_v2/wrapper.h index 9d9b99ce90f..16931615854 100644 --- a/lib/cmsis_rtos_v2/wrapper.h +++ b/lib/cmsis_rtos_v2/wrapper.h @@ -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 {