lib/cmsis_rtos_v2: Implement support for thread APIs
These APIs allow defining, creating and controlling of thread related functionalities. Signed-off-by: Rajavardhan Gundi <rajavardhan.gundi@intel.com>
This commit is contained in:
parent
b609175aff
commit
4af7b6ccf4
6 changed files with 516 additions and 0 deletions
|
@ -10,4 +10,5 @@ add_subdirectory_if_kconfig(base64)
|
|||
add_subdirectory(mempool)
|
||||
add_subdirectory_ifdef(CONFIG_POSIX_API posix)
|
||||
add_subdirectory_ifdef(CONFIG_CMSIS_RTOS_V1 cmsis_rtos_v1)
|
||||
add_subdirectory_ifdef(CONFIG_CMSIS_RTOS_V2 cmsis_rtos_v2)
|
||||
add_subdirectory(rbtree)
|
||||
|
|
|
@ -29,4 +29,5 @@ config BASE64
|
|||
source "lib/posix/Kconfig"
|
||||
|
||||
source "lib/cmsis_rtos_v1/Kconfig"
|
||||
source "lib/cmsis_rtos_v2/Kconfig"
|
||||
endmenu
|
||||
|
|
13
lib/cmsis_rtos_v2/CMakeLists.txt
Normal file
13
lib/cmsis_rtos_v2/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
add_library(CMSIS INTERFACE)
|
||||
|
||||
target_include_directories(CMSIS INTERFACE ${PROJECT_SOURCE_DIR}/include/cmsis_rtos_v2)
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources_ifdef(
|
||||
CONFIG_CMSIS_RTOS_V2
|
||||
thread.c
|
||||
)
|
||||
|
||||
zephyr_library_link_libraries(CMSIS)
|
||||
target_link_libraries(CMSIS INTERFACE zephyr_interface)
|
34
lib/cmsis_rtos_v2/Kconfig
Normal file
34
lib/cmsis_rtos_v2/Kconfig
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Copyright (c) 2018 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
config CMSIS_RTOS_V2
|
||||
bool "CMSIS RTOS v2 API"
|
||||
default n
|
||||
depends on POLL
|
||||
depends on THREAD_NAME
|
||||
depends on THREAD_STACK_INFO
|
||||
depends on THREAD_MONITOR
|
||||
depends on INIT_STACKS
|
||||
help
|
||||
This enables CMSIS RTOS v2 API support. This is an OS-integration
|
||||
layer which allows applications using CMSIS RTOS V2 APIs to build
|
||||
on Zephyr.
|
||||
|
||||
if CMSIS_RTOS_V2
|
||||
config CMSIS_V2_THREAD_MAX_COUNT
|
||||
int "Maximum thread count in CMSIS RTOS V2 application"
|
||||
default 15
|
||||
range 0 255
|
||||
help
|
||||
Mention max number of threads in CMSIS RTOS V2 compliant application.
|
||||
There's a limitation on the number of threads due to memory
|
||||
related constraints.
|
||||
|
||||
config CMSIS_V2_THREAD_MAX_STACK_SIZE
|
||||
int "Max stack size threads can be allocated in CMSIS RTOS V2 application"
|
||||
default 512
|
||||
help
|
||||
Mention max stack size threads can be allocated in CMSIS RTOS V2 application.
|
||||
endif
|
438
lib/cmsis_rtos_v2/thread.c
Normal file
438
lib/cmsis_rtos_v2/thread.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <ksched.h>
|
||||
#include <atomic.h>
|
||||
#include <misc/stack.h>
|
||||
#include "wrapper.h"
|
||||
|
||||
static sys_dlist_t thread_list;
|
||||
static struct cv2_thread cv2_thread_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT];
|
||||
static u32_t thread_num;
|
||||
|
||||
static inline int _is_thread_cmsis_inactive(struct k_thread *thread)
|
||||
{
|
||||
u8_t state = thread->base.thread_state;
|
||||
|
||||
return state & (_THREAD_PRESTART | _THREAD_DEAD);
|
||||
}
|
||||
|
||||
static inline u32_t zephyr_to_cmsis_priority(u32_t z_prio)
|
||||
{
|
||||
return (osPriorityISR - z_prio);
|
||||
}
|
||||
|
||||
static inline u32_t cmsis_to_zephyr_priority(u32_t c_prio)
|
||||
{
|
||||
return (osPriorityISR - c_prio);
|
||||
}
|
||||
|
||||
static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
void * (*fun_ptr)(void *) = arg3;
|
||||
|
||||
fun_ptr(arg1);
|
||||
}
|
||||
|
||||
void *is_cmsis_rtos_v2_thread(void *thread_id)
|
||||
{
|
||||
sys_dnode_t *pnode;
|
||||
struct cv2_thread *itr;
|
||||
|
||||
SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) {
|
||||
itr = CONTAINER_OF(pnode, struct cv2_thread, node);
|
||||
|
||||
if ((void *)itr == thread_id) {
|
||||
return itr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osThreadId_t get_cmsis_thread_id(k_tid_t tid)
|
||||
{
|
||||
sys_dnode_t *pnode;
|
||||
struct cv2_thread *itr;
|
||||
|
||||
if (tid != NULL) {
|
||||
SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) {
|
||||
itr = CONTAINER_OF(pnode, struct cv2_thread, node);
|
||||
|
||||
if (&itr->z_thread == tid) {
|
||||
return (osThreadId_t)itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a thread and add it to Active Threads.
|
||||
*/
|
||||
osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg,
|
||||
const osThreadAttr_t *attr)
|
||||
{
|
||||
s32_t prio;
|
||||
struct cv2_thread *tid;
|
||||
static u32_t one_time;
|
||||
|
||||
BUILD_ASSERT_MSG(osPriorityISR <= CONFIG_NUM_PREEMPT_PRIORITIES,
|
||||
"Configure NUM_PREEMPT_PRIORITIES to at least osPriorityISR");
|
||||
|
||||
__ASSERT(attr->stack_size <= CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE,
|
||||
"invalid stack size\n");
|
||||
|
||||
__ASSERT(thread_num <= CONFIG_CMSIS_V2_THREAD_MAX_COUNT,
|
||||
"Exceeded max number of threads\n");
|
||||
|
||||
__ASSERT(attr != NULL,
|
||||
"Zephyr requirement: Pass attributes explicitly for ThreadNew\n");
|
||||
|
||||
/* Zephyr needs valid stack to be specified when this API is called */
|
||||
__ASSERT(attr->stack_mem, "");
|
||||
__ASSERT(attr->stack_size, "");
|
||||
|
||||
__ASSERT((attr->priority >= osPriorityIdle) &&
|
||||
(attr->priority <= osPriorityISR),
|
||||
"invalid priority\n");
|
||||
|
||||
if (k_is_in_isr()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prio = cmsis_to_zephyr_priority(attr->priority);
|
||||
|
||||
tid = &cv2_thread_pool[thread_num];
|
||||
tid->state = attr->attr_bits;/* detached/joinable */
|
||||
atomic_inc((atomic_t *)&thread_num);
|
||||
|
||||
k_poll_signal_init(&tid->poll_signal);
|
||||
k_poll_event_init(&tid->poll_event, K_POLL_TYPE_SIGNAL,
|
||||
K_POLL_MODE_NOTIFY_ONLY, &tid->poll_signal);
|
||||
tid->signal_results = 0;
|
||||
|
||||
/* TODO: Do this somewhere only once */
|
||||
if (one_time == 0) {
|
||||
sys_dlist_init(&thread_list);
|
||||
one_time = 1;
|
||||
}
|
||||
|
||||
sys_dlist_append(&thread_list, &tid->node);
|
||||
|
||||
(void)k_thread_create(&tid->z_thread,
|
||||
attr->stack_mem, attr->stack_size,
|
||||
(k_thread_entry_t)zephyr_thread_wrapper,
|
||||
(void *)arg, NULL, threadfunc,
|
||||
prio, 0, K_NO_WAIT);
|
||||
|
||||
k_thread_name_set(&tid->z_thread, attr->name);
|
||||
|
||||
return (osThreadId_t)tid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get name of a thread.
|
||||
*/
|
||||
const char *osThreadGetName(osThreadId_t thread_id)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
if (k_is_in_isr() || (thread_id == NULL)) {
|
||||
name = NULL;
|
||||
} else {
|
||||
if (is_cmsis_rtos_v2_thread(thread_id) == NULL) {
|
||||
name = NULL;
|
||||
} else {
|
||||
struct cv2_thread *tid =
|
||||
(struct cv2_thread *)thread_id;
|
||||
|
||||
name = k_thread_name_get(&tid->z_thread);
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the thread ID of the current running thread.
|
||||
*/
|
||||
osThreadId_t osThreadGetId(void)
|
||||
{
|
||||
k_tid_t tid = k_current_get();
|
||||
|
||||
return get_cmsis_thread_id(tid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current priority of an active thread.
|
||||
*/
|
||||
osPriority_t osThreadGetPriority(osThreadId_t thread_id)
|
||||
{
|
||||
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
|
||||
u32_t priority;
|
||||
|
||||
if (k_is_in_isr() || (tid == NULL) ||
|
||||
(is_cmsis_rtos_v2_thread(tid) == NULL) ||
|
||||
(_is_thread_cmsis_inactive(&tid->z_thread))) {
|
||||
return osPriorityError;
|
||||
}
|
||||
|
||||
priority = k_thread_priority_get(&tid->z_thread);
|
||||
return zephyr_to_cmsis_priority(priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change priority of an active thread.
|
||||
*/
|
||||
osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority)
|
||||
{
|
||||
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
|
||||
|
||||
if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL) ||
|
||||
(priority <= osPriorityNone) || (priority > osPriorityISR)) {
|
||||
return osErrorParameter;
|
||||
}
|
||||
|
||||
if (k_is_in_isr()) {
|
||||
return osErrorISR;
|
||||
}
|
||||
|
||||
if (_is_thread_cmsis_inactive(&tid->z_thread)) {
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
k_thread_priority_set((k_tid_t)&tid->z_thread,
|
||||
cmsis_to_zephyr_priority(priority));
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current thread state of a thread.
|
||||
*/
|
||||
osThreadState_t osThreadGetState(osThreadId_t thread_id)
|
||||
{
|
||||
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
|
||||
osThreadState_t state;
|
||||
|
||||
if (k_is_in_isr() || (tid == NULL) ||
|
||||
(is_cmsis_rtos_v2_thread(tid) == NULL)) {
|
||||
return osThreadError;
|
||||
}
|
||||
|
||||
switch (tid->z_thread.base.thread_state) {
|
||||
case _THREAD_DUMMY:
|
||||
state = osThreadError;
|
||||
break;
|
||||
case _THREAD_PRESTART:
|
||||
state = osThreadInactive;
|
||||
break;
|
||||
case _THREAD_DEAD:
|
||||
state = osThreadTerminated;
|
||||
break;
|
||||
case _THREAD_SUSPENDED:
|
||||
case _THREAD_PENDING:
|
||||
state = osThreadBlocked;
|
||||
break;
|
||||
case _THREAD_QUEUED:
|
||||
state = osThreadReady;
|
||||
break;
|
||||
default:
|
||||
state = osThreadError;
|
||||
break;
|
||||
}
|
||||
|
||||
if (osThreadGetId() == thread_id) {
|
||||
state = osThreadRunning;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pass control to next thread that is in READY state.
|
||||
*/
|
||||
osStatus_t osThreadYield(void)
|
||||
{
|
||||
if (k_is_in_isr()) {
|
||||
return osErrorISR;
|
||||
}
|
||||
|
||||
k_yield();
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get stack size of a thread.
|
||||
*/
|
||||
uint32_t osThreadGetStackSize(osThreadId_t thread_id)
|
||||
{
|
||||
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
|
||||
|
||||
__ASSERT(tid, "");
|
||||
__ASSERT(is_cmsis_rtos_v2_thread(tid), "");
|
||||
__ASSERT(!k_is_in_isr(), "");
|
||||
|
||||
return tid->z_thread.stack_info.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get available stack space of a thread based on stack watermark
|
||||
* recording during execution.
|
||||
*/
|
||||
uint32_t osThreadGetStackSpace(osThreadId_t thread_id)
|
||||
{
|
||||
struct cv2_thread *tid = (struct cv2_thread *)thread_id;
|
||||
u32_t size = tid->z_thread.stack_info.size;
|
||||
u32_t unused = 0;
|
||||
|
||||
__ASSERT(tid, "");
|
||||
__ASSERT(is_cmsis_rtos_v2_thread(tid), "");
|
||||
__ASSERT(!k_is_in_isr(), "");
|
||||
|
||||
unused = stack_unused_space_get((char *)tid->z_thread.stack_info.start,
|
||||
size);
|
||||
|
||||
return unused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend execution of a thread.
|
||||
*/
|
||||
osStatus_t osThreadSuspend(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;
|
||||
}
|
||||
|
||||
k_thread_suspend(&tid->z_thread);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume execution of a thread.
|
||||
*/
|
||||
osStatus_t osThreadResume(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;
|
||||
}
|
||||
|
||||
k_thread_resume(&tid->z_thread);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Terminate execution of current running thread.
|
||||
*/
|
||||
__NO_RETURN void osThreadExit(void)
|
||||
{
|
||||
struct cv2_thread *tid;
|
||||
|
||||
__ASSERT(!k_is_in_isr(), "");
|
||||
tid = osThreadGetId();
|
||||
|
||||
k_thread_abort((k_tid_t)&tid->z_thread);
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Terminate execution of a thread.
|
||||
*/
|
||||
osStatus_t osThreadTerminate(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;
|
||||
}
|
||||
|
||||
k_thread_abort((k_tid_t)&tid->z_thread);
|
||||
return osOK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get number of active threads.
|
||||
*/
|
||||
uint32_t osThreadGetCount(void)
|
||||
{
|
||||
struct k_thread *thread;
|
||||
u32_t count = 0;
|
||||
|
||||
__ASSERT(!k_is_in_isr(), "");
|
||||
for (thread = _kernel.threads; thread; thread = thread->next_thread) {
|
||||
if (get_cmsis_thread_id(thread) && _is_thread_queued(thread)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enumerate active threads.
|
||||
*/
|
||||
uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items)
|
||||
{
|
||||
struct k_thread *thread;
|
||||
u32_t count = 0;
|
||||
osThreadId_t tid;
|
||||
|
||||
__ASSERT(!k_is_in_isr(), "");
|
||||
__ASSERT(thread_array != NULL, "");
|
||||
__ASSERT(array_items, "");
|
||||
|
||||
for (thread = _kernel.threads; thread; thread = thread->next_thread) {
|
||||
if (count == array_items) {
|
||||
break;
|
||||
}
|
||||
|
||||
tid = get_cmsis_thread_id(thread);
|
||||
if (tid != NULL) {
|
||||
thread_array[count] = tid;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return (count);
|
||||
}
|
29
lib/cmsis_rtos_v2/wrapper.h
Normal file
29
lib/cmsis_rtos_v2/wrapper.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __WRAPPER_H__
|
||||
#define __WRAPPER_H__
|
||||
|
||||
#include <kernel.h>
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
struct cv2_thread {
|
||||
sys_dnode_t node;
|
||||
struct k_thread z_thread;
|
||||
struct k_poll_signal poll_signal;
|
||||
struct k_poll_event poll_event;
|
||||
u32_t signal_results;
|
||||
char name[16];
|
||||
u32_t state;
|
||||
};
|
||||
|
||||
extern osThreadId_t get_cmsis_thread_id(k_tid_t tid);
|
||||
extern void *is_cmsis_rtos_v2_thread(void *thread_id);
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue