|
|
@@ -36,81 +36,67 @@
|
|
|
|
|
|
#if MICROPY_PY_THREAD
|
|
|
|
|
|
-#define MP_THREAD_MIN_STACK_SIZE (5 * 1024)
|
|
|
-#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024)
|
|
|
-#define MP_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 2)
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- rt_thread_t thread;
|
|
|
- /* whether the thread is ready and running */
|
|
|
- rt_bool_t ready;
|
|
|
- /* thread Python args, a GC root pointer */
|
|
|
- void *arg;
|
|
|
- /* pointer to the stack */
|
|
|
- void *stack;
|
|
|
- void *tcb;
|
|
|
- /* number of words in the stack */
|
|
|
- size_t stack_len;
|
|
|
- rt_list_t list;
|
|
|
-} mp_thread, *mp_thread_t;
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- rt_mutex_t mutex;
|
|
|
- rt_list_t list;
|
|
|
-} mp_mutex, *mp_mutex_t;
|
|
|
+#define MP_THREAD_MIN_STACK_SIZE (4 * 1024)
|
|
|
+#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024)
|
|
|
+#define MP_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 2)
|
|
|
+
|
|
|
+#define MP_THREAD_STATUS_READY 0
|
|
|
+#define MP_THREAD_STATUS_RUNNING 1
|
|
|
+#define MP_THREAD_STATUS_FINISH 2
|
|
|
+
|
|
|
+typedef struct _thread_t {
|
|
|
+ rt_thread_t id; // system id of thread
|
|
|
+ int status; // whether the thread is ready, running and finish
|
|
|
+ void *arg; // thread Python args, a GC root pointer
|
|
|
+ void *stack; // pointer to the stack
|
|
|
+ size_t stack_len; // number of words in the stack
|
|
|
+ struct _thread_t *next;
|
|
|
+} thread_t;
|
|
|
|
|
|
// the mutex controls access to the linked list
|
|
|
STATIC mp_thread_mutex_t thread_mutex;
|
|
|
-STATIC rt_list_t thread_list, mutex_list;
|
|
|
-STATIC mp_thread thread_entry0;
|
|
|
-/* root pointer, handled by mp_thread_gc_others */
|
|
|
-STATIC mp_thread *main_thread;
|
|
|
+STATIC thread_t thread_root_node;
|
|
|
+STATIC thread_t *thread_root; // root pointer, handled by mp_thread_gc_others
|
|
|
|
|
|
/**
|
|
|
* thread port initialization
|
|
|
*
|
|
|
* @param stack MicroPython main thread stack
|
|
|
- * @param stack_len MicroPython main thread stack, unit: word
|
|
|
+ * @param stack_len MicroPython main thread stack
|
|
|
*/
|
|
|
void mp_thread_init(void *stack, uint32_t stack_len) {
|
|
|
mp_thread_set_state(&mp_state_ctx.thread);
|
|
|
|
|
|
- main_thread = &thread_entry0;
|
|
|
- main_thread->thread = rt_thread_self();
|
|
|
- main_thread->ready = RT_TRUE;
|
|
|
- main_thread->arg = NULL;
|
|
|
- main_thread->stack = stack;
|
|
|
- main_thread->stack_len = stack_len;
|
|
|
-
|
|
|
- rt_list_init(&thread_list);
|
|
|
- rt_list_init(&mutex_list);
|
|
|
-
|
|
|
- rt_list_insert_before(&thread_list, &(main_thread->list));
|
|
|
+ thread_root = &thread_root_node;
|
|
|
+ thread_root->id = rt_thread_self();
|
|
|
+ thread_root->status = MP_THREAD_STATUS_RUNNING;
|
|
|
+ thread_root->arg = NULL;
|
|
|
+ thread_root->stack = stack;
|
|
|
+ thread_root->stack_len = stack_len;
|
|
|
+ thread_root->next = NULL;
|
|
|
|
|
|
mp_thread_mutex_init(&thread_mutex);
|
|
|
}
|
|
|
|
|
|
void mp_thread_gc_others(void) {
|
|
|
- struct rt_list_node *list = &thread_list, *node = NULL;
|
|
|
- mp_thread_t cur_thread_node = NULL;
|
|
|
|
|
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
|
|
+ for (thread_t *th = thread_root; th != NULL; th = th->next) {
|
|
|
+ if (th == &thread_root_node) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ gc_collect_root((void**)&th, 1);
|
|
|
+ gc_collect_root(&th->arg, 1); // probably not needed
|
|
|
|
|
|
- for (node = list->next; node != list; node = node->next) {
|
|
|
- cur_thread_node = rt_list_entry(node, mp_thread, list);
|
|
|
- gc_collect_root((void **)&cur_thread_node->thread, 1);
|
|
|
- /* probably not needed */
|
|
|
- gc_collect_root(&cur_thread_node->arg, 1);
|
|
|
- if (cur_thread_node->thread == rt_thread_self()) {
|
|
|
+ if (th->id == rt_thread_self()) {
|
|
|
continue;
|
|
|
}
|
|
|
- if (!cur_thread_node->ready) {
|
|
|
+ if (th->status != MP_THREAD_STATUS_FINISH) {
|
|
|
continue;
|
|
|
}
|
|
|
- /* probably not needed */
|
|
|
- gc_collect_root(cur_thread_node->stack, cur_thread_node->stack_len);
|
|
|
+ gc_collect_root((void**)&th->id, 1); // probably not needed
|
|
|
+ gc_collect_root((void**)&th->stack, th->stack_len); // probably not needed
|
|
|
}
|
|
|
-
|
|
|
mp_thread_mutex_unlock(&thread_mutex);
|
|
|
}
|
|
|
|
|
|
@@ -123,35 +109,18 @@ void mp_thread_set_state(void *state) {
|
|
|
}
|
|
|
|
|
|
void mp_thread_start(void) {
|
|
|
- struct rt_list_node *list = &thread_list, *node = NULL;
|
|
|
- mp_thread_t cur_thread_node = NULL;
|
|
|
-
|
|
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
|
|
-
|
|
|
- for (node = list->next; node != list; node = node->next) {
|
|
|
- cur_thread_node = rt_list_entry(node, mp_thread, list);
|
|
|
- if (cur_thread_node->thread == rt_thread_self()) {
|
|
|
- cur_thread_node->ready = RT_TRUE;
|
|
|
+ for (thread_t *th = thread_root; th != NULL; th = th->next) {
|
|
|
+ if (th->id == rt_thread_self()) {
|
|
|
+ th->status = MP_THREAD_STATUS_RUNNING;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
mp_thread_mutex_unlock(&thread_mutex);
|
|
|
}
|
|
|
|
|
|
-STATIC void *(*ext_thread_entry)(void*) = NULL;
|
|
|
-
|
|
|
-STATIC void rtthread_entry(void *arg) {
|
|
|
- if (ext_thread_entry) {
|
|
|
- ext_thread_entry(arg);
|
|
|
- }
|
|
|
-
|
|
|
- rt_thread_detach(rt_thread_self());
|
|
|
-}
|
|
|
-
|
|
|
void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
|
|
|
- // store thread entry function into a global variable so we can access it
|
|
|
- ext_thread_entry = entry;//(void (*)(void *parameter))
|
|
|
+ static uint8_t count = 0;
|
|
|
|
|
|
if (*stack_size == 0) {
|
|
|
*stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
|
|
|
@@ -159,44 +128,34 @@ void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, i
|
|
|
*stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
|
|
|
}
|
|
|
|
|
|
- // allocate TCB, stack and linked-list node (must be outside thread_mutex lock)
|
|
|
- rt_thread_t th = m_new_obj(struct rt_thread);
|
|
|
+ // allocate the linked-list node, TCB and stack (must be outside thread_mutex lock)
|
|
|
+ thread_t *th = m_new_obj(thread_t);
|
|
|
if (th == NULL) {
|
|
|
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread TCB"));
|
|
|
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread obj"));
|
|
|
}
|
|
|
- uint8_t *stack = m_new(uint8_t, *stack_size);
|
|
|
- if (stack == NULL) {
|
|
|
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread stack"));
|
|
|
+ th->id = m_new_obj(struct rt_thread);
|
|
|
+ if (th->id == NULL) {
|
|
|
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread id"));
|
|
|
}
|
|
|
- mp_thread *node = m_new_obj(mp_thread);
|
|
|
- if (node == NULL) {
|
|
|
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread list node"));
|
|
|
+ th->stack = m_new(uint8_t, *stack_size);
|
|
|
+ if (th->stack == NULL) {
|
|
|
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread stack"));
|
|
|
}
|
|
|
- // adjust the stack_size to provide room to recover from hitting the limit
|
|
|
- *stack_size -= 1024;
|
|
|
-
|
|
|
- node->ready = RT_FALSE;
|
|
|
- node->arg = arg;
|
|
|
- node->stack = stack;
|
|
|
- node->stack_len = *stack_size / 4;
|
|
|
|
|
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
|
|
|
|
|
- rt_thread_init(th, name, rtthread_entry, arg, stack, *stack_size, priority, 0);
|
|
|
+ // adjust the stack_size to provide room to recover from hitting the limit
|
|
|
+ *stack_size -= 1024;
|
|
|
|
|
|
// add thread to linked list of all threads
|
|
|
- {
|
|
|
- rt_base_t level;
|
|
|
-
|
|
|
- level = rt_hw_interrupt_disable();
|
|
|
-
|
|
|
- node->thread = th;
|
|
|
- rt_list_insert_before(&thread_list, &(node->list));
|
|
|
-
|
|
|
- rt_hw_interrupt_enable(level);
|
|
|
- }
|
|
|
+ th->status = MP_THREAD_STATUS_READY;
|
|
|
+ th->arg = arg;
|
|
|
+ th->stack_len = *stack_size;
|
|
|
+ th->next = thread_root;
|
|
|
+ thread_root = th;
|
|
|
|
|
|
- rt_thread_startup(th);
|
|
|
+ rt_thread_init(th->id, name, (void (*)(void *))entry, arg, th->stack, *stack_size, priority, count++);
|
|
|
+ rt_thread_startup(th->id);
|
|
|
|
|
|
mp_thread_mutex_unlock(&thread_mutex);
|
|
|
}
|
|
|
@@ -206,96 +165,64 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
|
|
|
char name[RT_NAME_MAX];
|
|
|
|
|
|
/* build name */
|
|
|
- rt_snprintf(name, sizeof(name), "mp%02d", count ++);
|
|
|
+ rt_snprintf(name, sizeof(name), "mp%02d", count++);
|
|
|
|
|
|
mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, name);
|
|
|
}
|
|
|
|
|
|
void mp_thread_finish(void) {
|
|
|
- struct rt_list_node *list = &thread_list, *node = NULL;
|
|
|
- mp_thread_t cur_thread_node = NULL;
|
|
|
+ thread_t *prev = NULL;
|
|
|
|
|
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
|
|
-
|
|
|
- for (node = list->next; node != list; node = node->next) {
|
|
|
- cur_thread_node = rt_list_entry(node, mp_thread, list);
|
|
|
- if (cur_thread_node->thread == rt_thread_self()) {
|
|
|
- cur_thread_node->ready = RT_FALSE;
|
|
|
+ for (thread_t *th = thread_root; th != NULL;prev = th, th = th->next) {
|
|
|
+ // unlink the node from the list
|
|
|
+ if (th->id == rt_thread_self()) {
|
|
|
+
|
|
|
+ if (prev != NULL) {
|
|
|
+ prev->next = th->next;
|
|
|
+ } else {
|
|
|
+ // move the start pointer
|
|
|
+ thread_root = th->next;
|
|
|
+ }
|
|
|
+ th->status = MP_THREAD_STATUS_FINISH;
|
|
|
// explicitly release all its memory
|
|
|
- m_del(rt_thread_t, cur_thread_node->thread, 1);
|
|
|
- m_del(uint8_t, cur_thread_node->stack, cur_thread_node->stack_len);
|
|
|
-// m_del(mp_thread, cur_thread_node, 1);
|
|
|
- rt_list_remove(node);
|
|
|
+ m_del_obj(struct rt_thread, th->id);
|
|
|
+ m_del(uint8_t, th->stack, th->stack_len);
|
|
|
+ m_del_obj(thread_t, th);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
mp_thread_mutex_unlock(&thread_mutex);
|
|
|
-
|
|
|
- rt_thread_detach(rt_thread_self());
|
|
|
}
|
|
|
|
|
|
void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
|
|
|
static uint8_t count = 0;
|
|
|
char name[RT_NAME_MAX];
|
|
|
- rt_base_t level;
|
|
|
|
|
|
- level = rt_hw_interrupt_disable();
|
|
|
-
|
|
|
- mp_mutex *node = rt_malloc(sizeof(mp_mutex));
|
|
|
- if (node == NULL) {
|
|
|
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create mutex list node"));
|
|
|
+ if (!mutex->is_init) {
|
|
|
+ /* build name */
|
|
|
+ rt_snprintf(name, sizeof(name), "mp%02d", count++);
|
|
|
+ rt_mutex_init(&(mutex->mutex), name, RT_IPC_FLAG_FIFO);
|
|
|
+ mutex->is_init = 1;
|
|
|
}
|
|
|
-
|
|
|
- /* build name */
|
|
|
- rt_snprintf(name, sizeof(name), "mp%02d", count ++);
|
|
|
-
|
|
|
- rt_mutex_init((rt_mutex_t) mutex, name, RT_IPC_FLAG_FIFO);
|
|
|
-
|
|
|
- // add mutex to linked list of all mutexs
|
|
|
- node->mutex = (rt_mutex_t)mutex;
|
|
|
- rt_list_insert_before(&mutex_list, &(node->list));
|
|
|
-
|
|
|
- rt_hw_interrupt_enable(level);
|
|
|
}
|
|
|
|
|
|
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
|
|
|
- return (RT_EOK == rt_mutex_take((rt_mutex_t) mutex, wait ? RT_WAITING_FOREVER : 0));
|
|
|
+ return (RT_EOK == rt_mutex_take(&(mutex->mutex), wait ? RT_WAITING_FOREVER : 0));
|
|
|
}
|
|
|
|
|
|
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
|
|
|
- rt_mutex_release((rt_mutex_t) mutex);
|
|
|
+ rt_mutex_release(&(mutex->mutex));
|
|
|
}
|
|
|
|
|
|
void mp_thread_deinit(void) {
|
|
|
- rt_base_t level;
|
|
|
-
|
|
|
- level = rt_hw_interrupt_disable();
|
|
|
- /* remove all thread node on list */
|
|
|
- {
|
|
|
- struct rt_list_node *list = &thread_list, *node = NULL;
|
|
|
- mp_thread_t cur_thread_node = NULL;
|
|
|
-
|
|
|
- for (node = list->next; node != list; node = node->next) {
|
|
|
- cur_thread_node = rt_list_entry(node, mp_thread, list);
|
|
|
- if (cur_thread_node->thread != main_thread->thread) {
|
|
|
- rt_thread_detach(cur_thread_node->thread);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- /* remove all mutex node on list */
|
|
|
- {
|
|
|
- struct rt_list_node *list = &mutex_list, *node = NULL;
|
|
|
- mp_mutex_t cur_mutex_node = NULL;
|
|
|
-
|
|
|
- for (node = list->next; node != list; node = node->next) {
|
|
|
- cur_mutex_node = rt_list_entry(node, mp_mutex, list);
|
|
|
- rt_mutex_detach(cur_mutex_node->mutex);
|
|
|
- rt_free(cur_mutex_node);
|
|
|
+ // detach all ready and running mpy thread
|
|
|
+ for (thread_t *th = thread_root; th != NULL; th = th->next) {
|
|
|
+ if (th != &thread_root_node && th->status != MP_THREAD_STATUS_FINISH) {
|
|
|
+ rt_thread_detach(th->id);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- rt_hw_interrupt_enable(level);
|
|
|
// allow RT-Thread to clean-up the threads
|
|
|
rt_thread_delay(200);
|
|
|
}
|