[modify] the recycle logic about resource of pthread.
This commit is contained in:
parent
9ab2094ef6
commit
9f5a9b6bc8
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
25
src/idle.c
25
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue