|
|
@@ -36,12 +36,21 @@
|
|
|
|
|
|
#if MICROPY_PY_THREAD
|
|
|
|
|
|
-#define MP_THREAD_MIN_STACK_SIZE (4 * 1024)
|
|
|
+#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;
|
|
|
|
|
|
@@ -53,16 +62,58 @@ typedef struct {
|
|
|
// 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;
|
|
|
|
|
|
-void mp_thread_init(void) {
|
|
|
+/**
|
|
|
+ * thread port initialization
|
|
|
+ *
|
|
|
+ * @param stack MicroPython main thread stack
|
|
|
+ * @param stack_len MicroPython main thread stack, unit: word
|
|
|
+ */
|
|
|
+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));
|
|
|
+
|
|
|
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 (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()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!cur_thread_node->ready) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ /* probably not needed */
|
|
|
+ gc_collect_root(cur_thread_node->stack, cur_thread_node->stack_len);
|
|
|
+ }
|
|
|
+
|
|
|
+ mp_thread_mutex_unlock(&thread_mutex);
|
|
|
+}
|
|
|
+
|
|
|
mp_state_thread_t *mp_thread_get_state(void) {
|
|
|
return (mp_state_thread_t *)(rt_thread_self()->user_data);
|
|
|
}
|
|
|
@@ -72,6 +123,20 @@ 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;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mp_thread_mutex_unlock(&thread_mutex);
|
|
|
}
|
|
|
|
|
|
STATIC void *(*ext_thread_entry)(void*) = NULL;
|
|
|
@@ -81,23 +146,7 @@ STATIC void rtthread_entry(void *arg) {
|
|
|
ext_thread_entry(arg);
|
|
|
}
|
|
|
|
|
|
- /* remove node on list */
|
|
|
- {
|
|
|
- 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()) {
|
|
|
- rt_list_remove(node);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- mp_thread_mutex_unlock(&thread_mutex);
|
|
|
- }
|
|
|
+ rt_thread_detach(rt_thread_self());
|
|
|
}
|
|
|
|
|
|
void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
|
|
|
@@ -110,20 +159,30 @@ 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 linked-list node (must be outside thread_mutex lock)
|
|
|
- mp_thread *node = rt_malloc(sizeof(mp_thread));
|
|
|
+ // allocate TCB, stack and linked-list node (must be outside thread_mutex lock)
|
|
|
+ rt_thread_t th = m_new_obj(struct rt_thread);
|
|
|
+ if (th == NULL) {
|
|
|
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread TCB"));
|
|
|
+ }
|
|
|
+ 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"));
|
|
|
+ }
|
|
|
+ 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"));
|
|
|
}
|
|
|
+ // 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);
|
|
|
|
|
|
- // create thread
|
|
|
- rt_thread_t th = rt_thread_create(name, rtthread_entry, arg, *stack_size, priority, 0);
|
|
|
- if (th == NULL) {
|
|
|
- mp_thread_mutex_unlock(&thread_mutex);
|
|
|
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
|
|
|
- }
|
|
|
+ rt_thread_init(th, name, rtthread_entry, arg, stack, *stack_size, priority, 0);
|
|
|
|
|
|
// add thread to linked list of all threads
|
|
|
{
|
|
|
@@ -153,6 +212,27 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
|
|
|
}
|
|
|
|
|
|
void mp_thread_finish(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_FALSE;
|
|
|
+ // 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);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mp_thread_mutex_unlock(&thread_mutex);
|
|
|
+
|
|
|
+ rt_thread_detach(rt_thread_self());
|
|
|
}
|
|
|
|
|
|
void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
|
|
|
@@ -198,8 +278,9 @@ void mp_thread_deinit(void) {
|
|
|
|
|
|
for (node = list->next; node != list; node = node->next) {
|
|
|
cur_thread_node = rt_list_entry(node, mp_thread, list);
|
|
|
- rt_thread_delete(cur_thread_node->thread);
|
|
|
- rt_free(cur_thread_node);
|
|
|
+ if (cur_thread_node->thread != main_thread->thread) {
|
|
|
+ rt_thread_detach(cur_thread_node->thread);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
/* remove all mutex node on list */
|