aboutsummaryrefslogtreecommitdiff
path: root/nuttx/sched
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-08-01 17:47:54 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-08-01 17:47:54 +0000
commit20324504d5997b2ddad85ec3bfa91544c09edd2a (patch)
tree9226c125b2583f72f45393934b2571f2600fee49 /nuttx/sched
parent8a4cf655d73899d4a6bac46c2ef762e0e9344ede (diff)
downloadpx4-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.c88
-rw-r--r--nuttx/sched/on_exit.c92
-rw-r--r--nuttx/sched/task_exithook.c159
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).
*/