Move atexit/on_exit data structures to task group; Now callbacks only occur when the final member of the task group exits
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5607 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
ad2cddb6e2
commit
b1bf234bf3
@ -4108,3 +4108,8 @@
|
|||||||
const char **.
|
const char **.
|
||||||
* sched/pthread* and include/nuttx/sched: Move pthread join data
|
* sched/pthread* and include/nuttx/sched: Move pthread join data
|
||||||
and pthread key calculation data into the "task group" structure.
|
and pthread key calculation data into the "task group" structure.
|
||||||
|
* sched/atexit.c, on_exit.c, task_exithook.c and include/nuttx/sched.h:
|
||||||
|
Move atexit and on_exit data structure to task group. These
|
||||||
|
callbacks are only issued now when the final member of the task
|
||||||
|
group exits.
|
||||||
|
|
||||||
|
24
TODO
24
TODO
@ -7,7 +7,7 @@ standards, things that could be improved, and ideas for enhancements.
|
|||||||
nuttx/
|
nuttx/
|
||||||
|
|
||||||
(11) Task/Scheduler (sched/)
|
(11) Task/Scheduler (sched/)
|
||||||
(2) Memory Managment (mm/)
|
(1) Memory Managment (mm/)
|
||||||
(3) Signals (sched/, arch/)
|
(3) Signals (sched/, arch/)
|
||||||
(2) pthreads (sched/)
|
(2) pthreads (sched/)
|
||||||
(2) C++ Support
|
(2) C++ Support
|
||||||
@ -186,9 +186,9 @@ o Task/Scheduler (sched/)
|
|||||||
posix_spawn(). However, posix_spawn uses the non-standard, internal
|
posix_spawn(). However, posix_spawn uses the non-standard, internal
|
||||||
NuttX interface task_reparent() to replace the childs parent task
|
NuttX interface task_reparent() to replace the childs parent task
|
||||||
with the caller of posix_spawn(). That cannot be done with vfork()
|
with the caller of posix_spawn(). That cannot be done with vfork()
|
||||||
because we don't know what vfor() is going to do.
|
because we don't know what vfork() is going to do.
|
||||||
|
|
||||||
Any solution to this is either very difficult or impossible with
|
Any solution to this is either very difficult or impossible without
|
||||||
an MMU.
|
an MMU.
|
||||||
Status: Open
|
Status: Open
|
||||||
Priority: Low (it might as well be low since it isn't going to be fixed).
|
Priority: Low (it might as well be low since it isn't going to be fixed).
|
||||||
@ -200,7 +200,8 @@ o Task/Scheduler (sched/)
|
|||||||
to make this change: Just move the pterrno field from
|
to make this change: Just move the pterrno field from
|
||||||
_TCB to struct task_group_s. However, I am still not sure
|
_TCB to struct task_group_s. However, I am still not sure
|
||||||
if this should be done or not.
|
if this should be done or not.
|
||||||
Status: Open
|
Status: Closed. The existing solution is better (although its
|
||||||
|
incompatibilities could show up in porting some code).
|
||||||
Priority: Low
|
Priority: Low
|
||||||
|
|
||||||
o Memory Managment (mm/)
|
o Memory Managment (mm/)
|
||||||
@ -269,19 +270,6 @@ o Memory Managment (mm/)
|
|||||||
Priority: Medium/Low, a good feature to prevent memory leaks but would
|
Priority: Medium/Low, a good feature to prevent memory leaks but would
|
||||||
have negative impact on memory usage and code size.
|
have negative impact on memory usage and code size.
|
||||||
|
|
||||||
Title: CONTAINER ALLOCATOR
|
|
||||||
Description: There are several places where the logic requires allocation of
|
|
||||||
a tiny structure that just contains pointers to other things or
|
|
||||||
small amounts of data that needs to be bundled together. There
|
|
||||||
are examples net/net_poll.c and numerous other places.
|
|
||||||
|
|
||||||
I am wondering if it would not be good create a pool of generic
|
|
||||||
containers (say void *[4]). There re-use these when we need
|
|
||||||
small containers. The code in sched/task_childstatus.c might
|
|
||||||
be generalized for this purpose.
|
|
||||||
Status: Open
|
|
||||||
Priority: Very low (I am not even sure that this is a good idea yet).
|
|
||||||
|
|
||||||
o Signals (sched/, arch/)
|
o Signals (sched/, arch/)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@ -289,7 +277,7 @@ o Signals (sched/, arch/)
|
|||||||
Description: 'Standard' signals and signal actions are not supported.
|
Description: 'Standard' signals and signal actions are not supported.
|
||||||
(e.g., SIGINT, SIGSEGV, etc).
|
(e.g., SIGINT, SIGSEGV, etc).
|
||||||
|
|
||||||
Update: SIG_CHLD is support if configured.
|
Update: SIG_CHLD is supported if so configured.
|
||||||
Status: Open. No changes are planned.
|
Status: Open. No changes are planned.
|
||||||
Priority: Low, required by standards but not so critical for an
|
Priority: Low, required by standards but not so critical for an
|
||||||
embedded system.
|
embedded system.
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
#undef HAVE_TASK_GROUP
|
#undef HAVE_TASK_GROUP
|
||||||
#undef HAVE_GROUP_MEMBERS
|
#undef HAVE_GROUP_MEMBERS
|
||||||
|
|
||||||
/* We need a group an group members if we are supportint the parent/child
|
/* We need a group an group members if we are supporting the parent/child
|
||||||
* relationship.
|
* relationship.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -77,13 +77,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# if !defined(CONFIG_DISABLE_ENVIRON)
|
# if !defined(CONFIG_DISABLE_ENVIRON) /* Environment variales */
|
||||||
# define HAVE_TASK_GROUP 1
|
# define HAVE_TASK_GROUP 1
|
||||||
# elif CONFIG_NFILE_DESCRIPTORS > 0
|
# elif defined(CONFIG_SCHED_ATEXIT) /* Group atexit() function */
|
||||||
# define HAVE_TASK_GROUP 1
|
# define HAVE_TASK_GROUP 1
|
||||||
# elif CONFIG_NFILE_STREAMS > 0
|
# elif defined(CONFIG_SCHED_ONEXIT) /* Group on_exit() function */
|
||||||
# define HAVE_TASK_GROUP 1
|
# define HAVE_TASK_GROUP 1
|
||||||
# elif CONFIG_NSOCKET_DESCRIPTORS > 0
|
# elif CONFIG_NFILE_DESCRIPTORS > 0 /* File descriptors */
|
||||||
|
# define HAVE_TASK_GROUP 1
|
||||||
|
# elif CONFIG_NFILE_STREAMS > 0 /* Standard C buffered I/O */
|
||||||
|
# define HAVE_TASK_GROUP 1
|
||||||
|
# elif CONFIG_NSOCKET_DESCRIPTORS > 0 /* Sockets */
|
||||||
# define HAVE_TASK_GROUP 1
|
# define HAVE_TASK_GROUP 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -296,6 +300,26 @@ struct task_group_s
|
|||||||
FAR pid_t *tg_members; /* Members of the group */
|
FAR pid_t *tg_members; /* Members of the group */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* atexit/on_exit support ****************************************************/
|
||||||
|
|
||||||
|
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
|
||||||
|
# if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
||||||
|
atexitfunc_t tg_atexitfunc[CONFIG_SCHED_ATEXIT_MAX];
|
||||||
|
# else
|
||||||
|
atexitfunc_t tg_atexitfunc; /* Called when exit is called. */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_ONEXIT
|
||||||
|
# if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
||||||
|
onexitfunc_t tg_onexitfunc[CONFIG_SCHED_ONEXIT_MAX];
|
||||||
|
FAR void *tg_onexitarg[CONFIG_SCHED_ONEXIT_MAX];
|
||||||
|
# else
|
||||||
|
onexitfunc_t tg_onexitfunc; /* Called when exit is called. */
|
||||||
|
FAR void *tg_onexitarg; /* The argument passed to the function */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Child exit status **********************************************************/
|
/* Child exit status **********************************************************/
|
||||||
|
|
||||||
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
|
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
|
||||||
@ -384,24 +408,6 @@ struct _TCB
|
|||||||
FAR void *starthookarg; /* The argument passed to the function */
|
FAR void *starthookarg; /* The argument passed to the function */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
|
|
||||||
# if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
|
||||||
atexitfunc_t atexitfunc[CONFIG_SCHED_ATEXIT_MAX];
|
|
||||||
# else
|
|
||||||
atexitfunc_t atexitfunc; /* Called when exit is called. */
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_ONEXIT
|
|
||||||
# if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
|
||||||
onexitfunc_t onexitfunc[CONFIG_SCHED_ONEXIT_MAX];
|
|
||||||
FAR void *onexitarg[CONFIG_SCHED_ONEXIT_MAX];
|
|
||||||
# else
|
|
||||||
onexitfunc_t onexitfunc; /* Called when exit is called. */
|
|
||||||
FAR void *onexitarg; /* The argument passed to the function */
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
|
#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT)
|
||||||
sem_t exitsem; /* Support for waitpid */
|
sem_t exitsem; /* Support for waitpid */
|
||||||
int *stat_loc; /* Location to return exit status */
|
int *stat_loc; /* Location to return exit status */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* sched/atexit.c
|
* sched/atexit.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007, 2009, 2011-2013 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -117,12 +117,15 @@ int atexit(void (*func)(void))
|
|||||||
* can handle a callback function that recieves more parameters than it expects).
|
* can handle a callback function that recieves more parameters than it expects).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return on_exit(onexitfunc_t func, NULL);
|
return on_exit((onexitfunc_t)func, NULL);
|
||||||
|
|
||||||
#elif defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
#elif defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
||||||
_TCB *tcb = (_TCB*)g_readytorun.head;
|
FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
|
||||||
int index;
|
FAR struct task_group_s *group = tcb->group;
|
||||||
int ret = ERROR;
|
int index;
|
||||||
|
int ret = ERROR;
|
||||||
|
|
||||||
|
DEBUGASSERT(group);
|
||||||
|
|
||||||
/* The following must be atomic */
|
/* The following must be atomic */
|
||||||
|
|
||||||
@ -139,9 +142,9 @@ int atexit(void (*func)(void))
|
|||||||
available = -1;
|
available = -1;
|
||||||
for (index = 0; index < CONFIG_SCHED_ATEXIT_MAX; index++)
|
for (index = 0; index < CONFIG_SCHED_ATEXIT_MAX; index++)
|
||||||
{
|
{
|
||||||
if (!tcb->atexitfunc[index])
|
if (!group->tg_atexitfunc[index])
|
||||||
{
|
{
|
||||||
tcb->atexitfunc[index] = func;
|
group->tg_atexitfunc[index] = func;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -152,15 +155,18 @@ int atexit(void (*func)(void))
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
_TCB *tcb = (_TCB*)g_readytorun.head;
|
FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
|
||||||
int ret = ERROR;
|
FAR struct task_group_s *group = tcb->group;
|
||||||
|
int ret = ERROR;
|
||||||
|
|
||||||
|
DEBUGASSERT(group);
|
||||||
|
|
||||||
/* The following must be atomic */
|
/* The following must be atomic */
|
||||||
|
|
||||||
sched_lock();
|
sched_lock();
|
||||||
if (func && !tcb->atexitfunc)
|
if (func && !group->tg_atexitfunc)
|
||||||
{
|
{
|
||||||
tcb->atexitfunc = func;
|
group->tg_atexitfunc = func;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,9 @@
|
|||||||
#include <nuttx/net/net.h>
|
#include <nuttx/net/net.h>
|
||||||
#include <nuttx/lib.h>
|
#include <nuttx/lib.h>
|
||||||
|
|
||||||
#include "group_internal.h"
|
|
||||||
#include "env_internal.h"
|
#include "env_internal.h"
|
||||||
|
#include "pthread_internal.h"
|
||||||
|
#include "group_internal.h"
|
||||||
|
|
||||||
#ifdef HAVE_TASK_GROUP
|
#ifdef HAVE_TASK_GROUP
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* sched/on_exit.c
|
* sched/on_exit.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2012-2013 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -115,10 +115,13 @@
|
|||||||
int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
|
int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
||||||
_TCB *tcb = (_TCB*)g_readytorun.head;
|
FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
|
||||||
|
FAR struct task_group_s *group = tcb->group;
|
||||||
int index;
|
int index;
|
||||||
int ret = ENOSPC;
|
int ret = ENOSPC;
|
||||||
|
|
||||||
|
DEBUGASSERT(group);
|
||||||
|
|
||||||
/* The following must be atomic */
|
/* The following must be atomic */
|
||||||
|
|
||||||
if (func)
|
if (func)
|
||||||
@ -133,10 +136,10 @@ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
|
|||||||
|
|
||||||
for (index = 0; index < CONFIG_SCHED_ONEXIT_MAX; index++)
|
for (index = 0; index < CONFIG_SCHED_ONEXIT_MAX; index++)
|
||||||
{
|
{
|
||||||
if (!tcb->onexitfunc[index])
|
if (!group->tg_onexitfunc[index])
|
||||||
{
|
{
|
||||||
tcb->onexitfunc[index] = func;
|
group->tg_onexitfunc[index] = func;
|
||||||
tcb->onexitarg[index] = arg;
|
group->tg_onexitarg[index] = arg;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -147,16 +150,19 @@ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
#else
|
||||||
_TCB *tcb = (_TCB*)g_readytorun.head;
|
FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
|
||||||
|
FAR struct task_group_s *group = tcb->group;
|
||||||
int ret = ENOSPC;
|
int ret = ENOSPC;
|
||||||
|
|
||||||
|
DEBUGASSERT(group);
|
||||||
|
|
||||||
/* The following must be atomic */
|
/* The following must be atomic */
|
||||||
|
|
||||||
sched_lock();
|
sched_lock();
|
||||||
if (func && !tcb->onexitfunc)
|
if (func && !group->tg_onexitfunc)
|
||||||
{
|
{
|
||||||
tcb->onexitfunc = func;
|
group->tg_onexitfunc = func;
|
||||||
tcb->onexitarg = arg;
|
group->tg_onexitarg = arg;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,41 +87,50 @@
|
|||||||
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
|
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
|
||||||
static inline void task_atexit(FAR _TCB *tcb)
|
static inline void task_atexit(FAR _TCB *tcb)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
FAR struct task_group_s *group = tcb->group;
|
||||||
int index;
|
|
||||||
|
|
||||||
/* Call each atexit function in reverse order of registration atexit()
|
/* Make sure that we have not already left the group. Only the final
|
||||||
* functions are registered from lower to higher arry indices; they must
|
* exitting thread in the task group should trigger the atexit()
|
||||||
* be called in the reverse order of registration when task exists, i.e.,
|
* callbacks.
|
||||||
* from higher to lower indices.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--)
|
if (group && group->tg_nmembers == 1)
|
||||||
{
|
{
|
||||||
if (tcb->atexitfunc[index])
|
#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/* Call each atexit function in reverse order of registration atexit()
|
||||||
|
* functions are registered from lower to higher arry indices; they
|
||||||
|
* must be called in the reverse order of registration when the task
|
||||||
|
* group exits, i.e., from higher to lower indices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
if (group->tg_atexitfunc[index])
|
||||||
|
{
|
||||||
|
/* Call the atexit function */
|
||||||
|
|
||||||
|
(*group->tg_atexitfunc[index])();
|
||||||
|
|
||||||
|
/* Nullify the atexit function to prevent its reuse. */
|
||||||
|
|
||||||
|
group->tg_atexitfunc[index] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (group->tg_atexitfunc)
|
||||||
{
|
{
|
||||||
/* Call the atexit function */
|
/* Call the atexit function */
|
||||||
|
|
||||||
(*tcb->atexitfunc[index])();
|
(*group->tg_atexitfunc)();
|
||||||
|
|
||||||
/* Nullify the atexit function to prevent its reuse. */
|
/* Nullify the atexit function to prevent its reuse. */
|
||||||
|
|
||||||
tcb->atexitfunc[index] = NULL;
|
group->tg_atexitfunc = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
if (tcb->atexitfunc)
|
|
||||||
{
|
|
||||||
/* Call the atexit function */
|
|
||||||
|
|
||||||
(*tcb->atexitfunc)();
|
|
||||||
|
|
||||||
/* Nullify the atexit function to prevent its reuse. */
|
|
||||||
|
|
||||||
tcb->atexitfunc = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define task_atexit(tcb)
|
# define task_atexit(tcb)
|
||||||
@ -138,40 +147,50 @@ static inline void task_atexit(FAR _TCB *tcb)
|
|||||||
#ifdef CONFIG_SCHED_ONEXIT
|
#ifdef CONFIG_SCHED_ONEXIT
|
||||||
static inline void task_onexit(FAR _TCB *tcb, int status)
|
static inline void task_onexit(FAR _TCB *tcb, int status)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
FAR struct task_group_s *group = tcb->group;
|
||||||
int index;
|
|
||||||
|
|
||||||
/* Call each on_exit function in reverse order of registration. on_exit()
|
/* Make sure that we have not already left the group. Only the final
|
||||||
* functions are registered from lower to higher arry indices; they must
|
* exitting thread in the task group should trigger the atexit()
|
||||||
* be called in the reverse order of registration when task exists, i.e.,
|
* callbacks.
|
||||||
* from higher to lower indices.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--)
|
if (group && group->tg_nmembers == 1)
|
||||||
{
|
{
|
||||||
if (tcb->onexitfunc[index])
|
#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
||||||
|
int index;
|
||||||
|
|
||||||
|
/* Call each on_exit function in reverse order of registration.
|
||||||
|
* on_exit() functions are registered from lower to higher arry
|
||||||
|
* indices; they must be called in the reverse order of registration
|
||||||
|
* when the task grroup exits, i.e., from higher to lower indices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
if (group->tg_onexitfunc[index])
|
||||||
|
{
|
||||||
|
/* Call the on_exit function */
|
||||||
|
|
||||||
|
(*group->tg_onexitfunc[index])(status, group->tg_onexitarg[index]);
|
||||||
|
|
||||||
|
/* Nullify the on_exit function to prevent its reuse. */
|
||||||
|
|
||||||
|
group->tg_onexitfunc[index] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (group->tg_onexitfunc)
|
||||||
{
|
{
|
||||||
/* Call the on_exit function */
|
/* Call the on_exit function */
|
||||||
|
|
||||||
(*tcb->onexitfunc[index])(status, tcb->onexitarg[index]);
|
(*group->tg_onexitfunc)(status, group->tg_onexitarg);
|
||||||
|
|
||||||
/* Nullify the on_exit function to prevent its reuse. */
|
/* Nullify the on_exit function to prevent its reuse. */
|
||||||
|
|
||||||
tcb->onexitfunc[index] = NULL;
|
group->tg_onexitfunc = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (tcb->onexitfunc)
|
|
||||||
{
|
|
||||||
/* Call the on_exit function */
|
|
||||||
|
|
||||||
(*tcb->onexitfunc)(status, tcb->onexitarg);
|
|
||||||
|
|
||||||
/* Nullify the on_exit function to prevent its reuse. */
|
|
||||||
|
|
||||||
tcb->onexitfunc = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define task_onexit(tcb,status)
|
# define task_onexit(tcb,status)
|
||||||
@ -490,7 +509,7 @@ static inline void task_exitwakeup(FAR _TCB *tcb, int status)
|
|||||||
* Description:
|
* Description:
|
||||||
* This function implements some of the internal logic of exit() and
|
* This function implements some of the internal logic of exit() and
|
||||||
* task_delete(). This function performs some cleanup and other actions
|
* task_delete(). This function performs some cleanup and other actions
|
||||||
* required when a task exists:
|
* required when a task exits:
|
||||||
*
|
*
|
||||||
* - All open streams are flushed and closed.
|
* - All open streams are flushed and closed.
|
||||||
* - All functions registered with atexit() and on_exit() are called, in
|
* - All functions registered with atexit() and on_exit() are called, in
|
||||||
|
Loading…
Reference in New Issue
Block a user