From 60185fe969614b01d5dc57f3aa157b24d2901af6 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 2 Feb 2013 19:31:30 +0000 Subject: New interface task_spawn(); exec_builtin() now uses task_spawn(); All argv types should be char * const * not const char ** git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5598 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/ChangeLog | 7 + nuttx/Documentation/NuttxUserGuide.html | 228 +++++++++++- nuttx/TODO | 30 +- nuttx/binfmt/binfmt_exec.c | 2 +- nuttx/configs/cloudctrl/src/up_usb.c | 2 +- nuttx/configs/olimex-lpc1766stk/src/up_nsh.c | 4 +- nuttx/configs/pic32-starterkit/src/up_nsh.c | 4 +- nuttx/configs/pic32mx7mmb/src/up_nsh.c | 4 +- nuttx/configs/shenzhou/src/up_usb.c | 2 +- nuttx/configs/sim/nsh/defconfig | 2 +- nuttx/configs/stm3220g-eval/src/up_usb.c | 2 +- nuttx/configs/stm3240g-eval/src/up_usb.c | 2 +- .../configs/stm32f4discovery/posix_spawn/defconfig | 2 +- nuttx/configs/stm32f4discovery/src/up_usb.c | 2 +- nuttx/configs/sure-pic32mx/src/up_nsh.c | 4 +- nuttx/drivers/usbhost/usbhost_hidkbd.c | 4 +- nuttx/fs/fat/fs_configfat.c | 2 +- nuttx/include/nuttx/binfmt/binfmt.h | 4 +- nuttx/include/sched.h | 8 +- nuttx/include/spawn.h | 40 +- nuttx/libc/Kconfig | 23 +- nuttx/libc/spawn/Make.defs | 5 +- nuttx/libc/spawn/lib_psa_getschedparam.c | 2 +- nuttx/libc/spawn/lib_psa_getstacksize.c | 74 ++++ nuttx/libc/spawn/lib_psa_init.c | 26 +- nuttx/libc/spawn/lib_psa_setstacksize.c | 73 ++++ nuttx/libc/spawn/lib_psfa_dump.c | 5 +- nuttx/libc/unistd/lib_execv.c | 4 +- nuttx/sched/Makefile | 2 + nuttx/sched/os_bringup.c | 8 +- nuttx/sched/os_internal.h | 6 +- nuttx/sched/sched_waitid.c | 4 +- nuttx/sched/sched_waitpid.c | 4 +- nuttx/sched/spawn_internal.h | 158 ++++++++ nuttx/sched/task_create.c | 12 +- nuttx/sched/task_init.c | 4 +- nuttx/sched/task_posixspawn.c | 302 ++------------- nuttx/sched/task_setup.c | 2 +- nuttx/sched/task_spawn.c | 411 +++++++++++++++++++++ nuttx/sched/task_spawnparms.c | 340 +++++++++++++++++ nuttx/syscall/syscall.csv | 4 +- 41 files changed, 1453 insertions(+), 371 deletions(-) create mode 100644 nuttx/libc/spawn/lib_psa_getstacksize.c create mode 100644 nuttx/libc/spawn/lib_psa_setstacksize.c create mode 100644 nuttx/sched/spawn_internal.h create mode 100644 nuttx/sched/task_spawn.c create mode 100644 nuttx/sched/task_spawnparms.c diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 5bdd1aad8..c3e16607f 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -4100,3 +4100,10 @@ * drivers/serial/serial.c: Correct some race conditions when checking for disconnection of a removable serial device. + * sched/task_posixspawn.c, task_spawn.c, task_spawnparms.c and + spawn_internal.h: Create new interface task_spawn() that is + like posix_spawn(), but uses entry point addresses like + task_create(). + * Corrected all argv[] arguments. Should be char * const *, not + const char **. + diff --git a/nuttx/Documentation/NuttxUserGuide.html b/nuttx/Documentation/NuttxUserGuide.html index 10e5eb7ba..2704196d0 100644 --- a/nuttx/Documentation/NuttxUserGuide.html +++ b/nuttx/Documentation/NuttxUserGuide.html @@ -13,7 +13,7 @@

NuttX Operating System

User's Manual

by

Gregory Nutt

-

Last Updated: January 23, 2013

+

Last Updated: February 2, 2013

@@ -221,7 +221,6 @@ paragraphs.

Standard posix_spawn interfaces:

- +

+ Non-standard task control interfaces inspired by posix_spawn: +

+

2.1.1 task_create

@@ -246,7 +253,7 @@ paragraphs. Function Prototype:

@@ -336,7 +343,7 @@ VxWorks provides the following similar interface:

    #include <sched.h>
    int task_init(_TCB *tcb, char *name, int priority, uint32_t *stack, uint32_t stack_size,
-                 maint_t entry, const char *argv[]);
+                 maint_t entry, char * const argv[]);
 

