[modify] the recycle logic about resource of pthread.

This commit is contained in:
liuxianliang 2022-05-10 21:51:30 +08:00 committed by guo
parent 9ab2094ef6
commit 9f5a9b6bc8
3 changed files with 120 additions and 109 deletions

View File

@ -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
}
}

View File

@ -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,66 +127,32 @@ 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);
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)
{
pthread_t pth = _pthread_data_get_pth(ptd);
if (pth != PTHREAD_NUM_MAX)
{
_pthread_data_destroy(pth);
}
return;
}
static void _pthread_cleanup(rt_thread_t tid)
{
_pthread_data_t *ptd;
/* get pthread data from user data of thread */
ptd = (_pthread_data_t *)tid->user_data;
RT_ASSERT(ptd != RT_NULL);
/* clear cleanup function */
tid->cleanup = RT_NULL;
if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
{
rt_sem_release(ptd->joinable_sem);
}
else
{
/* release pthread resource */
_pthread_destroy(ptd);
}
/* restore tid stack */
rt_free(tid->stack_addr);
/* restore tid control block */
rt_free(tid);
}
static void pthread_entry_stub(void *parameter)
@ -193,8 +164,19 @@ static void pthread_entry_stub(void *parameter)
/* 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_data_destroy(ptd);
}
}
int pthread_create(pthread_t *pid,
@ -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
@ -338,28 +321,9 @@ 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);
}
_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 ++)
/* According to "detachstate" to whether or not to recycle resource immediately */
if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
{
if (_thread_keys[index].is_used)
{
data = ptd->tls[index];
if (data && _thread_keys[index].destructor)
_thread_keys[index].destructor(data);
/* set value */
rt_sem_release(ptd->joinable_sem);
}
else
{
/* release pthread resource */
_pthread_data_destroy(ptd);
}
/* release tls area */
rt_free(ptd->tls);
ptd->tls = RT_NULL;
}
/*
* 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);
/* detach thread */
rt_thread_detach(ptd->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);
}
}

View File

@ -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
}
}