diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-08-01 17:47:54 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-08-01 17:47:54 +0000 |
commit | 20324504d5997b2ddad85ec3bfa91544c09edd2a (patch) | |
tree | 9226c125b2583f72f45393934b2571f2600fee49 /nuttx/sched | |
parent | 8a4cf655d73899d4a6bac46c2ef762e0e9344ede (diff) | |
download | px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.tar.gz px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.tar.bz2 px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.zip |
atexit() and on_exit() may now be configured to support multiple exit callbacks
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4995 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/sched')
-rw-r--r-- | nuttx/sched/atexit.c | 88 | ||||
-rw-r--r-- | nuttx/sched/on_exit.c | 92 | ||||
-rw-r--r-- | nuttx/sched/task_exithook.c | 159 |
3 files changed, 266 insertions, 73 deletions
diff --git a/nuttx/sched/atexit.c b/nuttx/sched/atexit.c index 2c9b89d92..f7d81bec2 100644 --- a/nuttx/sched/atexit.c +++ b/nuttx/sched/atexit.c @@ -1,4 +1,4 @@ -/************************************************************************ +/**************************************************************************** * sched/atexit.c * * Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved. @@ -31,11 +31,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************/ + ****************************************************************************/ #include <nuttx/config.h> @@ -51,50 +51,95 @@ #ifdef CONFIG_SCHED_ATEXIT -/************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Type Declarations - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Global Variables - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Variables - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Function Prototypes - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Functions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Public Functions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Name: atexit * * Description: * Registers a function to be called at program exit. + * The atexit() function registers the given function to be called + * at normal process termination, whether via exit or via return from + * the program's main(). + * + * NOTE: CONFIG_SCHED_ATEXIT must be defined to enable this function + * + * Limitiations in the current implementation: + * + * 1. Only a single atexit function can be registered unless + * CONFIG_SCHED_ATEXIT_MAX defines a larger number. + * 2. atexit functions are not inherited when a new task is + * created. * * Parameters: - * func + * func - A pointer to the function to be called when the task exits. * * Return Value: * Zero on success. Non-zero on failure. * - ************************************************************************/ + ****************************************************************************/ int atexit(void (*func)(void)) { +#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1 + _TCB *tcb = (_TCB*)g_readytorun.head; + int index; + int ret = ERROR; + + /* The following must be atomic */ + + if (func) + { + sched_lock(); + + /* Search for the first available slot. atexit() functions are registered + * from lower to higher arry indices; they must be called in the reverse + * order of registration when task exists, i.e., from higher to lower + * indices. + */ + + available = -1; + for (index = 0; index < CONFIG_SCHED_ATEXIT_MAX; index++) + { + if (!tcb->atexitfunc[index]) + { + tcb->atexitfunc[index] = func; + ret = OK; + break; + } + } + + sched_unlock(); + } + + return ret; +#else _TCB *tcb = (_TCB*)g_readytorun.head; int ret = ERROR; @@ -109,6 +154,7 @@ int atexit(void (*func)(void)) sched_unlock(); return ret; +#endif } #endif /* CONFIG_SCHED_ATEXIT */ diff --git a/nuttx/sched/on_exit.c b/nuttx/sched/on_exit.c index 8c08026fd..5b8be5cd1 100644 --- a/nuttx/sched/on_exit.c +++ b/nuttx/sched/on_exit.c @@ -1,4 +1,4 @@ -/************************************************************************ +/**************************************************************************** * sched/on_exit.c * * Copyright (C) 2012 Gregory Nutt. All rights reserved. @@ -31,11 +31,11 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************/ + ****************************************************************************/ #include <nuttx/config.h> @@ -51,36 +51,36 @@ #ifdef CONFIG_SCHED_ONEXIT -/************************************************************************ +/**************************************************************************** * Pre-processor Definitions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Type Declarations - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Global Variables - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Variables - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Function Prototypes - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Private Functions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ +/**************************************************************************** * Public Functions - ************************************************************************/ + ****************************************************************************/ -/************************************************************************ - * Name: atexit +/**************************************************************************** + * Name: on_exit * * Description: * Registers a function to be called at program exit. @@ -89,22 +89,65 @@ * the program's main(). The function is passed the status argument * given to the last call to exit and the arg argument from on_exit(). * + * NOTE 1: This function comes from SunOS 4, but is also present in + * libc4, libc5 and glibc. It no longer occurs in Solaris (SunOS 5). + * Avoid this function, and use the standard atexit() instead. + * + * NOTE 2: CONFIG_SCHED_ONEXIT must be defined to enable this function + * * Limitiations in the current implementation: * - * 1. Only a single on_exit function can be registered. + * 1. Only a single on_exit function can be registered unless + * CONFIG_SCHED_ONEXIT_MAX defines a larger number. * 2. on_exit functions are not inherited when a new task is * created. * * Parameters: - * func + * func - A pointer to the function to be called when the task exits. + * arg - An argument that will be provided to the on_exit() function when + * the task exits. * * Return Value: * Zero on success. Non-zero on failure. * - ************************************************************************/ + ****************************************************************************/ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg) { +#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1 + _TCB *tcb = (_TCB*)g_readytorun.head; + int index; + int ret = ERROR; + + /* The following must be atomic */ + + if (func) + { + sched_lock(); + + /* Search for the first available slot. on_exit() functions are registered + * from lower to higher arry indices; they must be called in the reverse + * order of registration when task exists, i.e., from higher to lower + * indices. + */ + + available = -1; + for (index = 0; index < CONFIG_SCHED_ONEXIT_MAX; index++) + { + if (!tcb->onexitfunc[index]) + { + tcb->onexitfunc[index] = func; + tcb->onexitarg[index] = arg; + ret = OK; + break; + } + } + + sched_unlock(); + } + + return ret; +#else _TCB *tcb = (_TCB*)g_readytorun.head; int ret = ERROR; @@ -120,8 +163,9 @@ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg) sched_unlock(); return ret; +#endif } -#endif /* CONFIG_SCHED_ATEXIT */ +#endif /* CONFIG_SCHED_ONEXIT */ diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c index 8fa3bde05..63dc28aa0 100644 --- a/nuttx/sched/task_exithook.c +++ b/nuttx/sched/task_exithook.c @@ -74,40 +74,43 @@ ****************************************************************************/ /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_hook + * Name: task_atexit * * Description: - * This function implements some of the internal logic of exit() and - * task_delete(). This function performs some cleanup and other actions - * required when a task exists: - * - * - All open streams are flushed and closed. - * - All functions registered with atexit() and on_exit() are called, in - * the reverse order of their registration. - * - * When called from exit(), the tcb still resides at the head of the ready- - * to-run list. The following logic is safe because we will not be - * returning from the exit() call. - * - * When called from task_delete() we are operating on a different thread; - * on the thread that called task_delete(). In this case, task_delete - * will have already removed the tcb from the ready-to-run list to prevent - * any further action on this task. + * Call any registerd atexit function(s) * ****************************************************************************/ - -void task_exithook(FAR _TCB *tcb, int status) + +#ifdef CONFIG_SCHED_ATEXIT +static inline void task_atexit(FAR _TCB *tcb) { - /* If an exit function was registered, call it now before we do any un- - * initialized. NOTE: In the case of task_delete(), the exit function - * will *not* be called on the thread execution of the task being deleted! +#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 task exists, i.e., + * from higher to lower indices. */ -#ifdef CONFIG_SCHED_ATEXIT + for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--) + { + if (tcb->atexitfunc[index]) + { + /* Call the atexit function */ + + (*tcb->atexitfunc[index])(); + + /* Nullify the atexit function. task_exithook may be called more then + * once in most task exit scenarios. Nullifying the atext function + * pointer will assure that the callback is performed only once. + */ + + tcb->atexitfunc[index] = NULL; + } + } + +#else if (tcb->atexitfunc) { /* Call the atexit function */ @@ -122,8 +125,47 @@ void task_exithook(FAR _TCB *tcb, int status) tcb->atexitfunc = NULL; } #endif +#else +# define task_atexit(tcb) +#endif +/**************************************************************************** + * Name: task_onexit + * + * Description: + * Call any registerd on)exit function(s) + * + ****************************************************************************/ + #ifdef CONFIG_SCHED_ONEXIT +static inline void task_onexit(FAR _TCB *tcb, int status) +{ +#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 task exists, i.e., + * from higher to lower indices. + */ + + for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--) + { + if (tcb->onexitfunc[index]) + { + /* Call the on_exit function */ + + (*tcb->onexitfunc[index])(status, tcb->onexitarg[index]); + + /* Nullify the on_exit function. task_exithook may be called more then + * once in most task exit scenarios. Nullifying the atext function + * pointer will assure that the callback is performed only once. + */ + + tcb->onexitfunc[index] = NULL; + } + } +#else if (tcb->onexitfunc) { /* Call the on_exit function */ @@ -138,10 +180,23 @@ void task_exithook(FAR _TCB *tcb, int status) tcb->onexitfunc = NULL; } #endif +#else +# define task_onexit(tcb,status) +#endif +/**************************************************************************** + * Name: task_exitwakeup + * + * Description: + * Wakeup any tasks waiting for this task to exit + * + ****************************************************************************/ + +#ifdef CONFIG_SCHED_WAITPID +static inline void task_exitwakeup(FAR _TCB *tcb, int status) +{ /* Wakeup any tasks waiting for this task to exit */ -#ifdef CONFIG_SCHED_WAITPID /* Experimental */ while (tcb->exitsem.semcount < 0) { /* "If more than one thread is suspended in waitpid() awaiting @@ -160,7 +215,55 @@ void task_exithook(FAR _TCB *tcb, int status) sem_post(&tcb->exitsem); } +} +#else +# define task_exitwakeup(tcb, status) #endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_hook + * + * Description: + * This function implements some of the internal logic of exit() and + * task_delete(). This function performs some cleanup and other actions + * required when a task exists: + * + * - All open streams are flushed and closed. + * - All functions registered with atexit() and on_exit() are called, in + * the reverse order of their registration. + * + * When called from exit(), the tcb still resides at the head of the ready- + * to-run list. The following logic is safe because we will not be + * returning from the exit() call. + * + * When called from task_delete() we are operating on a different thread; + * on the thread that called task_delete(). In this case, task_delete + * will have already removed the tcb from the ready-to-run list to prevent + * any further action on this task. + * + ****************************************************************************/ + +void task_exithook(FAR _TCB *tcb, int status) +{ + /* If exit function(s) were registered, call them now before we do any un- + * initialization. NOTE: In the case of task_delete(), the exit function + * will *not* be called on the thread execution of the task being deleted! + */ + + task_atexit(tcb); + + /* Call any registered on_exit function(s) */ + + task_onexit(tcb, status); + + /* Wakeup any tasks waiting for this task to exit */ + + task_exitwakeup(tcb, status); + /* Flush all streams (File descriptors will be closed when * the TCB is deallocated). */ |