@@ -831,7 +838,7 @@ int posix_spawnp(FAR pid_t *pid, FAR const char *file,

Description: - The posix_spawn() and posix_spawnp() functions will create a new, child task, constructed from a regular executable file.

+ The posix_spawn() and posix_spawnp() functions will create a new, child task, constructed from a regular executable file.

Input Parameters: @@ -1403,6 +1410,206 @@ int posix_spawnattr_setsigmask(FAR posix_spawnattr_t *attr, FAR const sigset_t * On success, this function returns 0; on failure it will return an error number from <errno.h>

+

2.1.26 task_spawn

+

+ Function Prototype: +

+ +

+ Description: + The task_spawn() function will create a new, child task, where the entry point to the task is an address in memory. +

+

+ +

+ Returned Value: + task_spawn() will return zero on success. + Otherwise, an error number will be returned as the function return value to indicate the error: +

+

+ POSIX Compatibility: + This is a non-standard interface inspired by posix_spawn(). +

+ +

2.1.26 task_spawnattr_getstacksize

+

+ Function Prototype: +

+ +

+ Description: + The task_spawnattr_getstacksize() function will obtain the value of the spawn-stacksize attribute from the attributes object referenced by attr. +

+

+ Input Parameters: +

+ +

+ Returned Value: + On success, this function returns 0; on failure it will return an error number from <errno.h> +

+ +

2.1.26 task_spawnattr_setstacksize

+

+ Function Prototype: +

+ +

+ Description: + The task_spawnattr_setstacksize() function will set the spawn-stacksize attribute in an initialized attributes object referenced by attr. +

+

+ Input Parameters: +

+ +

+ Returned Value: + On success, this function returns 0; on failure it will return an error number from <errno.h> +

+ +

2.1.12 posix_spawn_file_actions_init

+

+ Function Prototype: +

+ +

+ Description: + The posix_spawn_file_actions_init() function initializes the object referenced by file_actions to an empty set of file actions for subsequent use in a call to posix_spawn() or posix_spawnp(). +

+

+ Input Parameters: +

+ +

+ Returned Value: + On success, this function returns 0; on failure it will return an error number from <errno.h>. +

+ - +
@@ -9277,9 +9484,9 @@ notify a task when a message is available on a queue.
  • poll
  • poll.h
  • posix_spawn
  • +
  • posix_spawn_file_actions_addclose
  • -
  • posix_spawn_file_actions_addclose
  • posix_spawn_file_actions_adddup2
  • posix_spawn_file_actions_addopen
  • posix_spawn_file_actions_destroy
  • @@ -9362,10 +9569,10 @@ notify a task when a message is available on a queue.
  • rename
  • rmdir
  • rewinddir
  • -
  • ROM disk driver
  • ROMFS
  • +
  • sched_getparam
  • sched_get_priority_max
  • sched_get_priority_min
  • @@ -9419,8 +9626,11 @@ notify a task when a message is available on a queue.
  • task_delete
  • task_init
  • task_restart
  • -
  • Task Control Interfaces
  • Task Scheduling Interfaces +
  • task_spawn
  • +
  • task_spawnattr_getstacksize
  • +
  • task_spawnattr_setstacksize
  • +
  • Task Switching Interfaces
  • telldir
  • timer_create
  • timer_delete
  • diff --git a/nuttx/TODO b/nuttx/TODO index b5958f397..a0f0aa1bb 100644 --- a/nuttx/TODO +++ b/nuttx/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated January 30, 2013) +NuttX TODO List (Last updated February 2, 2013) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -45,7 +45,7 @@ nuttx/ apps/ (5) Network Utilities (apps/netutils/) - (5) NuttShell (NSH) (apps/nshlib) + (4) NuttShell (NSH) (apps/nshlib) (1) System libraries apps/system (apps/system) (5) Other Applications & Tests (apps/examples/) @@ -2028,32 +2028,6 @@ o NuttShell (NSH) (apps/nshlib) Status: Open Priority: Low (enhancement) - Title: RE-DIRECTION OF BUILTIN APPLICATONS - Description: There is a problem with the re-direction of output form built-in - applications in NSH. When output is re-directed, exec_builtin() - spawns a tiny trampoline task that re-directs the output as - requested, starts the built-in task and then exit. - - The problem is that when exec_builtin() starts the trampoline task, - it receives and returns the pid of the trampoline task, and *not* - the pid of the desired builtin application. This bad pid is returned - to NSH and when NSH tries to use that pid in the waitpid() call, it - fails because the trampoline task no longer exists. - - The same tasking arrangement is used by the standard function - 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(). - - exec_builtin() should not use this internal interface, however, - since it resides in the application space. The suggested solution - is (1) move the exec_builtin() logic into nuttx/sched, (2) make it - a semi-standard interface renamed to task_spawn() and prototyped - in nuttx/include/sched.h, and then (2) use task_reparent to solve - the parental problem in the same way that posix_spawn does. - Status: Open - Priority: Medium - o System libraries apps/system (apps/system) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c index 4226b6cfc..c175de3b9 100644 --- a/nuttx/binfmt/binfmt_exec.c +++ b/nuttx/binfmt/binfmt_exec.c @@ -92,7 +92,7 @@ * ****************************************************************************/ -int exec(FAR const char *filename, FAR const char **argv, +int exec(FAR const char *filename, FAR char * const *argv, FAR const struct symtab_s *exports, int nexports) { #ifdef CONFIG_SCHED_ONEXIT diff --git a/nuttx/configs/cloudctrl/src/up_usb.c b/nuttx/configs/cloudctrl/src/up_usb.c index 2ee9822f5..a5560be85 100644 --- a/nuttx/configs/cloudctrl/src/up_usb.c +++ b/nuttx/configs/cloudctrl/src/up_usb.c @@ -195,7 +195,7 @@ int stm32_usbhost_initialize(void) pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)usbhost_waiter, (const char **)NULL); + (main_t)usbhost_waiter, (FAR char * const *)NULL); return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c b/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c index f201c8a1b..00c4be0b7 100644 --- a/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c +++ b/nuttx/configs/olimex-lpc1766stk/src/up_nsh.c @@ -287,10 +287,10 @@ static int nsh_usbhostinitialize(void) #ifndef CONFIG_CUSTOM_STACK pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #else pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #endif return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/pic32-starterkit/src/up_nsh.c b/nuttx/configs/pic32-starterkit/src/up_nsh.c index f0e745112..02e6a9376 100644 --- a/nuttx/configs/pic32-starterkit/src/up_nsh.c +++ b/nuttx/configs/pic32-starterkit/src/up_nsh.c @@ -310,10 +310,10 @@ static int nsh_usbhostinitialize(void) #ifndef CONFIG_CUSTOM_STACK pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #else pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #endif return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/pic32mx7mmb/src/up_nsh.c b/nuttx/configs/pic32mx7mmb/src/up_nsh.c index a1bfbeaa2..6feb7a2e1 100644 --- a/nuttx/configs/pic32mx7mmb/src/up_nsh.c +++ b/nuttx/configs/pic32mx7mmb/src/up_nsh.c @@ -318,10 +318,10 @@ static int nsh_usbhostinitialize(void) #ifndef CONFIG_CUSTOM_STACK pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #else pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #endif return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/shenzhou/src/up_usb.c b/nuttx/configs/shenzhou/src/up_usb.c index 1cf8a39a7..6c4d15d4b 100644 --- a/nuttx/configs/shenzhou/src/up_usb.c +++ b/nuttx/configs/shenzhou/src/up_usb.c @@ -194,7 +194,7 @@ int stm32_usbhost_initialize(void) pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)usbhost_waiter, (const char **)NULL); + (main_t)usbhost_waiter, (FAR char * const *)NULL); return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/sim/nsh/defconfig b/nuttx/configs/sim/nsh/defconfig index 6b0b8400a..61fe18a44 100644 --- a/nuttx/configs/sim/nsh/defconfig +++ b/nuttx/configs/sim/nsh/defconfig @@ -295,7 +295,7 @@ CONFIG_EOL_IS_EITHER_CRLF=y CONFIG_LIBC_EXECFUNCS=y CONFIG_EXECFUNCS_SYMTAB="g_symtab" CONFIG_EXECFUNCS_NSYMBOLS=0 -CONFIG_POSIX_SPAWN_STACKSIZE=1024 +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 # CONFIG_LIBC_STRERROR is not set # CONFIG_LIBC_PERROR_STDOUT is not set CONFIG_ARCH_LOWPUTC=y diff --git a/nuttx/configs/stm3220g-eval/src/up_usb.c b/nuttx/configs/stm3220g-eval/src/up_usb.c index 64fdda6f8..2ca9b31cb 100644 --- a/nuttx/configs/stm3220g-eval/src/up_usb.c +++ b/nuttx/configs/stm3220g-eval/src/up_usb.c @@ -194,7 +194,7 @@ int stm32_usbhost_initialize(void) pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)usbhost_waiter, (const char **)NULL); + (main_t)usbhost_waiter, (FAR char * const *)NULL); return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/stm3240g-eval/src/up_usb.c b/nuttx/configs/stm3240g-eval/src/up_usb.c index 294fd661e..bc315a527 100644 --- a/nuttx/configs/stm3240g-eval/src/up_usb.c +++ b/nuttx/configs/stm3240g-eval/src/up_usb.c @@ -194,7 +194,7 @@ int stm32_usbhost_initialize(void) pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)usbhost_waiter, (const char **)NULL); + (main_t)usbhost_waiter, (FAR char * const *)NULL); return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/stm32f4discovery/posix_spawn/defconfig b/nuttx/configs/stm32f4discovery/posix_spawn/defconfig index 97cf84ab4..b365f735d 100644 --- a/nuttx/configs/stm32f4discovery/posix_spawn/defconfig +++ b/nuttx/configs/stm32f4discovery/posix_spawn/defconfig @@ -442,7 +442,7 @@ CONFIG_EOL_IS_EITHER_CRLF=y CONFIG_LIBC_EXECFUNCS=y CONFIG_EXECFUNCS_SYMTAB="exports" CONFIG_EXECFUNCS_NSYMBOLS=10 -CONFIG_POSIX_SPAWN_STACKSIZE=1024 +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 # CONFIG_LIBC_STRERROR is not set # CONFIG_LIBC_PERROR_STDOUT is not set CONFIG_ARCH_LOWPUTC=y diff --git a/nuttx/configs/stm32f4discovery/src/up_usb.c b/nuttx/configs/stm32f4discovery/src/up_usb.c index 89fc96006..653dd9a88 100644 --- a/nuttx/configs/stm32f4discovery/src/up_usb.c +++ b/nuttx/configs/stm32f4discovery/src/up_usb.c @@ -194,7 +194,7 @@ int stm32_usbhost_initialize(void) pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)usbhost_waiter, (const char **)NULL); + (main_t)usbhost_waiter, (FAR char * const *)NULL); return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/configs/sure-pic32mx/src/up_nsh.c b/nuttx/configs/sure-pic32mx/src/up_nsh.c index 94ae10d21..548ade02b 100644 --- a/nuttx/configs/sure-pic32mx/src/up_nsh.c +++ b/nuttx/configs/sure-pic32mx/src/up_nsh.c @@ -289,10 +289,10 @@ static int nsh_usbhostinitialize(void) #ifndef CONFIG_CUSTOM_STACK pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #else pid = task_create("usbhost", CONFIG_USBHOST_DEFPRIO, - (main_t)nsh_waiter, (const char **)NULL); + (main_t)nsh_waiter, (FAR char * const *)NULL); #endif return pid < 0 ? -ENOEXEC : OK; } diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c index d6a9ceda3..403befd49 100644 --- a/nuttx/drivers/usbhost/usbhost_hidkbd.c +++ b/nuttx/drivers/usbhost/usbhost_hidkbd.c @@ -1570,10 +1570,10 @@ static inline int usbhost_devinit(FAR struct usbhost_state_s *priv) #ifndef CONFIG_CUSTOM_STACK priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO, CONFIG_HIDKBD_STACKSIZE, - (main_t)usbhost_kbdpoll, (const char **)NULL); + (main_t)usbhost_kbdpoll, (FAR char * const *)NULL); #else priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO, - (main_t)usbhost_kbdpoll, (const char **)NULL); + (main_t)usbhost_kbdpoll, (FAR char * const *)NULL); #endif if (priv->pollpid == ERROR) { diff --git a/nuttx/fs/fat/fs_configfat.c b/nuttx/fs/fat/fs_configfat.c index 04141ee2b..d0365b0e6 100644 --- a/nuttx/fs/fat/fs_configfat.c +++ b/nuttx/fs/fat/fs_configfat.c @@ -450,7 +450,7 @@ mkfatfs_tryfat12(FAR struct fat_format_s *fmt, FAR struct fat_var_s *var, * maxnclusters = nfatsects * sectorsize / 1.5 - 2 */ - maxnclusters = (config->fc_nfatsects >> (var->fv_sectshift + 1)) / 3; + maxnclusters = (config->fc_nfatsects << (var->fv_sectshift + 1)) / 3; if (maxnclusters > FAT_MAXCLUST12) { maxnclusters = FAT_MAXCLUST12; diff --git a/nuttx/include/nuttx/binfmt/binfmt.h b/nuttx/include/nuttx/binfmt/binfmt.h index 590d88402..a2e23e1e5 100644 --- a/nuttx/include/nuttx/binfmt/binfmt.h +++ b/nuttx/include/nuttx/binfmt/binfmt.h @@ -97,7 +97,7 @@ struct binary_s /* Information provided to the loader to load and bind a module */ FAR const char *filename; /* Full path to the binary to be loaded (See NOTE 1 above) */ - FAR const char **argv; /* Argument list */ + FAR char * const *argv; /* Argument list */ FAR const struct symtab_s *exports; /* Table of exported symbols */ int nexports; /* The number of symbols in exports[] */ @@ -290,7 +290,7 @@ int schedule_unload(pid_t pid, FAR struct binary_s *bin); * ****************************************************************************/ -int exec(FAR const char *filename, FAR const char **argv, +int exec(FAR const char *filename, FAR char * const *argv, FAR const struct symtab_s *exports, int nexports); /**************************************************************************** diff --git a/nuttx/include/sched.h b/nuttx/include/sched.h index 9ccbf57b2..804dd47cd 100644 --- a/nuttx/include/sched.h +++ b/nuttx/include/sched.h @@ -112,18 +112,18 @@ extern "C" #ifndef CONFIG_CUSTOM_STACK int task_init(FAR _TCB *tcb, const char *name, int priority, FAR uint32_t *stack, uint32_t stack_size, main_t entry, - FAR const char *argv[]); + FAR char * const argv[]); #else int task_init(FAR _TCB *tcb, const char *name, int priority, main_t entry, - FAR const char *argv[]); + FAR char * const argv[]); #endif int task_activate(FAR _TCB *tcb); #ifndef CONFIG_CUSTOM_STACK int task_create(FAR const char *name, int priority, int stack_size, main_t entry, - FAR const char *argv[]); + FAR char * const argv[]); #else int task_create(FAR const char *name, int priority, main_t entry, - FAR const char *argv[]); + FAR char * const argv[]); #endif int task_delete(pid_t pid); int task_restart(pid_t pid); diff --git a/nuttx/include/spawn.h b/nuttx/include/spawn.h index 5e0ce3416..e6096fdba 100644 --- a/nuttx/include/spawn.h +++ b/nuttx/include/spawn.h @@ -75,12 +75,18 @@ struct posix_spawnattr_s { - uint8_t flags; - uint8_t priority; - uint8_t policy; + /* Used by posix_spawn, posix_spawnp, and task_spawn */ + + uint8_t flags; /* See POSIX_SPAWN_ definitions */ + uint8_t priority; /* Task scheduling priority */ + uint8_t policy; /* Task scheduling policy */ #ifndef CONFIG_DISABLE_SIGNALS - sigset_t sigmask; + sigset_t sigmask; /* Signals to be masked */ #endif + + /* Used only by task_spawn (non-standard) */ + + size_t stacksize; /* Task stack size */ }; typedef struct posix_spawnattr_s posix_spawnattr_t; @@ -107,7 +113,10 @@ extern "C" { #endif -/* posix_spawn[p] interfaces ************************************************/ +/* Spawn interfaces *********************************************************/ +/* Standard posix_spawn[p] interfaces. These functions execute files in the + * file system at 'path' + */ #ifdef CONFIG_BINFMT_EXEPATH int posix_spawnp(FAR pid_t *pid, FAR const char *path, @@ -121,8 +130,20 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, FAR const posix_spawn_file_actions_t *file_actions, FAR const posix_spawnattr_t *attr, FAR char *const argv[], FAR char *const envp[]); +#define posix_spawnp(pid,path,file_actions,attr,argv,envp) \ + posix_spawn(pid,path,file_actions,attr,argv,envp) #endif +/* Non-standard task_spawn interface. This function uses the same + * semantics to execute a file in memory at 'entry', giving it the name + * 'name'. + */ + +int task_spawn(FAR pid_t *pid, FAR const char *name, main_t entry, + FAR const posix_spawn_file_actions_t *file_actions, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[], FAR char *const envp[]); + /* File action interfaces ***************************************************/ /* File action initialization and destruction */ @@ -181,6 +202,15 @@ int posix_spawnattr_setsigmask(FAR posix_spawnattr_t *attr, # define posix_spawnattr_setsigmask(attr,sigmask) (ENOSYS) #endif +/* Non-standard get/set spawn attributes interfaces for use only with + * task_spawn() + */ + +int task_spawnattr_getstacksize(FAR const posix_spawnattr_t *attr, + size_t *stacksize); +int task_spawnattr_setstacksize(FAR posix_spawnattr_t *attr, + size_t stacksize); + /* Non standard debug functions */ #ifdef CONFIG_DEBUG diff --git a/nuttx/libc/Kconfig b/nuttx/libc/Kconfig index 72a6a5346..3aee837c3 100644 --- a/nuttx/libc/Kconfig +++ b/nuttx/libc/Kconfig @@ -121,16 +121,25 @@ config EXECFUNCS_NSYMBOLS symbols in that table. This selection provides the number of symbols in the symbol table. -config POSIX_SPAWN_STACKSIZE - int "posix_spawn Stack Size" +endif + +config POSIX_SPAWN_PROXY_STACKSIZE + int "Spawn Stack Size" default 1024 ---help--- - If posix_spawn[p] uses I/O redirection options, then it will require - an intermediary/proxy task to muck with the file descriptors. This - configuration item specifies the stack size used for the proxy. Default: - 1024 bytes. + If posix_spawn[p]() and task_spawn() use I/O redirection options, + they will require an intermediary/proxy task to muck with the file + descriptors. This configuration item specifies the stack size + used for the proxy. Default: 1024 bytes. -endif +config TASK_SPAWN_DEFAULT_STACKSIZE + int "Default task_spawn Stack Size" + default 2048 + ---help--- + The actual size to use for the child task's stack can be set with + task_spawnattr_setstacksize(). This value specifies the default + stack size to use if task_spawnattr_setstacksize() is not used. + Default: 2048. config LIBC_STRERROR bool "Enable strerror" diff --git a/nuttx/libc/spawn/Make.defs b/nuttx/libc/spawn/Make.defs index 8cb086fee..edbcc4fbb 100644 --- a/nuttx/libc/spawn/Make.defs +++ b/nuttx/libc/spawn/Make.defs @@ -45,8 +45,9 @@ CSRCS += lib_psfa_dump.c endif CSRCS += lib_psa_getflags.c lib_psa_getschedparam.c lib_psa_getschedpolicy.c -CSRCS += lib_psa_init.c lib_psa_setflags.c lib_psa_setschedparam.c -CSRCS += lib_psa_setschedpolicy.c +CSRCS += lib_psa_getstacksize.c lib_psa_init.c lib_psa_setflags.c +CSRCS += lib_psa_setschedparam.c lib_psa_setschedpolicy.c +CSRCS += lib_psa_setstacksize.c ifneq ($(CONFIG_DISABLE_SIGNALS),y) CSRCS += lib_psa_getsigmask.c lib_psa_setsigmask.c diff --git a/nuttx/libc/spawn/lib_psa_getschedparam.c b/nuttx/libc/spawn/lib_psa_getschedparam.c index ed8cb1f70..51b2cb38e 100644 --- a/nuttx/libc/spawn/lib_psa_getschedparam.c +++ b/nuttx/libc/spawn/lib_psa_getschedparam.c @@ -57,7 +57,7 @@ * * Input Parameters: * attr - The address spawn attributes to be queried. - * flags - The location to return the spawn-schedparam value. + * param - The location to return the spawn-schedparam value. * * Returned Value: * On success, these functions return 0; on failure they return an error diff --git a/nuttx/libc/spawn/lib_psa_getstacksize.c b/nuttx/libc/spawn/lib_psa_getstacksize.c new file mode 100644 index 000000000..ab499f5de --- /dev/null +++ b/nuttx/libc/spawn/lib_psa_getstacksize.c @@ -0,0 +1,74 @@ +/**************************************************************************** + * libc/string/lib_psa_getstacksize.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_spawnattr_getstacksize + * + * Description: + * The task_spawnattr_getstacksize() function will obtain the value of + * the spawn-stacksize attribute from the attributes object referenced + * by attr. + * + * Input Parameters: + * attr - The address spawn attributes to be queried. + * stacksize - The location to return the spawn-stacksize value. + * + * Returned Value: + * On success, these functions return 0; on failure they return an error + * number from . + * + ****************************************************************************/ + +int task_spawnattr_getstacksize(FAR const posix_spawnattr_t *attr, + size_t *stacksize) +{ + DEBUGASSERT(attr && stacksize); + *stacksize = attr->stacksize; + return OK; +} diff --git a/nuttx/libc/spawn/lib_psa_init.c b/nuttx/libc/spawn/lib_psa_init.c index f76188c52..c016cc6cd 100644 --- a/nuttx/libc/spawn/lib_psa_init.c +++ b/nuttx/libc/spawn/lib_psa_init.c @@ -45,7 +45,15 @@ #include /**************************************************************************** - * Global Functions + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef TASK_SPAWN_DEFAULT_STACKSIZE +# define TASK_SPAWN_DEFAULT_STACKSIZE 2048 +#endif + +/**************************************************************************** + * Public Functions ****************************************************************************/ /**************************************************************************** @@ -76,10 +84,6 @@ int posix_spawnattr_init(posix_spawnattr_t *attr) attr->flags = 0; - /* Set the default scheduler policy to the policy of this task */ - - attr->policy = sched_getscheduler(0); - /* Set the default priority to the same priority as this task */ ret = sched_getparam(0, ¶m); @@ -89,5 +93,17 @@ int posix_spawnattr_init(posix_spawnattr_t *attr) } attr->priority = param.sched_priority; + + /* Set the default scheduler policy to the policy of this task */ + + attr->policy = sched_getscheduler(0); + + /* Empty signal masek */ + + attr->sigmask = 0; + + /* Default stack size */ + + attr->stacksize = TASK_SPAWN_DEFAULT_STACKSIZE; return OK; } diff --git a/nuttx/libc/spawn/lib_psa_setstacksize.c b/nuttx/libc/spawn/lib_psa_setstacksize.c new file mode 100644 index 000000000..d49a1d611 --- /dev/null +++ b/nuttx/libc/spawn/lib_psa_setstacksize.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * libc/string/lib_psa_setstacksize.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_spawnattr_setstacksize + * + * Description: + * The task_spawnattr_setstacksize() function shall set the spawn- + * stacksize attribute in an initialized attributes object referenced + * by attr. + * + * Input Parameters: + * attr - The address spawn attributes to be used. + * stacksize - The new stacksize to set. + * + * Returned Value: + * On success, these functions return 0; on failure they return an error + * number from . + * + ****************************************************************************/ + +int task_spawnattr_setstacksize(FAR posix_spawnattr_t *attr, size_t stacksize) +{ + DEBUGASSERT(attr); + attr->stacksize = stacksize; + return OK; +} diff --git a/nuttx/libc/spawn/lib_psfa_dump.c b/nuttx/libc/spawn/lib_psfa_dump.c index 0dbaeb023..f71f2701e 100644 --- a/nuttx/libc/spawn/lib_psfa_dump.c +++ b/nuttx/libc/spawn/lib_psfa_dump.c @@ -56,7 +56,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: lib_psfa_dump + * Name: posix_spawn_file_actions_dump * * Description: * Show the entryent file actions. @@ -126,4 +126,5 @@ void posix_spawn_file_actions_dump(FAR posix_spawn_file_actions_t *file_actions) } } -#endif /* CONFIG_DEBUG */ \ No newline at end of file +#endif /* CONFIG_DEBUG */ + diff --git a/nuttx/libc/unistd/lib_execv.c b/nuttx/libc/unistd/lib_execv.c index 48b089913..64346c9db 100644 --- a/nuttx/libc/unistd/lib_execv.c +++ b/nuttx/libc/unistd/lib_execv.c @@ -117,7 +117,7 @@ * ****************************************************************************/ -int execv(FAR const char *path, FAR char *const argv[]) +int execv(FAR const char *path, FAR char * const argv[]) { FAR const struct symtab_s *symtab; int nsymbols; @@ -129,7 +129,7 @@ int execv(FAR const char *path, FAR char *const argv[]) /* Start the task */ - ret = exec(path, (FAR const char **)argv, symtab, nsymbols); + ret = exec(path, (FAR char * const *)argv, symtab, nsymbols); if (ret < 0) { sdbg("exec failed: %d\n", errno); diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile index 961560176..0b0173306 100644 --- a/nuttx/sched/Makefile +++ b/nuttx/sched/Makefile @@ -48,6 +48,8 @@ TSK_SRCS += sched_removereadytorun.c sched_addprioritized.c sched_mergepending.c TSK_SRCS += sched_addblocked.c sched_removeblocked.c sched_free.c sched_gettcb.c TSK_SRCS += sched_verifytcb.c sched_releasetcb.c +TSK_SRCS += task_spawn.c task_spawnparms.c + ifneq ($(CONFIG_BINFMT_DISABLE),y) ifeq ($(CONFIG_LIBC_EXECFUNCS),y) TSK_SRCS += task_posixspawn.c diff --git a/nuttx/sched/os_bringup.c b/nuttx/sched/os_bringup.c index 610d8515a..85cb5e627 100644 --- a/nuttx/sched/os_bringup.c +++ b/nuttx/sched/os_bringup.c @@ -141,7 +141,7 @@ int os_bringup(void) g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO, CONFIG_PAGING_STACKSIZE, - (main_t)pg_worker, (const char **)NULL); + (main_t)pg_worker, (FAR char * const *)NULL); ASSERT(g_pgworker != ERROR); #endif @@ -154,7 +154,7 @@ int os_bringup(void) g_work[HPWORK].pid = KERNEL_THREAD("work0", CONFIG_SCHED_WORKPRIORITY, CONFIG_SCHED_WORKSTACKSIZE, - (main_t)work_hpthread, (const char **)NULL); + (main_t)work_hpthread, (FAR char * const *)NULL); ASSERT(g_work[HPWORK].pid != ERROR); /* Start a lower priority worker thread for other, non-critical continuation @@ -166,7 +166,7 @@ int os_bringup(void) g_work[LPWORK].pid = KERNEL_THREAD("work1", CONFIG_SCHED_LPWORKPRIORITY, CONFIG_SCHED_LPWORKSTACKSIZE, - (main_t)work_lpthread, (const char **)NULL); + (main_t)work_lpthread, (FAR char * const *)NULL); ASSERT(g_work[LPWORK].pid != ERROR); #endif #endif @@ -182,7 +182,7 @@ int os_bringup(void) init_taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT, CONFIG_USERMAIN_STACKSIZE, - (main_t)CONFIG_USER_ENTRYPOINT, (const char **)NULL); + (main_t)CONFIG_USER_ENTRYPOINT, (FAR char * const *)NULL); ASSERT(init_taskid != ERROR); /* We an save a few bytes by discarding the IDLE thread's environment. */ diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h index 262a40ccc..73bff3422 100644 --- a/nuttx/sched/os_internal.h +++ b/nuttx/sched/os_internal.h @@ -259,16 +259,16 @@ void weak_function task_initialize(void); void task_start(void); int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main, uint8_t ttype); -int task_argsetup(FAR _TCB *tcb, FAR const char *name, FAR const char *argv[]); +int task_argsetup(FAR _TCB *tcb, FAR const char *name, FAR char * const argv[]); void task_exithook(FAR _TCB *tcb, int status); int task_deletecurrent(void); #ifndef CONFIG_CUSTOM_STACK int kernel_thread(FAR const char *name, int priority, int stack_size, - main_t entry, FAR const char *argv[]); + main_t entry, FAR char * const argv[]); #else int kernel_thread(FAR const char *name, int priority, main_t entry, - FAR const char *argv[]); + FAR char * const argv[]); #endif bool sched_addreadytorun(FAR _TCB *rtrtcb); bool sched_removereadytorun(FAR _TCB *rtrtcb); diff --git a/nuttx/sched/sched_waitid.c b/nuttx/sched/sched_waitid.c index 9c24189c4..26804f344 100644 --- a/nuttx/sched/sched_waitid.c +++ b/nuttx/sched/sched_waitid.c @@ -342,10 +342,10 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options) { /* We know that the child task was running okay we stared, * so we must have lost the signal. What can we do? - * Let's claim we were interrupted by a signal. + * Let's return ECHILD.. that is at least informative. */ - err = EINTR; + err = ECHILD; goto errout_with_errno; } #endif diff --git a/nuttx/sched/sched_waitpid.c b/nuttx/sched/sched_waitpid.c index 0285c2673..e44ef6e21 100644 --- a/nuttx/sched/sched_waitpid.c +++ b/nuttx/sched/sched_waitpid.c @@ -461,10 +461,10 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options) { /* We know that the child task was running okay we stared, * so we must have lost the signal. What can we do? - * Let's claim we were interrupted by a signal. + * Let's return ECHILD.. that is at least informative. */ - err = EINTR; + err = ECHILD; goto errout_with_errno; } #endif diff --git a/nuttx/sched/spawn_internal.h b/nuttx/sched/spawn_internal.h new file mode 100644 index 000000000..6520f3947 --- /dev/null +++ b/nuttx/sched/spawn_internal.h @@ -0,0 +1,158 @@ +/**************************************************************************** + * sched/spawn_internal.h + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __SCHED_SPAWN_INERNAL_H +#define __SCHED_SPAWN_INERNAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct spawn_parms_s +{ + /* Common parameters */ + + int result; + FAR pid_t *pid; + FAR const posix_spawn_file_actions_t *file_actions; + FAR const posix_spawnattr_t *attr; + FAR char * const *argv; + + /* Parameters that differ for posix_spawn[p] and task_spawn */ + + union + { + struct + { + FAR const char *path; + } posix; + struct + { + FAR const char *name; + main_t entry; + } task; + } u; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern sem_t g_spawn_parmsem; +#ifndef CONFIG_SCHED_WAITPID +extern sem_t g_spawn_execsem; +#endif +extern struct spawn_parms_s g_spawn_parms; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_semtake and spawn_semgive + * + * Description: + * Give and take semaphores + * + * Input Parameters: + * + * sem - The semaphore to act on. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spawn_semtake(FAR sem_t *sem); +#define spawn_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: spawn_execattrs + * + * Description: + * Set attributes of the new child task after it has been spawned. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * + * Returned Value: + * Errors are not reported by this function. This is because errors + * cannot occur, but ratther that the new task has already been started + * so there is no graceful way to handle errors detected in this context + * (unless we delete the new task and recover). + * + * Assumptions: + * That task has been started but has not yet executed because pre- + * emption is disabled. + * + ****************************************************************************/ + +int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr); + +/**************************************************************************** + * Name: spawn_proxyattrs + * + * Description: + * Set attributes of the proxy task before it has started the new child + * task. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * file_actions - The attributes to use + * + * Returned Value: + * 0 (OK) on successed; A negated errno value is returned on failure. + * + ****************************************************************************/ + +int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, + FAR const posix_spawn_file_actions_t *file_actions); + +#endif /* __SCHED_SPAWN_INERNAL_H */ diff --git a/nuttx/sched/task_create.c b/nuttx/sched/task_create.c index 944743200..bcb9c77c0 100644 --- a/nuttx/sched/task_create.c +++ b/nuttx/sched/task_create.c @@ -100,10 +100,10 @@ #ifndef CONFIG_CUSTOM_STACK static int thread_create(const char *name, uint8_t ttype, int priority, - int stack_size, main_t entry, const char **argv) + int stack_size, main_t entry, FAR char * const argv[]) #else static int thread_create(const char *name, uint8_t ttype, int priority, - main_t entry, const char **argv) + main_t entry, FAR char * const argv[]) #endif { FAR _TCB *tcb; @@ -244,10 +244,10 @@ errout: #ifndef CONFIG_CUSTOM_STACK int task_create(const char *name, int priority, - int stack_size, main_t entry, const char *argv[]) + int stack_size, main_t entry, FAR char * const argv[]) #else int task_create(const char *name, int priority, - main_t entry, const char *argv[]) + main_t entry, FAR char * const argv[]) #endif { #ifndef CONFIG_CUSTOM_STACK @@ -275,10 +275,10 @@ int task_create(const char *name, int priority, #ifndef CONFIG_CUSTOM_STACK int kernel_thread(const char *name, int priority, - int stack_size, main_t entry, const char *argv[]) + int stack_size, main_t entry, FAR char * const argv[]) #else int kernel_thread(const char *name, int priority, - main_t entry, const char *argv[]) + main_t entry, FAR char * const argv[]) #endif { #ifndef CONFIG_CUSTOM_STACK diff --git a/nuttx/sched/task_init.c b/nuttx/sched/task_init.c index 78f35bc2a..4214393e1 100644 --- a/nuttx/sched/task_init.c +++ b/nuttx/sched/task_init.c @@ -114,10 +114,10 @@ #ifndef CONFIG_CUSTOM_STACK int task_init(FAR _TCB *tcb, const char *name, int priority, FAR uint32_t *stack, uint32_t stack_size, - main_t entry, const char *argv[]) + main_t entry, FAR char * const argv[]) #else int task_init(FAR _TCB *tcb, const char *name, int priority, - main_t entry, const char *argv[]) + main_t entry, FAR char * const argv[]) #endif { int errcode; diff --git a/nuttx/sched/task_posixspawn.c b/nuttx/sched/task_posixspawn.c index e9ad1fc45..f26391500 100644 --- a/nuttx/sched/task_posixspawn.c +++ b/nuttx/sched/task_posixspawn.c @@ -40,36 +40,19 @@ #include #include -#include -#include -#include -#include -#include #include -#include -#include #include #include -#include #include "os_internal.h" #include "group_internal.h" +#include "spawn_internal.h" /**************************************************************************** * Private Types ****************************************************************************/ -struct spawn_parms_s -{ - int result; - FAR pid_t *pid; - FAR const char *path; - FAR const posix_spawn_file_actions_t *file_actions; - FAR const posix_spawnattr_t *attr; - FAR char *const *argv; -}; - /**************************************************************************** * Public Data ****************************************************************************/ @@ -78,47 +61,12 @@ struct spawn_parms_s * Private Data ****************************************************************************/ -static sem_t g_ps_parmsem = SEM_INITIALIZER(1); -#ifndef CONFIG_SCHED_WAITPID -static sem_t g_ps_execsem = SEM_INITIALIZER(0); -#endif -static struct spawn_parms_s g_ps_parms; - /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: spawn_semtake and spawn_semgive - * - * Description: - * Give and take semaphores - * - * Input Parameters: - * - * sem - The semaphore to act on. - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void spawn_semtake(FAR sem_t *sem) -{ - int ret; - - do - { - ret = sem_wait(sem); - ASSERT(ret == 0 || errno == EINTR); - } - while (ret != 0); -} - -#define spawn_semgive(sem) sem_post(sem) - -/**************************************************************************** - * Name: spawn_exec + * Name: posix_spawn_exec * * Description: * Execute the task from the file system. @@ -156,11 +104,10 @@ static void spawn_semtake(FAR sem_t *sem) * ****************************************************************************/ -static int spawn_exec(FAR pid_t *pidp, FAR const char *path, - FAR const posix_spawnattr_t *attr, - FAR char *const argv[]) +static int posix_spawn_exec(FAR pid_t *pidp, FAR const char *path, + FAR const posix_spawnattr_t *attr, + FAR char * const argv[]) { - struct sched_param param; FAR const struct symtab_s *symtab; int nsymbols; int pid; @@ -181,7 +128,7 @@ static int spawn_exec(FAR pid_t *pidp, FAR const char *path, /* Start the task */ - pid = exec(path, (FAR const char **)argv, symtab, nsymbols); + pid = exec(path, (FAR char * const *)argv, symtab, nsymbols); if (pid < 0) { ret = errno; @@ -203,50 +150,7 @@ static int spawn_exec(FAR pid_t *pidp, FAR const char *path, if (attr) { - /* If we are only setting the priority, then call sched_setparm() - * to set the priority of the of the new task. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) - { - /* Get the priority from the attrributes */ - - param.sched_priority = attr->priority; - - /* If we are setting *both* the priority and the scheduler, - * then we will call sched_setscheduler() below. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) == 0) - { - svdbg("Setting priority=%d for pid=%d\n", - param.sched_priority, pid); - - (void)sched_setparam(pid, ¶m); - } - } - - /* If we are only changing the scheduling policy, then reset - * the priority to the default value (the same as this thread) in - * preparation for the sched_setscheduler() call below. - */ - - else if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) - { - (void)sched_getparam(0, ¶m); - } - - /* Are we setting the scheduling policy? If so, use the priority - * setting determined above. - */ - - if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) - { - svdbg("Setting policy=%d priority=%d for pid=%d\n", - attr->policy, param.sched_priority, pid); - - (void)sched_setscheduler(pid, attr->policy, ¶m); - } + (void)spawn_execattrs(pid, attr); } /* Re-enable pre-emption and return */ @@ -257,94 +161,7 @@ errout: } /**************************************************************************** - * Name: spawn_close, spawn_dup2, and spawn_open - * - * Description: - * Implement individual file actions - * - * Input Parameters: - * action - describes the action to be performed - * - * Returned Value: - * posix_spawn() and posix_spawnp() will return zero on success. - * Otherwise, an error number will be returned as the function return - * value to indicate the error. - * - ****************************************************************************/ - -static inline int spawn_close(FAR struct spawn_close_file_action_s *action) -{ - /* The return value from close() is ignored */ - - svdbg("Closing fd=%d\n", action->fd); - - (void)close(action->fd); - return OK; -} - -static inline int spawn_dup2(FAR struct spawn_dup2_file_action_s *action) -{ - int ret; - - /* Perform the dup */ - - svdbg("Dup'ing %d->%d\n", action->fd1, action->fd2); - - ret = dup2(action->fd1, action->fd2); - if (ret < 0) - { - int errcode = errno; - - sdbg("ERROR: dup2 failed: %d\n", errcode); - return errcode; - } - - return OK; -} - -static inline int spawn_open(FAR struct spawn_open_file_action_s *action) -{ - int fd; - int ret = OK; - - /* Open the file */ - - svdbg("Open'ing path=%s oflags=%04x mode=%04x\n", - action->path, action->oflags, action->mode); - - fd = open(action->path, action->oflags, action->mode); - if (fd < 0) - { - ret = errno; - sdbg("ERROR: open failed: %d\n", ret); - } - - /* Does the return file descriptor happen to match the required file - * desciptor number? - */ - - else if (fd != action->fd) - { - /* No.. dup2 to get the correct file number */ - - svdbg("Dup'ing %d->%d\n", fd, action->fd); - - ret = dup2(fd, action->fd); - if (ret < 0) - { - ret = errno; - sdbg("ERROR: dup2 failed: %d\n", ret); - } - - svdbg("Closing fd=%d\n", fd); - close(fd); - } - - return ret; -} - -/**************************************************************************** - * Name: spawn_proxy + * Name: posix_spawn_proxy * * Description: * Perform file_actions, then execute the task from the file system. @@ -357,11 +174,9 @@ static inline int spawn_open(FAR struct spawn_open_file_action_s *action) * ****************************************************************************/ -static int spawn_proxy(int argc, char *argv[]) +static int posix_spawn_proxy(int argc, FAR char *argv[]) { - FAR struct spawn_general_file_action_s *entry; - FAR const posix_spawnattr_t *attr = g_ps_parms.attr; - int ret = OK; + int ret; /* Perform file actions and/or set a custom signal mask. We get here only * if the file_actions parameter to posix_spawn[p] was non-NULL and/or the @@ -369,62 +184,22 @@ static int spawn_proxy(int argc, char *argv[]) */ #ifndef CONFIG_DISABLE_SIGNALS - DEBUGASSERT((g_ps_parms.file_actions && *g_ps_parms.file_actions) || - (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); + DEBUGASSERT(g_spawn_parms.file_actions || + (g_spawn_parms.attr && + (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); #else - DEBUGASSERT(g_ps_parms.file_actions && *g_ps_parms.file_actions); + DEBUGASSERT(g_spawn_parms.file_actions); #endif - /* Check if we need to change the signal mask */ - -#ifndef CONFIG_DISABLE_SIGNALS - if (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0) - { - (void)sigprocmask(SIG_SETMASK, &attr->sigmask, NULL); - } - - /* Were we also requested to perform file actions? */ - - if (g_ps_parms.file_actions) -#endif - { - /* Execute each file action */ - - for (entry = (FAR struct spawn_general_file_action_s *)*g_ps_parms.file_actions; - entry && ret == OK; - entry = entry->flink) - { - switch (entry->action) - { - case SPAWN_FILE_ACTION_CLOSE: - ret = spawn_close((FAR struct spawn_close_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_DUP2: - ret = spawn_dup2((FAR struct spawn_dup2_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_OPEN: - ret = spawn_open((FAR struct spawn_open_file_action_s *)entry); - break; - - case SPAWN_FILE_ACTION_NONE: - default: - sdbg("ERROR: Unknown action: %d\n", entry->action); - ret = EINVAL; - break; - } - } - } - - /* Check for failures */ + /* Set the attributes and perform the file actions as appropriate */ + ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); if (ret == OK) { /* Start the task */ - ret = spawn_exec(g_ps_parms.pid, g_ps_parms.path, attr, - g_ps_parms.argv); + ret = posix_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.posix.path, + g_spawn_parms.attr, g_spawn_parms.argv); #ifdef CONFIG_SCHED_HAVE_PARENT if (ret == OK) @@ -433,7 +208,7 @@ static int spawn_proxy(int argc, char *argv[]) * What should we do in the event of a failure? */ - int tmp = task_reparent(0, *g_ps_parms.pid); + int tmp = task_reparent(0, *g_spawn_parms.pid); if (tmp < 0) { sdbg("ERROR: task_reparent() failed: %d\n", tmp); @@ -446,9 +221,9 @@ static int spawn_proxy(int argc, char *argv[]) * what we need to do. */ - g_ps_parms.result = ret; + g_spawn_parms.result = ret; #ifndef CONFIG_SCHED_WAITPID - spawn_semgive(&g_ps_execsem); + spawn_semgive(&g_posix_spawn_execsem); #endif return OK; } @@ -585,7 +360,7 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, if (file_actions == NULL || *file_actions == NULL) #endif { - return spawn_exec(pid, path, attr, argv); + return posix_spawn_exec(pid, path, attr, argv); } /* Otherwise, we will have to go through an intermediary/proxy task in order @@ -601,16 +376,16 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, /* Get exclusive access to the global parameter structure */ - spawn_semtake(&g_ps_parmsem); + spawn_semtake(&g_spawn_parmsem); /* Populate the parameter structure */ - g_ps_parms.result = ENOSYS; - g_ps_parms.pid = pid; - g_ps_parms.path = path; - g_ps_parms.file_actions = file_actions; - g_ps_parms.attr = attr; - g_ps_parms.argv = argv; + g_spawn_parms.result = ENOSYS; + g_spawn_parms.pid = pid; + g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; + g_spawn_parms.attr = attr; + g_spawn_parms.argv = argv; + g_spawn_parms.u.posix.path = path; /* Get the priority of this (parent) task */ @@ -620,12 +395,12 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, int errcode = errno; sdbg("ERROR: sched_getparam failed: %d\n", errcode); - spawn_semgive(&g_ps_parmsem); + spawn_semgive(&g_spawn_parmsem); return errcode; } /* Disable pre-emption so that the proxy does not run until we waitpid - * is called. This is probably unnecessary since the spawn_proxy has + * is called. This is probably unnecessary since the posix_spawn_proxy has * the same priority as this thread; it should be schedule behind this * task in the ready-to-run list. */ @@ -638,13 +413,14 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, * task. */ - proxy = TASK_CREATE("spawn_proxy", param.sched_priority, - CONFIG_POSIX_SPAWN_STACKSIZE, (main_t)spawn_proxy, - (FAR const char **)NULL); + proxy = TASK_CREATE("posix_spawn_proxy", param.sched_priority, + CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, + (main_t)posix_spawn_proxy, + (FAR char * const *)NULL); if (proxy < 0) { ret = get_errno(); - sdbg("ERROR: Failed to start spawn_proxy: %d\n", ret); + sdbg("ERROR: Failed to start posix_spawn_proxy: %d\n", ret); goto errout_with_lock; } @@ -659,17 +435,17 @@ int posix_spawn(FAR pid_t *pid, FAR const char *path, goto errout_with_lock; } #else - spawn_semtake(&g_ps_execsem); + spawn_semtake(&g_posix_spawn_execsem); #endif /* Get the result and relinquish our access to the parameter structure */ - ret = g_ps_parms.result; + ret = g_spawn_parms.result; errout_with_lock: #ifdef CONFIG_SCHED_WAITPID sched_unlock(); #endif - spawn_semgive(&g_ps_parmsem); + spawn_semgive(&g_spawn_parmsem); return ret; } diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c index b770d46e6..649e97184 100644 --- a/nuttx/sched/task_setup.c +++ b/nuttx/sched/task_setup.c @@ -414,7 +414,7 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main, * ****************************************************************************/ -int task_argsetup(FAR _TCB *tcb, const char *name, const char *argv[]) +int task_argsetup(FAR _TCB *tcb, const char *name, FAR char * const argv[]) { int i; diff --git a/nuttx/sched/task_spawn.c b/nuttx/sched/task_spawn.c new file mode 100644 index 000000000..04a3944bf --- /dev/null +++ b/nuttx/sched/task_spawn.c @@ -0,0 +1,411 @@ +/**************************************************************************** + * sched/task_spawn.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "os_internal.h" +#include "group_internal.h" +#include "spawn_internal.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_spawn_exec + * + * Description: + * Execute the task from the file system. + * + * Input Parameters: + * + * pidp - Upon successful completion, this will return the task ID of the + * child task in the variable pointed to by a non-NULL 'pid' argument.| + * + * path - The 'path' argument identifies the file to execute. If + * CONFIG_BINFMT_EXEPATH is defined, this may be either a relative or + * or an absolute path. Otherwise, it must be an absolute path. + * + * attr - If the value of the 'attr' parameter is NULL, the all default + * values for the POSIX spawn attributes will be used. Otherwise, the + * attributes will be set according to the spawn flags. The + * following spawn flags are supported: + * + * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param + * value. + * - POSIX_SPAWN_SETSCHEDULER: Set the new tasks scheduler priority to + * the sched_policy value. + * + * NOTE: POSIX_SPAWN_SETSIGMASK is handled in ps_proxy(). + * + * argv - argv[] is the argument list for the new task. argv[] is an + * array of pointers to null-terminated strings. The list is terminated + * with a null pointer. + * + * Returned Value: + * This function will return zero on success. Otherwise, an error number + * will be returned as the function return value to indicate the error. + * This errno value may be that set by execv(), sched_setpolicy(), or + * sched_setparam(). + * + ****************************************************************************/ + +static int task_spawn_exec(FAR pid_t *pidp, FAR const char *name, + main_t entry, FAR const posix_spawnattr_t *attr, + FAR char * const *argv) +{ + int pid; + int ret = OK; + + DEBUGASSERT(path); + + /* Disable pre-emption so that we can modify the task parameters after + * we start the new task; the new task will not actually begin execution + * until we re-enable pre-emption. + */ + + sched_lock(); + + /* Start the task */ + + pid = TASK_CREATE(name, attr->priority, attr->stacksize, entry, argv); + if (pid < 0) + { + ret = errno; + sdbg("ERROR: TASK_CREATE failed: %d\n", ret); + goto errout; + } + + /* Return the task ID to the caller */ + + if (pid) + { + *pidp = pid; + } + + /* Now set the attributes. Note that we ignore all of the return values + * here because we have already successfully started the task. If we + * return an error value, then we would also have to stop the task. + */ + + if (attr) + { + (void)spawn_execattrs(pid, attr); + } + + /* Re-enable pre-emption and return */ + +errout: + sched_unlock(); + return ret; +} + +/**************************************************************************** + * Name: task_spawn_proxy + * + * Description: + * Perform file_actions, then execute the task from the file system. + * + * Input Parameters: + * Standard task start-up parameters + * + * Returned Value: + * Standard task return value. + * + ****************************************************************************/ + +static int task_spawn_proxy(int argc, FAR char *argv[]) +{ + int ret; + + /* Perform file actions and/or set a custom signal mask. We get here only + * if the file_actions parameter to task_spawn[p] was non-NULL and/or the + * option to change the signal mask was selected. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + DEBUGASSERT(g_spawn_parms.file_actions || + (g_spawn_parms.attr && + (g_spawn_parms.attr->flags & POSIX_SPAWN_SETSIGMASK) != 0)); +#else + DEBUGASSERT(g_spawn_parms.file_actions); +#endif + + /* Set the attributes and perform the file actions as appropriate */ + + ret = spawn_proxyattrs(g_spawn_parms.attr, g_spawn_parms.file_actions); + if (ret == OK) + { + /* Start the task */ + + ret = task_spawn_exec(g_spawn_parms.pid, g_spawn_parms.u.task.name, + g_spawn_parms.u.task.entry, g_spawn_parms.attr, + g_spawn_parms.argv); + +#ifdef CONFIG_SCHED_HAVE_PARENT + if (ret == OK) + { + /* Change of the parent of the task we just spawned to our parent. + * What should we do in the event of a failure? + */ + + int tmp = task_reparent(0, *g_spawn_parms.pid); + if (tmp < 0) + { + sdbg("ERROR: task_reparent() failed: %d\n", tmp); + } + } +#endif + } + + /* Post the semaphore to inform the parent task that we have completed + * what we need to do. + */ + + g_spawn_parms.result = ret; +#ifndef CONFIG_SCHED_WAITPID + spawn_semgive(&g_task_spawn_execsem); +#endif + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_spawn + * + * Description: + * The task_spawn() function will create a new, child task, where the + * entry point to the task is an address in memory. + * + * Input Parameters: + * + * pid - Upon successful completion, task_spawn() will return the task ID + * of the child task to the parent task, in the variable pointed to by + * a non-NULL 'pid' argument. If the 'pid' argument is a null pointer, + * the process ID of the child is not returned to the caller. + * + * name - The name to assign to the child task. + * + * entry - The child task's entry point (an address in memory) + * + * file_actions - If 'file_actions' is a null pointer, then file + * descriptors open in the calling process will remain open in the + * child process (unless CONFIG_FDCLONE_STDIO is defined). If + * 'file_actions' is not NULL, then the file descriptors open in the + * child process will be those open in the calling process as modified + * by the spawn file actions object pointed to by file_actions. + * + * attr - If the value of the 'attr' parameter is NULL, the all default + * values for the POSIX spawn attributes will be used. Otherwise, the + * attributes will be set according to the spawn flags. The + * task_spawnattr_t spawn attributes object type is defined in spawn.h. + * It will contains these attributes, not all of which are supported by + * NuttX: + * + * - POSIX_SPAWN_SETPGROUP: Setting of the new task's process group is + * not supported. NuttX does not support process groups. + * - POSIX_SPAWN_SETSCHEDPARAM: Set new tasks priority to the sched_param + * value. + * - POSIX_SPAWN_SETSCHEDULER: Set the new task's scheduler policy to + * the sched_policy value. + * - POSIX_SPAWN_RESETIDS: Resetting of the effective user ID of the child + * process is not supported. NuttX does not support effective user + * IDs. + * - POSIX_SPAWN_SETSIGMASK: Set the new task's signal mask. + * - POSIX_SPAWN_SETSIGDEF: Resetting signal default actions is not + * supported. NuttX does not support default signal actions. + * + * And the non-standard: + * + * - TASK_SPAWN_SETSTACKSIZE: Set the stack size for the new task. + * + * argv - argv[] is the argument list for the new task. argv[] is an + * array of pointers to null-terminated strings. The list is terminated + * with a null pointer. + * + * envp - The envp[] argument is not used by NuttX and may be NULL. + * + * Returned Value: + * task_spawn() will return zero on success. Otherwise, an error number + * will be returned as the function return value to indicate the error: + * + * - EINVAL: The value specified by 'file_actions' or 'attr' is invalid. + * - Any errors that might have been return if vfork() and excec[l|v]() + * had been called. + * + ****************************************************************************/ + +int task_spawn(FAR pid_t *pid, FAR const char *name, main_t entry, + FAR const posix_spawn_file_actions_t *file_actions, + FAR const posix_spawnattr_t *attr, + FAR char *const argv[], FAR char *const envp[]) +{ + struct sched_param param; + pid_t proxy; +#ifdef CONFIG_SCHED_WAITPID + int status; +#endif + int ret; + + DEBUGASSERT(path); + + svdbg("pid=%p path=%s file_actions=%p attr=%p argv=%p\n", + pid, path, file_actions, attr, argv); + + /* If there are no file actions to be performed and there is no change to + * the signal mask, then start the new child task directly from the parent task. + */ + +#ifndef CONFIG_DISABLE_SIGNALS + if ((file_actions == NULL || *file_actions == NULL) && + (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0)) +#else + if (file_actions == NULL || *file_actions == NULL) +#endif + { + return task_spawn_exec(pid, name, entry, attr, argv); + } + + /* Otherwise, we will have to go through an intermediary/proxy task in order + * to perform the I/O redirection. This would be a natural place to fork(). + * However, true fork() behavior requires an MMU and most implementations + * of vfork() are not capable of these operations. + * + * Even without fork(), we can still do the job, but parameter passing is + * messier. Unfortunately, there is no (clean) way to pass binary values + * as a task parameter, so we will use a semaphore-protected global + * structure. + */ + + /* Get exclusive access to the global parameter structure */ + + spawn_semtake(&g_spawn_parmsem); + + /* Populate the parameter structure */ + + g_spawn_parms.result = ENOSYS; + g_spawn_parms.pid = pid; + g_spawn_parms.file_actions = file_actions ? *file_actions : NULL; + g_spawn_parms.attr = attr; + g_spawn_parms.argv = argv; + g_spawn_parms.u.task.name = name; + g_spawn_parms.u.task.entry = entry; + + /* Get the priority of this (parent) task */ + + ret = sched_getparam(0, ¶m); + if (ret < 0) + { + int errcode = errno; + + sdbg("ERROR: sched_getparam failed: %d\n", errcode); + spawn_semgive(&g_spawn_parmsem); + return errcode; + } + + /* Disable pre-emption so that the proxy does not run until we waitpid + * is called. This is probably unnecessary since the task_spawn_proxy has + * the same priority as this thread; it should be schedule behind this + * task in the ready-to-run list. + */ + +#ifdef CONFIG_SCHED_WAITPID + sched_lock(); +#endif + + /* Start the intermediary/proxy task at the same priority as the parent + * task. + */ + + proxy = TASK_CREATE("task_spawn_proxy", param.sched_priority, + CONFIG_POSIX_SPAWN_PROXY_STACKSIZE, + (main_t)task_spawn_proxy, + (FAR char * const*)NULL); + if (proxy < 0) + { + ret = get_errno(); + sdbg("ERROR: Failed to start task_spawn_proxy: %d\n", ret); + + goto errout_with_lock; + } + + /* Wait for the proxy to complete its job */ + +#ifdef CONFIG_SCHED_WAITPID + ret = waitpid(proxy, &status, 0); + if (ret < 0) + { + sdbg("ERROR: waitpid() failed: %d\n", errno); + goto errout_with_lock; + } +#else + spawn_semtake(&g_task_spawn_execsem); +#endif + + /* Get the result and relinquish our access to the parameter structure */ + + ret = g_spawn_parms.result; + +errout_with_lock: +#ifdef CONFIG_SCHED_WAITPID + sched_unlock(); +#endif + spawn_semgive(&g_spawn_parmsem); + return ret; +} diff --git a/nuttx/sched/task_spawnparms.c b/nuttx/sched/task_spawnparms.c new file mode 100644 index 000000000..25cb86531 --- /dev/null +++ b/nuttx/sched/task_spawnparms.c @@ -0,0 +1,340 @@ +/**************************************************************************** + * sched/task_spawnparms.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "spawn_internal.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +sem_t g_spawn_parmsem = SEM_INITIALIZER(1); +#ifndef CONFIG_SCHED_WAITPID +sem_t g_spawn_execsem = SEM_INITIALIZER(0); +#endif +struct spawn_parms_s g_spawn_parms; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_close, spawn_dup2, and spawn_open + * + * Description: + * Implement individual file actions + * + * Input Parameters: + * action - describes the action to be performed + * + * Returned Value: + * posix_spawn() and posix_spawnp() will return zero on success. + * Otherwise, an error number will be returned as the function return + * value to indicate the error. + * + ****************************************************************************/ + +static inline int spawn_close(FAR struct spawn_close_file_action_s *action) +{ + /* The return value from close() is ignored */ + + svdbg("Closing fd=%d\n", action->fd); + + (void)close(action->fd); + return OK; +} + +static inline int spawn_dup2(FAR struct spawn_dup2_file_action_s *action) +{ + int ret; + + /* Perform the dup */ + + svdbg("Dup'ing %d->%d\n", action->fd1, action->fd2); + + ret = dup2(action->fd1, action->fd2); + if (ret < 0) + { + int errcode = errno; + + sdbg("ERROR: dup2 failed: %d\n", errcode); + return errcode; + } + + return OK; +} + +static inline int spawn_open(FAR struct spawn_open_file_action_s *action) +{ + int fd; + int ret = OK; + + /* Open the file */ + + svdbg("Open'ing path=%s oflags=%04x mode=%04x\n", + action->path, action->oflags, action->mode); + + fd = open(action->path, action->oflags, action->mode); + if (fd < 0) + { + ret = errno; + sdbg("ERROR: open failed: %d\n", ret); + } + + /* Does the return file descriptor happen to match the required file + * desciptor number? + */ + + else if (fd != action->fd) + { + /* No.. dup2 to get the correct file number */ + + svdbg("Dup'ing %d->%d\n", fd, action->fd); + + ret = dup2(fd, action->fd); + if (ret < 0) + { + ret = errno; + sdbg("ERROR: dup2 failed: %d\n", ret); + } + + svdbg("Closing fd=%d\n", fd); + close(fd); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spawn_semtake and spawn_semgive + * + * Description: + * Give and take semaphores + * + * Input Parameters: + * + * sem - The semaphore to act on. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void spawn_semtake(FAR sem_t *sem) +{ + int ret; + + do + { + ret = sem_wait(sem); + ASSERT(ret == 0 || errno == EINTR); + } + while (ret != 0); +} + +/**************************************************************************** + * Name: spawn_execattrs + * + * Description: + * Set attributes of the new child task after it has been spawned. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * + * Returned Value: + * Errors are not reported by this function. This is because errors + * cannot occur, but ratther that the new task has already been started + * so there is no graceful way to handle errors detected in this context + * (unless we delete the new task and recover). + * + * Assumptions: + * That task has been started but has not yet executed because pre- + * emption is disabled. + * + ****************************************************************************/ + +int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr) +{ + struct sched_param param; + + DEBUGASSERT(attr); + + /* Now set the attributes. Note that we ignore all of the return values + * here because we have already successfully started the task. If we + * return an error value, then we would also have to stop the task. + */ + + /* If we are only setting the priority, then call sched_setparm() + * to set the priority of the of the new task. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDPARAM) != 0) + { + /* Get the priority from the attrributes */ + + param.sched_priority = attr->priority; + + /* If we are setting *both* the priority and the scheduler, + * then we will call sched_setscheduler() below. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) == 0) + { + svdbg("Setting priority=%d for pid=%d\n", + param.sched_priority, pid); + + (void)sched_setparam(pid, ¶m); + } + } + + /* If we are only changing the scheduling policy, then reset + * the priority to the default value (the same as this thread) in + * preparation for the sched_setscheduler() call below. + */ + + else if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) + { + (void)sched_getparam(0, ¶m); + } + + /* Are we setting the scheduling policy? If so, use the priority + * setting determined above. + */ + + if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0) + { + svdbg("Setting policy=%d priority=%d for pid=%d\n", + attr->policy, param.sched_priority, pid); + + (void)sched_setscheduler(pid, attr->policy, ¶m); + } + + return OK; +} + +/**************************************************************************** + * Name: spawn_proxyattrs + * + * Description: + * Set attributes of the proxy task before it has started the new child + * task. + * + * Input Parameters: + * + * pid - The pid of the new task. + * attr - The attributes to use + * file_actions - The attributes to use + * + * Returned Value: + * 0 (OK) on successed; A negated errno value is returned on failure. + * + ****************************************************************************/ + +int spawn_proxyattrs(FAR const posix_spawnattr_t *attr, + FAR const posix_spawn_file_actions_t *file_actions) +{ + FAR struct spawn_general_file_action_s *entry; + int ret = OK; + + /* Check if we need to change the signal mask */ + +#ifndef CONFIG_DISABLE_SIGNALS + if (attr && (attr->flags & POSIX_SPAWN_SETSIGMASK) != 0) + { + (void)sigprocmask(SIG_SETMASK, &attr->sigmask, NULL); + } + + /* Were we also requested to perform file actions? */ + + if (file_actions) +#endif + { + /* Yes.. Execute each file action */ + + for (entry = (FAR struct spawn_general_file_action_s *)file_actions; + entry && ret == OK; + entry = entry->flink) + { + switch (entry->action) + { + case SPAWN_FILE_ACTION_CLOSE: + ret = spawn_close((FAR struct spawn_close_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_DUP2: + ret = spawn_dup2((FAR struct spawn_dup2_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_OPEN: + ret = spawn_open((FAR struct spawn_open_file_action_s *)entry); + break; + + case SPAWN_FILE_ACTION_NONE: + default: + sdbg("ERROR: Unknown action: %d\n", entry->action); + ret = EINVAL; + break; + } + } + } + + return ret; +} diff --git a/nuttx/syscall/syscall.csv b/nuttx/syscall/syscall.csv index 5bc52a71d..2e1adb199 100644 --- a/nuttx/syscall/syscall.csv +++ b/nuttx/syscall/syscall.csv @@ -120,8 +120,8 @@ "stat","sys/stat.h","CONFIG_NFILE_DESCRIPTORS > 0","int","const char*","FAR struct stat*" #"statfs","stdio.h","","int","FAR const char*","FAR struct statfs*" "statfs","sys/statfs.h","CONFIG_NFILE_DESCRIPTORS > 0","int","const char*","struct statfs*" -"task_create","sched.h","","int","const char*","int","int","main_t","const char* []|const char**" -#"task_create","sched.h","","int","const char*","int","main_t","const char* []|const char**" +"task_create","sched.h","","int","const char*","int","int","main_t","FAR char * const []|FAR char * const *" +#"task_create","sched.h","","int","const char*","int","main_t","FAR char * const []|FAR char * const *" "task_delete","sched.h","","int","pid_t" "task_restart","sched.h","","int","pid_t" "telldir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","off_t","FAR DIR*" -- cgit v1.2.3