Преглед на файлове

[modify] the recycle logic about resource of pthread.

liuxianliang преди 3 години
родител
ревизия
9f5a9b6bc8
променени са 3 файла, в които са добавени 119 реда и са изтрити 108 реда
  1. 5 0
      components/libc/compilers/common/stdlib.c
  2. 98 99
      components/libc/posix/pthreads/pthread.c
  3. 16 9
      src/idle.c

+ 5 - 0
components/libc/compilers/common/stdlib.c

@@ -20,8 +20,13 @@ void __rt_libc_exit(int status)
 
     if (self != RT_NULL)
     {
+#ifdef RT_USING_PTHREADS
+        extern void pthread_exit(void *value);
+        pthread_exit((void *)status);
+#else
         LOG_E("thread:%s exit:%d!", self->name, status);
         rt_thread_control(self, RT_THREAD_CTRL_CLOSE, RT_NULL);
+#endif
     }
 }
 

+ 98 - 99
components/libc/posix/pthreads/pthread.c

@@ -8,6 +8,7 @@
  * 2018-01-26     Bernard      Fix pthread_detach issue for a none-joinable
  *                             thread.
  * 2019-02-07     Bernard      Add _pthread_destroy to release pthread resource.
+ * 2022-05-10     xiangxistu   Modify the recycle logic about resource of pthread.
  */
 
 #include <rthw.h>
@@ -87,15 +88,18 @@ pthread_t _pthread_data_create(void)
     return index;
 }
 
-void _pthread_data_destroy(pthread_t pth)
+void _pthread_data_destroy(_pthread_data_t *ptd)
 {
     RT_DECLARE_SPINLOCK(pth_lock);
 
     extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
-    _pthread_data_t *ptd = _pthread_get_data(pth);
+    pthread_t pth;
+
     if (ptd)
     {
-        /* destruct thread local key */
+        /* if this thread create the local thread data,
+         * destruct thread local key
+         */
         if (ptd->tls != RT_NULL)
         {
             void *data;
@@ -115,6 +119,7 @@ void _pthread_data_destroy(pthread_t pth)
             ptd->tls = RT_NULL;
         }
 
+        pth  = _pthread_data_get_pth(ptd);
         /* remove from pthread table */
         rt_hw_spin_lock(&pth_lock);
         pth_table[pth] = NULL;
@@ -122,81 +127,58 @@ void _pthread_data_destroy(pthread_t pth)
 
         /* delete joinable semaphore */
         if (ptd->joinable_sem != RT_NULL)
-            rt_sem_delete(ptd->joinable_sem);
-
-        /* release thread resource */
-        if (ptd->attr.stackaddr == RT_NULL)
         {
-            /* release thread allocated stack */
-            if (ptd->tid)
-            {
-                rt_free(ptd->tid->stack_addr);
-            }
+            rt_sem_delete(ptd->joinable_sem);
+            ptd->joinable_sem = RT_NULL;
         }
-        /* clean stack addr pointer */
-        if (ptd->tid)
-            ptd->tid->stack_addr = RT_NULL;
-
-        /*
-        * if this thread create the local thread data,
-        * delete it
-        */
-        if (ptd->tls != RT_NULL) rt_free(ptd->tls);
-        rt_free(ptd->tid);
 
         /* clean magic */
         ptd->magic = 0x0;
 
+        /* clear the "ptd->tid->user_data" */
+        ptd->tid->user_data = RT_NULL;
+
         /* free ptd */
         rt_free(ptd);
     }
 }
 
-static void _pthread_destroy(_pthread_data_t *ptd)
+static void _pthread_cleanup(rt_thread_t tid)
 {
-    pthread_t pth = _pthread_data_get_pth(ptd);
-    if (pth != PTHREAD_NUM_MAX)
-    {
-        _pthread_data_destroy(pth);
-    }
+    /* clear cleanup function */
+    tid->cleanup = RT_NULL;
+
+    /* restore tid stack */
+    rt_free(tid->stack_addr);
 
-    return;
+    /* restore tid control block */
+    rt_free(tid);
 }
 
