Просмотр исходного кода

【完善】多线程相关的垃圾回收机制。

Signed-off-by: armink <armink.ztl@gmail.com>
armink 8 лет назад
Родитель
Сommit
52da5b17f5
2 измененных файлов с 90 добавлено и 75 удалено
  1. 90 71
      port/mpthreadport.c
  2. 0 4
      port/mpy_main.c

+ 90 - 71
port/mpthreadport.c

@@ -32,50 +32,35 @@
 #include "py/mpthread.h"
 #include "mpthreadport.h"
 
+#include <rthw.h>
+
 #if MICROPY_PY_THREAD
 
 #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)
 
-// this structure forms a linked list, one node per active thread
-typedef struct _thread_t {
-    rt_thread_t id;         // system id of thread
-    int ready;              // whether the thread is ready and running
-    void *arg;              // thread Python args, a GC root pointer
-    struct _thread_t *next;
-} thread_t;
+typedef struct {
+    rt_thread_t thread;
+    rt_list_t list;
+} mp_thread, *mp_thread_t;
+
+typedef struct {
+    rt_mutex_t mutex;
+    rt_list_t list;
+} mp_mutex, *mp_mutex_t;
 
 // the mutex controls access to the linked list
 STATIC mp_thread_mutex_t thread_mutex;
-STATIC thread_t thread_entry0;
-STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others
+STATIC rt_list_t thread_list, mutex_list;
 
 void mp_thread_init(void) {
     mp_thread_set_state(&mp_state_ctx.thread);
-    // create the first entry in the linked list of all threads
-    thread = &thread_entry0;
-    thread->id = rt_thread_self();
-    thread->ready = 1;
-    thread->arg = NULL;
-    thread->next = NULL;
-    mp_thread_mutex_init(&thread_mutex);
-}
 
-void mp_thread_gc_others(void) {
-    mp_thread_mutex_lock(&thread_mutex, 1);
-    for (thread_t *th = thread; th != NULL; th = th->next) {
-        gc_collect_root((void**)&th, 1);
-        gc_collect_root(&th->arg, 1); // probably not needed
-        if (th->id == rt_thread_self()) {
-            continue;
-        }
-        if (!th->ready) {
-            continue;
-        }
-        rt_thread_delete(th->id);
-    }
-    mp_thread_mutex_unlock(&thread_mutex);
+    rt_list_init(&thread_list);
+    rt_list_init(&mutex_list);
+
+    mp_thread_mutex_init(&thread_mutex);
 }
 
 mp_state_thread_t *mp_thread_get_state(void) {
@@ -87,14 +72,6 @@ void mp_thread_set_state(void *state) {
 }
 
 void mp_thread_start(void) {
-    mp_thread_mutex_lock(&thread_mutex, 1);
-    for (thread_t *th = thread; th != NULL; th = th->next) {
-        if (th->id == rt_thread_self()) {
-            th->ready = 1;
-            break;
-        }
-    }
-    mp_thread_mutex_unlock(&thread_mutex);
 }
 
 STATIC void *(*ext_thread_entry)(void*) = NULL;
@@ -103,8 +80,23 @@ STATIC void rtthread_entry(void *arg) {
     if (ext_thread_entry) {
         ext_thread_entry(arg);
     }
-    while(1) {
-        rt_thread_delay(RT_TICK_PER_SECOND);
+
+    /* 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);
     }
 }
 
@@ -119,28 +111,34 @@ void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, i
     }
 
     // allocate linked-list node (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 obj"));
+    mp_thread *node = rt_malloc(sizeof(mp_thread));
+    if (node == NULL) {
+        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread list node"));
     }
 
     mp_thread_mutex_lock(&thread_mutex, 1);
 
     // create thread
-    rt_thread_t id = rt_thread_create(name, rtthread_entry, arg, *stack_size, priority, 0);
-    if (id == NULL) {
+    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"));
     }
 
     // add thread to linked list of all threads
-    th->id = id;
-    th->ready = 0;
-    th->arg = arg;
-    th->next = thread;
-    thread = th;
+    {
+        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);
+    }
 
-    rt_thread_startup(id);
+    rt_thread_startup(th);
 
     mp_thread_mutex_unlock(&thread_mutex);
 }
@@ -156,27 +154,30 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
 }
 
 void mp_thread_finish(void) {
-    mp_thread_mutex_lock(&thread_mutex, 1);
-    for (thread_t *th = thread; th != NULL; th = th->next) {
-        if (th->id == rt_thread_self()) {
-            th->ready = 0;
-            break;
-        }
-    }
-    mp_thread_mutex_unlock(&thread_mutex);
 }
 
 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"));
+    }
 
     /* build name */
     rt_snprintf(name, sizeof(name), "mp%02d", count ++);
 
-    /* only init once */
-    if (mutex->parent.parent.type != (RT_Object_Class_Mutex | RT_Object_Class_Static)) {
-        rt_mutex_init((rt_mutex_t) mutex, name, RT_IPC_FLAG_FIFO);
-    }
+    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) {
@@ -188,15 +189,33 @@ void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
 }
 
 void mp_thread_deinit(void) {
-    mp_thread_mutex_lock(&thread_mutex, 1);
-    for (thread_t *th = thread; th != NULL; th = th->next) {
-        // don't delete the current task
-        if (th->id == rt_thread_self()) {
-            continue;
+    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);
+            rt_thread_delete(cur_thread_node->thread);
+            rt_free(cur_thread_node);
         }
-        rt_thread_delete(th->id);
     }
-    mp_thread_mutex_unlock(&thread_mutex);
+    /* 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);
+        }
+    }
+
+    rt_hw_interrupt_enable(level);
     // allow RT-Thread to clean-up the threads
     rt_thread_delay(200);
 }

+ 0 - 4
port/mpy_main.c

@@ -134,10 +134,6 @@ void gc_collect(void) {
     gc_collect_start();
     gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
 
-#if MICROPY_PY_THREAD
-    mp_thread_gc_others();
-#endif
-
     gc_collect_end();
     gc_dump_info();
 }