summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/ChangeLog5
-rw-r--r--nuttx/TODO24
-rw-r--r--nuttx/include/nuttx/sched.h52
-rw-r--r--nuttx/sched/atexit.c28
-rw-r--r--nuttx/sched/group_leave.c3
-rw-r--r--nuttx/sched/on_exit.c24
-rw-r--r--nuttx/sched/task_exithook.c103
7 files changed, 135 insertions, 104 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 6e2f5bd02..cc7b911ee 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -4108,3 +4108,8 @@
const char **.
* sched/pthread* and include/nuttx/sched: Move pthread join data
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.
+
diff --git a/nuttx/TODO b/nuttx/TODO
index a0f0aa1bb..f3feb6fb0 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -7,7 +7,7 @@ standards, things that could be improved, and ideas for enhancements.
nuttx/
(11) Task/Scheduler (sched/)
- (2) Memory Managment (mm/)
+ (1) Memory Managment (mm/)
(3) Signals (sched/, arch/)
(2) pthreads (sched/)
(2) C++ Support
@@ -186,9 +186,9 @@ o Task/Scheduler (sched/)
posix_spawn(). However, posix_spawn uses the non-standard, internal
NuttX interface task_reparent() to replace the childs parent task
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.
Status: Open
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
_TCB to struct task_group_s. However, I am still not sure
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
o Memory Managment (mm/)
@@ -269,19 +270,6 @@ o Memory Managment (mm/)
Priority: Medium/Low, a good feature to prevent memory leaks but would
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/)
^^^^^^^^^^^^^^^^^^^^^^^
@@ -289,7 +277,7 @@ o Signals (sched/, arch/)
Description: 'Standard' signals and signal actions are not supported.
(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.
Priority: Low, required by standards but not so critical for an
embedded system.
diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h
index 75c478220..456135962 100644
--- a/nuttx/include/nuttx/sched.h
+++ b/nuttx/include/nuttx/sched.h
@@ -64,7 +64,7 @@
#undef HAVE_TASK_GROUP
#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.
*/
@@ -77,13 +77,17 @@
*/
#else
-# if !defined(CONFIG_DISABLE_ENVIRON)
+# if !defined(CONFIG_DISABLE_ENVIRON) /* Environment variales */
# define HAVE_TASK_GROUP 1
-# elif CONFIG_NFILE_DESCRIPTORS > 0
+# elif defined(CONFIG_SCHED_ATEXIT) /* Group atexit() function */
# define HAVE_TASK_GROUP 1
-# elif CONFIG_NFILE_STREAMS > 0
+# elif defined(CONFIG_SCHED_ONEXIT) /* Group on_exit() function */
# 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
# endif
#endif
@@ -296,6 +300,26 @@ struct task_group_s
FAR pid_t *tg_members; /* Members of the group */
#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 **********************************************************/
#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 */
#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)
sem_t exitsem; /* Support for waitpid */
int *stat_loc; /* Location to return exit status */
diff --git a/nuttx/sched/atexit.c b/nuttx/sched/atexit.c
index b0559b01b..f60598884 100644
--- a/nuttx/sched/atexit.c
+++ b/nuttx/sched/atexit.c
@@ -1,7 +1,7 @@
/****************************************************************************
* 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>
*
* 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).
*/
- 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
- _TCB *tcb = (_TCB*)g_readytorun.head;
- int index;
- int ret = ERROR;
+ FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
+ FAR struct task_group_s *group = tcb->group;
+ int index;
+ int ret = ERROR;
+
+ DEBUGASSERT(group);
/* The following must be atomic */
@@ -139,9 +142,9 @@ int atexit(void (*func)(void))
available = -1;
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;
break;
}
@@ -152,15 +155,18 @@ int atexit(void (*func)(void))
return ret;
#else
- _TCB *tcb = (_TCB*)g_readytorun.head;
- int ret = ERROR;
+ FAR _TCB *tcb = (FAR _TCB*)g_readytorun.head;
+ FAR struct task_group_s *group = tcb->group;
+ int ret = ERROR;
+
+ DEBUGASSERT(group);
/* The following must be atomic */
sched_lock();
- if (func && !tcb->atexitfunc)
+ if (func && !group->tg_atexitfunc)
{
- tcb->atexitfunc = func;
+ group->tg_atexitfunc = func;
ret = OK;
}
diff --git a/nuttx/sched/group_leave.c b/nuttx/sched/group_leave.c
index 1373a25a2..e56952a7b 100644
--- a/nuttx/sched/group_leave.c
+++ b/nuttx/sched/group_leave.c
@@ -48,8 +48,9 @@
#include <nuttx/net/net.h>
#include <nuttx/lib.h>
-#include "group_internal.h"
#include "env_internal.h"
+#include "pthread_internal.h"
+#include "group_internal.h"
#ifdef HAVE_TASK_GROUP
diff --git a/nuttx/sched/on_exit.c b/nuttx/sched/on_exit.c
index 19a4f9196..89c4a2d57 100644
--- a/nuttx/sched/on_exit.c
+++ b/nuttx/sched/on_exit.c
@@ -1,7 +1,7 @@
/****************************************************************************
* 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>
*
* 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)
{
#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 ret = ENOSPC;
+ DEBUGASSERT(group);
+
/* The following must be atomic */
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++)
{
- if (!tcb->onexitfunc[index])
+ if (!group->tg_onexitfunc[index])
{
- tcb->onexitfunc[index] = func;
- tcb->onexitarg[index] = arg;
+ group->tg_onexitfunc[index] = func;
+ group->tg_onexitarg[index] = arg;
ret = OK;
break;
}
@@ -147,16 +150,19 @@ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
return ret;
#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;
+ DEBUGASSERT(group);
+
/* The following must be atomic */
sched_lock();
- if (func && !tcb->onexitfunc)
+ if (func && !group->tg_onexitfunc)
{
- tcb->onexitfunc = func;
- tcb->onexitarg = arg;
+ group->tg_onexitfunc = func;
+ group->tg_onexitarg = arg;
ret = OK;
}
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 889df25e0..20162c0d6 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -87,41 +87,50 @@
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
static inline void task_atexit(FAR _TCB *tcb)
{
-#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
- int index;
+ FAR struct task_group_s *group = tcb->group;
- /* 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.
+ /* Make sure that we have not already left the group. Only the final
+ * exitting thread in the task group should trigger the atexit()
+ * callbacks.
*/
- 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--)
{
- /* Call the atexit function */
+ if (group->tg_atexitfunc[index])
+ {
+ /* Call the atexit function */
- (*tcb->atexitfunc[index])();
+ (*group->tg_atexitfunc[index])();
- /* Nullify the atexit function to prevent its reuse. */
+ /* Nullify the atexit function to prevent its reuse. */
- tcb->atexitfunc[index] = NULL;
+ group->tg_atexitfunc[index] = NULL;
+ }
}
- }
-
#else
- if (tcb->atexitfunc)
- {
- /* Call the atexit function */
+ if (group->tg_atexitfunc)
+ {
+ /* Call the atexit function */
- (*tcb->atexitfunc)();
+ (*group->tg_atexitfunc)();
- /* Nullify the atexit function to prevent its reuse. */
+ /* Nullify the atexit function to prevent its reuse. */
- tcb->atexitfunc = NULL;
- }
+ group->tg_atexitfunc = NULL;
+ }
#endif
+ }
}
#else
# define task_atexit(tcb)
@@ -138,40 +147,50 @@ static inline void task_atexit(FAR _TCB *tcb)
#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;
+ FAR struct task_group_s *group = tcb->group;
- /* 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.
+ /* Make sure that we have not already left the group. Only the final
+ * exitting thread in the task group should trigger the atexit()
+ * callbacks.
*/
- 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--)
{
- /* Call the on_exit function */
+ if (group->tg_onexitfunc[index])
+ {
+ /* Call the on_exit function */
- (*tcb->onexitfunc[index])(status, tcb->onexitarg[index]);
+ (*group->tg_onexitfunc[index])(status, group->tg_onexitarg[index]);
- /* 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[index] = NULL;
+ }
}
- }
#else
- if (tcb->onexitfunc)
- {
- /* Call the on_exit function */
+ if (group->tg_onexitfunc)
+ {
+ /* Call the on_exit function */
- (*tcb->onexitfunc)(status, tcb->onexitarg);
+ (*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 = NULL;
- }
+ group->tg_onexitfunc = NULL;
+ }
#endif
+ }
}
#else
# define task_onexit(tcb,status)
@@ -490,7 +509,7 @@ static inline void task_exitwakeup(FAR _TCB *tcb, int status)
* 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:
+ * required when a task exits:
*
* - All open streams are flushed and closed.
* - All functions registered with atexit() and on_exit() are called, in