[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)
|
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);
|
LOG_E("thread:%s exit:%d!", self->name, status);
|
||||||
rt_thread_control(self, RT_THREAD_CTRL_CLOSE, RT_NULL);
|
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
|
* 2018-01-26 Bernard Fix pthread_detach issue for a none-joinable
|
||||||
* thread.
|
* thread.
|
||||||
* 2019-02-07 Bernard Add _pthread_destroy to release pthread resource.
|
* 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>
|
#include <rthw.h>
|
||||||
|
@ -87,15 +88,18 @@ pthread_t _pthread_data_create(void)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pthread_data_destroy(pthread_t pth)
|
void _pthread_data_destroy(_pthread_data_t *ptd)
|
||||||
{
|
{
|
||||||
RT_DECLARE_SPINLOCK(pth_lock);
|
RT_DECLARE_SPINLOCK(pth_lock);
|
||||||
|
|
||||||
extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
|
extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
|
||||||
_pthread_data_t *ptd = _pthread_get_data(pth);
|
pthread_t pth;
|
||||||
|
|
||||||
if (ptd)
|
if (ptd)
|
||||||
{
|
{
|
||||||
/* destruct thread local key */
|
/* if this thread create the local thread data,
|
||||||
|
* destruct thread local key
|
||||||
|
*/
|
||||||
if (ptd->tls != RT_NULL)
|
if (ptd->tls != RT_NULL)
|
||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -115,6 +119,7 @@ void _pthread_data_destroy(pthread_t pth)
|
||||||
ptd->tls = RT_NULL;
|
ptd->tls = RT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pth = _pthread_data_get_pth(ptd);
|
||||||
/* remove from pthread table */
|
/* remove from pthread table */
|
||||||
rt_hw_spin_lock(&pth_lock);
|
rt_hw_spin_lock(&pth_lock);
|
||||||
pth_table[pth] = NULL;
|
pth_table[pth] = NULL;
|
||||||
|
@ -122,66 +127,32 @@ void _pthread_data_destroy(pthread_t pth)
|
||||||
|
|
||||||
/* delete joinable semaphore */
|
/* delete joinable semaphore */
|
||||||
if (ptd->joinable_sem != RT_NULL)
|
if (ptd->joinable_sem != RT_NULL)
|
||||||
|
{
|
||||||
rt_sem_delete(ptd->joinable_sem);
|
rt_sem_delete(ptd->joinable_sem);
|
||||||
|
ptd->joinable_sem = RT_NULL;
|
||||||
/* release thread resource */
|
|
||||||
if (ptd->attr.stackaddr == RT_NULL)
|
|
||||||
{
|
|
||||||
/* release thread allocated stack */
|
|
||||||
if (ptd->tid)
|
|
||||||
{
|
|
||||||
rt_free(ptd->tid->stack_addr);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* 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 */
|
/* clean magic */
|
||||||
ptd->magic = 0x0;
|
ptd->magic = 0x0;
|
||||||
|
|
||||||
|
/* clear the "ptd->tid->user_data" */
|
||||||
|
ptd->tid->user_data = RT_NULL;
|
||||||
|
|
||||||
/* free ptd */
|
/* free ptd */
|
||||||
rt_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)
|
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 */
|
/* clear cleanup function */
|
||||||
tid->cleanup = RT_NULL;
|
tid->cleanup = RT_NULL;
|
||||||
if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
|
|
||||||
{
|
/* restore tid stack */
|
||||||
rt_sem_release(ptd->joinable_sem);
|
rt_free(tid->stack_addr);
|
||||||
}
|
|
||||||
else
|
/* restore tid control block */
|
||||||
{
|
rt_free(tid);
|
||||||
/* release pthread resource */
|
|
||||||
_pthread_destroy(ptd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pthread_entry_stub(void *parameter)
|
static void pthread_entry_stub(void *parameter)
|
||||||
|
@ -193,8 +164,19 @@ static void pthread_entry_stub(void *parameter)
|
||||||
|
|
||||||
/* execute pthread entry */
|
/* execute pthread entry */
|
||||||
value = ptd->thread_entry(ptd->thread_parameter);
|
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 */
|
/* set value */
|
||||||
ptd->return_value = 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,
|
int pthread_create(pthread_t *pid,
|
||||||
|
@ -311,7 +293,9 @@ int pthread_create(pthread_t *pid,
|
||||||
|
|
||||||
__exit:
|
__exit:
|
||||||
if (pth_id != PTHREAD_NUM_MAX)
|
if (pth_id != PTHREAD_NUM_MAX)
|
||||||
_pthread_data_destroy(pth_id);
|
{
|
||||||
|
_pthread_data_destroy(ptd);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
RTM_EXPORT(pthread_create);
|
RTM_EXPORT(pthread_create);
|
||||||
|
@ -327,7 +311,6 @@ int pthread_detach(pthread_t thread)
|
||||||
goto __exit;
|
goto __exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_enter_critical();
|
|
||||||
if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
||||||
{
|
{
|
||||||
/* The implementation has detected that the value specified by thread does not refer
|
/* 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)
|
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 */
|
/* destroy this pthread */
|
||||||
_pthread_destroy(ptd);
|
_pthread_data_destroy(ptd);
|
||||||
}
|
|
||||||
|
|
||||||
goto __exit;
|
goto __exit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -376,7 +340,6 @@ int pthread_detach(pthread_t thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
__exit:
|
__exit:
|
||||||
rt_exit_critical();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
RTM_EXPORT(pthread_detach);
|
RTM_EXPORT(pthread_detach);
|
||||||
|
@ -412,7 +375,7 @@ int pthread_join(pthread_t thread, void **value_ptr)
|
||||||
*value_ptr = ptd->return_value;
|
*value_ptr = ptd->return_value;
|
||||||
|
|
||||||
/* destroy this pthread */
|
/* destroy this pthread */
|
||||||
_pthread_destroy(ptd);
|
_pthread_data_destroy(ptd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -507,9 +470,12 @@ void pthread_exit(void *value)
|
||||||
{
|
{
|
||||||
_pthread_data_t *ptd;
|
_pthread_data_t *ptd;
|
||||||
_pthread_cleanup_t *cleanup;
|
_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 */
|
/* get pthread data from user data of thread */
|
||||||
ptd = (_pthread_data_t *)rt_thread_self()->user_data;
|
ptd = (_pthread_data_t *)rt_thread_self()->user_data;
|
||||||
|
@ -521,7 +487,10 @@ void pthread_exit(void *value)
|
||||||
ptd->return_value = value;
|
ptd->return_value = value;
|
||||||
rt_exit_critical();
|
rt_exit_critical();
|
||||||
|
|
||||||
/* invoke pushed cleanup */
|
/*
|
||||||
|
* When use pthread_exit to exit.
|
||||||
|
* invoke pushed cleanup
|
||||||
|
*/
|
||||||
while (ptd->cleanup != RT_NULL)
|
while (ptd->cleanup != RT_NULL)
|
||||||
{
|
{
|
||||||
cleanup = ptd->cleanup;
|
cleanup = ptd->cleanup;
|
||||||
|
@ -532,29 +501,30 @@ void pthread_exit(void *value)
|
||||||
rt_free(cleanup);
|
rt_free(cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destruct thread local key */
|
/* get the info aboult "tid" early */
|
||||||
if (ptd->tls != RT_NULL)
|
tid = ptd->tid;
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
rt_uint32_t index;
|
|
||||||
|
|
||||||
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)
|
/* set value */
|
||||||
{
|
rt_sem_release(ptd->joinable_sem);
|
||||||
data = ptd->tls[index];
|
|
||||||
if (data && _thread_keys[index].destructor)
|
|
||||||
_thread_keys[index].destructor(data);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* release pthread resource */
|
||||||
|
_pthread_data_destroy(ptd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release tls area */
|
/*
|
||||||
rt_free(ptd->tls);
|
* second: detach thread.
|
||||||
ptd->tls = RT_NULL;
|
* 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 */
|
/* reschedule thread */
|
||||||
rt_schedule();
|
rt_schedule();
|
||||||
}
|
}
|
||||||
|
@ -765,6 +735,8 @@ RTM_EXPORT(pthread_testcancel);
|
||||||
int pthread_cancel(pthread_t thread)
|
int pthread_cancel(pthread_t thread)
|
||||||
{
|
{
|
||||||
_pthread_data_t *ptd;
|
_pthread_data_t *ptd;
|
||||||
|
_pthread_cleanup_t *cleanup;
|
||||||
|
rt_thread_t tid;
|
||||||
|
|
||||||
/* get posix thread data */
|
/* get posix thread data */
|
||||||
ptd = _pthread_get_data(thread);
|
ptd = _pthread_get_data(thread);
|
||||||
|
@ -772,6 +744,7 @@ int pthread_cancel(pthread_t thread)
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
tid = ptd->tid;
|
||||||
|
|
||||||
/* cancel self */
|
/* cancel self */
|
||||||
if (ptd->tid == rt_thread_self())
|
if (ptd->tid == rt_thread_self())
|
||||||
|
@ -784,13 +757,39 @@ int pthread_cancel(pthread_t thread)
|
||||||
if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
|
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
|
* this thread will be removed from scheduler list
|
||||||
* and because there is a cleanup function in the
|
* and because there is a cleanup function in the
|
||||||
* thread (pthread_cleanup), it will move to defunct
|
* thread (pthread_cleanup), it will move to defunct
|
||||||
* thread list and wait for handling in idle thread.
|
* 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)
|
while (1)
|
||||||
{
|
{
|
||||||
rt_thread_t thread;
|
rt_thread_t thread;
|
||||||
|
rt_bool_t object_is_systemobject;
|
||||||
void (*cleanup)(struct rt_thread *tid);
|
void (*cleanup)(struct rt_thread *tid);
|
||||||
|
|
||||||
#ifdef RT_USING_MODULE
|
#ifdef RT_USING_MODULE
|
||||||
|
@ -212,32 +213,38 @@ static void rt_defunct_execute(void)
|
||||||
dlmodule_destroy(module);
|
dlmodule_destroy(module);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* invoke thread cleanup */
|
|
||||||
cleanup = thread->cleanup;
|
|
||||||
if (cleanup != RT_NULL)
|
|
||||||
{
|
|
||||||
cleanup(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef RT_USING_SIGNALS
|
#ifdef RT_USING_SIGNALS
|
||||||
rt_thread_free_sig(thread);
|
rt_thread_free_sig(thread);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* store the point of "thread->cleanup" avoid to lose */
|
||||||
|
cleanup = thread->cleanup;
|
||||||
|
|
||||||
/* if it's a system object, not delete it */
|
/* 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 */
|
/* detach this object */
|
||||||
rt_object_detach((rt_object_t)thread);
|
rt_object_detach((rt_object_t)thread);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* invoke thread cleanup */
|
||||||
|
if (cleanup != RT_NULL)
|
||||||
{
|
{
|
||||||
|
cleanup(thread);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef RT_USING_HEAP
|
#ifdef RT_USING_HEAP
|
||||||
|
/* if need free, delete it */
|
||||||
|
if (object_is_systemobject == RT_FALSE)
|
||||||
|
{
|
||||||
/* release thread's stack */
|
/* release thread's stack */
|
||||||
RT_KERNEL_FREE(thread->stack_addr);
|
RT_KERNEL_FREE(thread->stack_addr);
|
||||||
/* delete thread object */
|
/* delete thread object */
|
||||||
rt_object_delete((rt_object_t)thread);
|
rt_object_delete((rt_object_t)thread);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue