cmsis_rtos_v1: fix thread instances management.

add a bitarray into struct osThreadDef_t to indicate whether the
thread is used or not, then we can get the first available thread
by searching this array when creating a new thread, and update this
array to add a free thread when terminating a thread.

Signed-off-by: Chen Peng1 <peng1.chen@intel.com>
This commit is contained in:
Chen Peng1 2021-09-06 13:59:40 +08:00 committed by Anas Nashif
commit 0f63d1135c
6 changed files with 62 additions and 4 deletions

View file

@ -67,6 +67,7 @@
#include <stdint.h>
#include <stddef.h>
#include <kernel.h>
#include <sys/bitarray.h>
#ifdef __cplusplus
extern "C"
@ -172,6 +173,8 @@ typedef struct os_thread_def {
struct k_poll_signal *poll_signal;
struct k_poll_event *poll_event;
int32_t signal_results;
///< a bitarray used to indicate whether the thread is used or not, 0: unused, 1: used
void *status_mask;
} osThreadDef_t;
/// Timer Definition structure contains timer parameters.
@ -288,8 +291,11 @@ static K_THREAD_STACK_ARRAY_DEFINE(stacks_##name, instances, CONFIG_CMSIS_THREAD
static struct k_thread cm_thread_##name[instances]; \
static struct k_poll_signal wait_signal_##name; \
static struct k_poll_event wait_events_##name; \
static SYS_BITARRAY_DEFINE(bitarray_##name, instances); \
static osThreadDef_t os_thread_def_##name = \
{ (name), (priority), (instances), (stacksz), (void *)(stacks_##name), (cm_thread_##name), (&wait_signal_##name), (&wait_events_##name), 0 }
{ (name), (priority), (instances), (stacksz), (void *)(stacks_##name), \
(cm_thread_##name), (&wait_signal_##name), \
(&wait_events_##name), 0, (void *)(&bitarray_##name)}
#endif
/// Access a Thread definition.

View file

@ -1460,6 +1460,10 @@ static inline void unpend_all(_wait_q_t *wait_q)
}
}
#ifdef CONFIG_CMSIS_RTOS_V1
extern void z_thread_cmsis_status_mask_clear(struct k_thread *thread);
#endif
static void end_thread(struct k_thread *thread)
{
/* We hold the lock, and the thread is known not to be running
@ -1482,6 +1486,10 @@ static void end_thread(struct k_thread *thread)
z_thread_monitor_exit(thread);
#ifdef CONFIG_CMSIS_RTOS_V1
z_thread_cmsis_status_mask_clear(thread);
#endif
#ifdef CONFIG_USERSPACE
z_mem_domain_exit_thread(thread);
z_thread_perms_all_clear(thread);

View file

@ -5,6 +5,7 @@ config CMSIS_RTOS_V1
bool "CMSIS RTOS v1 API"
depends on THREAD_CUSTOM_DATA
depends on POLL
depends on THREAD_STACK_INFO
help
This enables CMSIS RTOS v1 API support. This is an OS-integration
layer which allows applications using CMSIS RTOS APIs to build on

View file

@ -34,6 +34,23 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
fun_ptr(arg1);
}
/* clear related bit in cmsis thread status bitarray
* when terminating a thread
*/
void z_thread_cmsis_status_mask_clear(struct k_thread *thread)
{
uint32_t offset, instance;
osThreadDef_t *thread_def = (osThreadDef_t *)(thread->custom_data);
if (thread_def != NULL) {
/* get thread instance index according to stack address */
offset = thread->stack_info.start - (uintptr_t)thread_def->stack_mem;
instance = offset / K_THREAD_STACK_LEN(CONFIG_CMSIS_THREAD_MAX_STACK_SIZE);
sys_bitarray_clear_bit((sys_bitarray_t *)(thread_def->status_mask), instance);
}
}
/**
* @brief Create a new thread.
*/
@ -43,6 +60,8 @@ osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *arg)
uint32_t prio;
k_tid_t tid;
uint32_t stacksz;
int ret;
size_t instance;
k_thread_stack_t
(*stk_ptr)[K_THREAD_STACK_LEN(CONFIG_CMSIS_THREAD_MAX_STACK_SIZE)];
@ -67,6 +86,13 @@ osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *arg)
(thread_def->tpriority <= osPriorityRealtime),
"invalid priority\n");
/* get an available thread instance */
ret = sys_bitarray_alloc((sys_bitarray_t *)(thread_def->status_mask),
1, &instance);
if (ret != 0) {
return NULL;
}
stacksz = thread_def->stacksize;
if (stacksz == 0U) {
stacksz = CONFIG_CMSIS_THREAD_MAX_STACK_SIZE;
@ -77,17 +103,22 @@ osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *arg)
K_POLL_MODE_NOTIFY_ONLY, thread_def->poll_signal);
cm_thread = thread_def->cm_thread;
atomic_dec((atomic_t *)&thread_def->instances);
stk_ptr = thread_def->stack_mem;
prio = cmsis_to_zephyr_priority(thread_def->tpriority);
k_thread_custom_data_set((void *)thread_def);
tid = k_thread_create(&cm_thread[thread_def->instances],
stk_ptr[thread_def->instances], stacksz,
tid = k_thread_create(&cm_thread[instance],
stk_ptr[instance], stacksz,
(k_thread_entry_t)zephyr_thread_wrapper,
(void *)arg, NULL, thread_def->pthread,
prio, 0, K_NO_WAIT);
/* make custom_data pointer of thread point to its source thread_def,
* then we can use it to release thread instances
* when terminating threads
*/
tid->custom_data = (void *)thread_def;
return ((osThreadId)tid);
}

View file

@ -6,3 +6,4 @@ CONFIG_MAX_THREAD_BYTES=4
CONFIG_IRQ_OFFLOAD=y
CONFIG_CMSIS_THREAD_MAX_STACK_SIZE=2048
CONFIG_SMP=n
CONFIG_THREAD_STACK_INFO=y

View file

@ -26,6 +26,7 @@ osThreadDef(thread_inst_check, osPriorityNormal, 3, STACKSZ);
void test_thread_instances(void)
{
osThreadId id1, id2, id3, id4;
osStatus status;
id1 = osThreadCreate(osThread(thread_inst_check), NULL);
zassert_true(id1 != NULL, "Failed creating thread_inst_check");
@ -38,4 +39,14 @@ void test_thread_instances(void)
id4 = osThreadCreate(osThread(thread_inst_check), NULL);
zassert_true(id4 == NULL, "Something wrong with thread instances");
status = osThreadTerminate(id2);
zassert_true(status == osOK, "Error terminating thread_inst_check");
/* after terminating thread id2, when creating a new thread,
* it should re-use the available thread instance of id2.
*/
id4 = osThreadCreate(osThread(thread_inst_check), NULL);
zassert_true(id4 != NULL, "Failed creating thread_inst_check");
zassert_true(id2 == id4, "Error creating thread_inst_check");
}