-static void _pthread_cleanup(rt_thread_t tid)
+static void pthread_entry_stub(void *parameter)
 {
+    void *value;
     _pthread_data_t *ptd;
 
-    /* get pthread data from user data of thread */
-    ptd = (_pthread_data_t *)tid->user_data;
-    RT_ASSERT(ptd != RT_NULL);
+    ptd = (_pthread_data_t *)parameter;
 
-    /* clear cleanup function */
-    tid->cleanup = RT_NULL;
+    /* execute pthread entry */
+    value = ptd->thread_entry(ptd->thread_parameter);
+
+    /* According to "detachstate" to whether or not to recycle resource immediately */
     if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
     {
+        /* set value */
+        ptd->return_value = value;
         rt_sem_release(ptd->joinable_sem);
     }
     else
     {
         /* release pthread resource */
-        _pthread_destroy(ptd);
+        _pthread_data_destroy(ptd);
     }
 }
 
-static void pthread_entry_stub(void *parameter)
-{
-    void *value;
-    _pthread_data_t *ptd;
-
-    ptd = (_pthread_data_t *)parameter;
-
-    /* execute pthread entry */
-    value = ptd->thread_entry(ptd->thread_parameter);
-    /* set value */
-    ptd->return_value = value;
-}
-
 int pthread_create(pthread_t            *pid,
                    const pthread_attr_t *attr,
                    void *(*start)(void *), void *parameter)
@@ -311,7 +293,9 @@ int pthread_create(pthread_t            *pid,
 
 __exit:
     if (pth_id != PTHREAD_NUM_MAX)
-        _pthread_data_destroy(pth_id);
+    {
+        _pthread_data_destroy(ptd);
+    }
     return ret;
 }
 RTM_EXPORT(pthread_create);
@@ -327,7 +311,6 @@ int pthread_detach(pthread_t thread)
         goto __exit;
     }
 
-    rt_enter_critical();
     if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
     {
         /* The implementation has detected that the value specified by thread does not refer
@@ -339,27 +322,8 @@ int pthread_detach(pthread_t thread)
 
     if ((ptd->tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
     {
-        /* this defunct pthread is not handled by idle */
-        if (rt_sem_trytake(ptd->joinable_sem) != RT_EOK)
-        {
-            rt_sem_release(ptd->joinable_sem);
-
-            /* change to detach state */
-            ptd->attr.detachstate = PTHREAD_CREATE_DETACHED;
-
-            /* detach joinable semaphore */
-            if (ptd->joinable_sem)
-            {
-                rt_sem_delete(ptd->joinable_sem);
-                ptd->joinable_sem = RT_NULL;
-            }
-        }
-        else
-        {
-            /* destroy this pthread */
-            _pthread_destroy(ptd);
-        }
-
+        /* destroy this pthread */
+        _pthread_data_destroy(ptd);
         goto __exit;
     }
     else
@@ -376,7 +340,6 @@ int pthread_detach(pthread_t thread)
     }
 
 __exit:
-    rt_exit_critical();
     return ret;
 }
 RTM_EXPORT(pthread_detach);
@@ -412,7 +375,7 @@ int pthread_join(pthread_t thread, void **value_ptr)
             *value_ptr = ptd->return_value;
 
         /* destroy this pthread */
-        _pthread_destroy(ptd);
+        _pthread_data_destroy(ptd);
     }
     else
     {
@@ -507,9 +470,12 @@ void pthread_exit(void *value)
 {
     _pthread_data_t *ptd;
     _pthread_cleanup_t *cleanup;
-    extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
+    rt_thread_t tid;
 
-    if (rt_thread_self() == NULL) return;
+    if (rt_thread_self() == RT_NULL)
+    {
+        return;
+    }
 
     /* get pthread data from user data of thread */
     ptd = (_pthread_data_t *)rt_thread_self()->user_data;
@@ -521,7 +487,10 @@ void pthread_exit(void *value)
     ptd->return_value = value;
     rt_exit_critical();
 
-    /* invoke pushed cleanup */
+    /*
+    * When use pthread_exit to exit.
+    * invoke pushed cleanup
+    */
     while (ptd->cleanup != RT_NULL)
     {
         cleanup = ptd->cleanup;
@@ -532,29 +501,30 @@ void pthread_exit(void *value)
         rt_free(cleanup);
     }
 
-    /* destruct thread local key */
-    if (ptd->tls != RT_NULL)
-    {
-        void *data;
-        rt_uint32_t index;
+    /* get the info aboult "tid" early */
+    tid = ptd->tid;
 
-        for (index = 0; index < PTHREAD_KEY_MAX; index ++)
-        {
-            if (_thread_keys[index].is_used)
-            {
-                data = ptd->tls[index];
-                if (data && _thread_keys[index].destructor)
-                    _thread_keys[index].destructor(data);
-            }
-        }
-
-        /* release tls area */
-        rt_free(ptd->tls);
-        ptd->tls = RT_NULL;
+    /* According to "detachstate" to whether or not to recycle resource immediately */
+    if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
+    {
+        /* set value */
+        rt_sem_release(ptd->joinable_sem);
+    }
+    else
+    {
+        /* release pthread resource */
+        _pthread_data_destroy(ptd);
     }
 
-    /* detach thread */
-    rt_thread_detach(ptd->tid);
+    /*
+        * second: detach thread.
+        * this thread will be removed from scheduler list
+        * and because there is a cleanup function in the
+        * thread (pthread_cleanup), it will move to defunct
+        * thread list and wait for handling in idle thread.
+        */
+    rt_thread_detach(tid);
+
     /* reschedule thread */
     rt_schedule();
 }
@@ -765,6 +735,8 @@ RTM_EXPORT(pthread_testcancel);
 int pthread_cancel(pthread_t thread)
 {
     _pthread_data_t *ptd;
+    _pthread_cleanup_t *cleanup;
+    rt_thread_t tid;
 
     /* get posix thread data */
     ptd = _pthread_get_data(thread);
@@ -772,6 +744,7 @@ int pthread_cancel(pthread_t thread)
     {
         return EINVAL;
     }
+    tid = ptd->tid;
 
     /* cancel self */
     if (ptd->tid == rt_thread_self())
@@ -784,13 +757,39 @@ int pthread_cancel(pthread_t thread)
         if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
         {
             /*
-             * to detach thread.
+             * When use pthread_cancel to exit.
+             * invoke pushed cleanup
+             */
+            while (ptd->cleanup != RT_NULL)
+            {
+                cleanup = ptd->cleanup;
+                ptd->cleanup = cleanup->next;
+
+                cleanup->cleanup_func(cleanup->parameter);
+                /* release this cleanup function */
+                rt_free(cleanup);
+            }
+
+            /* According to "detachstate" to whether or not to recycle resource immediately */
+            if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
+            {
+                /* set value */
+                rt_sem_release(ptd->joinable_sem);
+            }
+            else
+            {
+                /* release pthread resource */
+                _pthread_data_destroy(ptd);
+            }
+
+            /*
+             * second: detach thread.
              * this thread will be removed from scheduler list
              * and because there is a cleanup function in the
              * thread (pthread_cleanup), it will move to defunct
              * thread list and wait for handling in idle thread.
              */
-            rt_thread_detach(ptd->tid);
+            rt_thread_detach(tid);
         }
     }
 

+ 16 - 9
src/idle.c

@@ -194,6 +194,7 @@ static void rt_defunct_execute(void)
     while (1)
     {
         rt_thread_t thread;
+        rt_bool_t object_is_systemobject;
         void (*cleanup)(struct rt_thread *tid);
 
 #ifdef RT_USING_MODULE
@@ -212,32 +213,38 @@ static void rt_defunct_execute(void)
             dlmodule_destroy(module);
         }
 #endif
-        /* invoke thread cleanup */
-        cleanup = thread->cleanup;
-        if (cleanup != RT_NULL)
-        {
-            cleanup(thread);
-        }
 
 #ifdef RT_USING_SIGNALS
         rt_thread_free_sig(thread);
 #endif
 
+        /* store the point of "thread->cleanup" avoid to lose */
+        cleanup = thread->cleanup;
+
         /* if it's a system object, not delete it */
-        if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
+        object_is_systemobject = rt_object_is_systemobject((rt_object_t)thread);
+        if (object_is_systemobject == RT_TRUE)
         {
             /* detach this object */
             rt_object_detach((rt_object_t)thread);
         }
-        else
+
+        /* invoke thread cleanup */
+        if (cleanup != RT_NULL)
         {
+            cleanup(thread);
+        }
+
 #ifdef RT_USING_HEAP
+        /* if need free, delete it */
+        if (object_is_systemobject == RT_FALSE)
+        {
             /* release thread's stack */
             RT_KERNEL_FREE(thread->stack_addr);
             /* delete thread object */
             rt_object_delete((rt_object_t)thread);
-#endif
         }
+#endif
     }
 }