| ======================= |
| Task Control Interfaces |
| ======================= |
| |
| .. warning:: This section name is duplicate with the first, how should it be named? |
| |
| - **Scheduler locking interfaces**. These *non-standard* interfaces are |
| used to enable and disable pre-emption and to test is pre-emption is |
| currently enabled. |
| |
| - :c:func:`sched_lock` |
| - :c:func:`sched_unlock` |
| - :c:func:`sched_lockcount` |
| |
| - **Task synchronization interfaces** are used to wait for termination of child tasks. |
| |
| - :c:func:`waitpid` |
| - :c:func:`waitid` |
| - :c:func:`wait` |
| |
| - **Task Exit Hooks** may be used to |
| register callback functions that are executed when a *task group* |
| terminates. A task group is the functional analog of a process: It is |
| a group that consists of the main task thread and of all of the |
| pthreads created by the main task thread or any of the other pthreads |
| within the task group. Members of a task group share certain |
| resources such as environment variables, file descriptors, ``FILE`` |
| streams, sockets, pthread keys and open message queues. |
| |
| - :c:func:`atexit` |
| - :c:func:`on_exit` |
| |
| .. note:: |
| Behavior of features related to task group's depend of |
| NuttX configuration settings. See the discussion of "Parent and |
| Child Tasks," below. See also the\ `NuttX |
| Tasking <https://cwiki.apache.org/confluence/display/NUTTX/NuttX+Tasking>`__\ page |
| and the\ `Tasks vs. Threads |
| FAQ <https://cwiki.apache.org/confluence/display/NUTTX/Tasks+vs.+Threads+FAQ>`__\ for |
| additional information on tasks and threads in NuttX. |
| |
| A *task group* terminates when the last thread within the group |
| exits. |
| |
| Parent and Child Tasks |
| ====================== |
| |
| The task synchronization interfaces |
| historically depend upon parent and child relationships between tasks. |
| But default, NuttX does not use any parent/child knowledge. However, |
| there are three important configuration options that can change that. |
| |
| - ``CONFIG_SCHED_HAVE_PARENT``: If this setting is defined, then it |
| instructs NuttX to remember the task ID of the parent task when each |
| new child task is created. This support enables some additional |
| features (such as ``SIGCHLD``) and modifies the behavior of other |
| interfaces. For example, it makes ``waitpid()`` more standards |
| complete by restricting the waited-for tasks to the children of the |
| caller. |
| |
| - ``CONFIG_SCHED_CHILD_STATUS``: If this option is selected, then |
| the exit status of the child task will be retained after the child |
| task exits. This option should be selected if you require knowledge |
| of a child process's exit status. Without this setting, ``wait()``, |
| ``waitpid()`` or ``waitid()`` may fail. For example, if you do: |
| |
| #. Start child task |
| #. Wait for exit status (using :c:func:`wait`, :c:func:`waitpid` or |
| :c:func:`waitid`). |
| |
| This may fail because the child task may run to completion before the |
| wait begins. There is a non-standard work-around in this case: The |
| above sequence will work if you disable pre-emption using |
| :c:func:`sched_lock` prior to starting the child task, then re-enable |
| pre-emption with :c:func:`sched_unlock` after the wait completes. This |
| works because the child task is not permitted to run until the wait |
| is in place. |
| |
| The standard solution would be to enable |
| ``CONFIG_SCHED_CHILD_STATUS``. In this case the exit status of the |
| child task is retained after the child exits and the wait will |
| successful obtain the child task's exit status whether it is called |
| before the child task exits or not. |
| |
| - ``CONFIG_PREALLOC_CHILDSTATUS``. To prevent runaway child status |
| allocations and to improve allocation performance, child task exit |
| status structures are pre-allocated when the system boots. This |
| setting determines the number of child status structures that will be |
| pre-allocated. |
| |
| Obviously, if tasks spawn children indefinitely and never have the |
| exit status reaped, then you may have a memory leak! (See **Warning** |
| below) |
| |
| .. warning:: If you enable the ``CONFIG_SCHED_CHILD_STATUS`` feature, |
| then your application must either (1) take responsibility for reaping |
| the child status with ``wait()``, ``waitpid()`` or ``waitid()``, or (2) |
| suppress retention of child status. If you do not reap the child status, |
| then you have a memory leak and your system will eventually fail. |
| |
| Retention of child status can be suppressed on the parent using logic |
| like: |
| |
| .. code-block:: c |
| |
| struct sigaction sa; |
| |
| sa.sa_handler = SIG_IGN; |
| sa.sa_flags = SA_NOCLDWAIT; |
| int ret = sigaction(SIGCHLD, &sa, NULL); |
| |
| Functions |
| ========= |
| |
| .. c:function:: int sched_lock(void) |
| |
| Disables context switching by Disabling |
| addition of new tasks to the ready-to-run task list. The task that calls |
| this function will be the only task that is allowed to run until it |
| either calls sched_unlock (the appropriate number of times) or until it |
| blocks itself. |
| |
| :return: OK or ERROR. |
| |
| **POSIX Compatibility:** This is a NON-POSIX interface. VxWorks provides |
| the comparable interface: |
| |
| .. code-block:: c |
| |
| STATUS taskLock(void); |
| |
| .. c:function:: int sched_unlock(void) |
| |
| Decrements the preemption lock count. |
| Typically this is paired with sched_lock() and concludes a critical |
| section of code. Preemption will not be unlocked until sched_unlock() |
| has been called as many times as sched_lock(). When the lockCount is |
| decremented to zero, any tasks that were eligible to preempt the current |
| task will execute. |
| |
| :return: OK or ERROR. |
| |
| **POSIX Compatibility:** This is a NON-POSIX interface. VxWorks provides |
| the comparable interface: |
| |
| .. code-block:: c |
| |
| STATUS taskUnlock(void); |
| |
| .. c:function:: int32_t sched_lockcount(void) |
| |
| Returns the current value of the |
| lockCount. If zero, preemption is enabled; if non-zero, this value |
| indicates the number of times that sched_lock() has been called on this |
| thread of execution. |
| |
| :return: The current value of the lockCount. |
| |
| **POSIX Compatibility:** None. |
| |
| .. c:function:: ipid_t waitpid(pid_t pid, int *stat_loc, int options) |
| |
| .. note:: |
| The following discussion is a general description of the |
| ``waitpid()`` interface. However, as of this writing, the |
| implementation of ``waitpid()`` is incomplete (but usable). If |
| ``CONFIG_SCHED_HAVE_PARENT`` is defined, ``waitpid()`` will be a |
| little more compliant to specifications. Without |
| ``CONFIG_SCHED_HAVE_PARENT``, ``waitpid()`` simply supports waiting |
| for any task to complete execution. With |
| ``CONFIG_SCHED_HAVE_PARENT``, ``waitpid()`` will use ``SIGCHLD`` and |
| can, therefore, wait for any child of the parent to complete. The |
| implementation is incomplete in either case, however: NuttX does not |
| support any concept of process groups. Nor does NuttX retain the |
| status of exited tasks so if ``waitpid()`` is called after a task has |
| exited, then no status will be available. The options argument is |
| currently ignored. |
| |
| The ``waitpid()`` functions will obtain status information pertaining to |
| one of the caller's child processes. The ``waitpid()`` function will |
| suspend execution of the calling thread until status information for one |
| of the terminated child processes of the calling process is available, |
| or until delivery of a signal whose action is either to execute a |
| signal-catching function or to terminate the process. If more than one |
| thread is suspended in ``waitpid()`` awaiting termination of the same |
| process, exactly one thread will return the process status at the time |
| of the target process termination. If status information is available |
| prior to the call to ``waitpid()``, return will be immediate. |
| |
| **NOTE**: Because ``waitpid()`` is not fully POSIX compliant, it must be |
| specifically enabled by setting ``CONFIG_SCHED_WAITPID`` in the NuttX |
| configuration file. |
| |
| :param pid: The task ID of the thread to wait for |
| :param stat_loc: The location to return the exit status |
| :param options: ignored |
| |
| The ``pid`` argument specifies a set of child processes for which status |
| is requested. The ``waitpid()`` function will only return the status of |
| a child process from this set: |
| |
| - If ``pid`` is equal to ``(pid_t)-1``), status is requested for any |
| child process. In this respect, ``waitpid()`` is then equivalent to |
| ``wait()``. |
| - If ``pid`` is greater than 0, it specifies the process ID of a single |
| child process for which status is requested. |
| - If ``pid`` is 0, status is requested for any child process whose |
| process group ID is equal to that of the calling process. |
| - If ``pid`` is less than ``(pid_t)-1``), status is requested for any |
| child process whose process group ID is equal to the absolute value |
| of pid. |
| |
| The ``options`` argument is constructed from the bitwise-inclusive OR of |
| zero or more of the following flags, defined in the ``<sys/wait.h>`` |
| header: |
| |
| - ``WCONTINUED``. The ``waitpid()`` function will report the status of |
| any continued child process specified by pid whose status has not |
| been reported since it continued from a job control stop. |
| - ``WNOHANG``. The ``waitpid()`` function will not suspend execution of |
| the calling thread if status is not immediately available for one of |
| the child processes specified by ``pid``. |
| - ``WUNTRACED``. The status of any child processes specified by ``pid`` |
| that are stopped, and whose status has not yet been reported since |
| they stopped, will also be reported to the requesting process. |
| |
| If the calling process has ``SA_NOCLDWAIT`` set or has ``SIGCHLD`` set |
| to ``SIG_IGN``, and the process has no unwaited-for children that were |
| transformed into zombie processes, the calling thread will block until |
| all of the children of the process containing the calling thread |
| terminate, and ``waitpid()`` will fail and set ``errno`` to ``ECHILD``. |
| |
| If ``waitpid()`` returns because the status of a child process is |
| available, these functions will return a value equal to the process ID |
| of the child process. In this case, if the value of the argument |
| stat_loc is not a null pointer, information will be stored in the |
| location pointed to by ``stat_loc``. The value stored at the location |
| pointed to by ``stat_loc`` will be 0 if and only if the status returned |
| is from a terminated child process that terminated by one of the |
| following means: |
| |
| #. The process returned 0 from ``main()``. |
| #. The process called ``_exit()`` or ``exit()`` with a status argument |
| of 0. |
| #. The process was terminated because the last thread in the process |
| terminated. |
| |
| Regardless of its value, this information may be interpreted using the |
| following macros, which are defined in ``<sys/wait.h>`` and evaluate to |
| integral expressions; the ``stat_val`` argument is the integer value |
| pointed to by ``stat_loc``. |
| |
| - ``WIFEXITED(stat_val)``. Evaluates to a non-zero value if status was |
| returned for a child process that terminated normally. |
| - ``WEXITSTATUS(stat_val)``. If the value of ``WIFEXITED(stat_val)`` is |
| non-zero, this macro evaluates to the low-order 8 bits of the status |
| argument that the child process passed to ``_exit()`` or ``exit()``, |
| or the value the child process returned from ``main()``. |
| - ``WIFSIGNALED(stat_val)``. Evaluates to a non-zero value if status |
| was returned for a child process that terminated due to the receipt |
| of a signal that was not caught (see >signal.h<). |
| - ``WTERMSIG(stat_val)``. If the value of ``WIFSIGNALED(stat_val)`` is |
| non-zero, this macro evaluates to the number of the signal that |
| caused the termination of the child process. |
| - ``WIFSTOPPED(stat_val)``. Evaluates to a non-zero value if status was |
| returned for a child process that is currently stopped. |
| - ``WSTOPSIG(stat_val)``. If the value of ``WIFSTOPPED(stat_val)`` is |
| non-zero, this macro evaluates to the number of the signal that |
| caused the child process to stop. |
| - ``WIFCONTINUED(stat_val)``. Evaluates to a non-zero value if status |
| was returned for a child process that has continued from a job |
| control stop. |
| |
| :return: |
| If ``waitpid()`` returns because the status of a child process is |
| available, it will return a value equal to the process ID of the child |
| process for which status is reported. |
| |
| If ``waitpid()`` returns due to the delivery of a signal to the calling |
| process, -1 will be returned and ``errno`` set to ``EINTR``. |
| |
| If ``waitpid()`` was invoked with WNOHANG set in options, it has at |
| least one child process specified by pid for which status is not |
| available, and status is not available for any process specified by pid, |
| 0 is returned. |
| |
| Otherwise, ``(pid_t)-1errno`` set to indicate the error: |
| |
| - ``ECHILD``. The process specified by ``pid`` does not exist or is not |
| a child of the calling process, or the process group specified by |
| ``pid`` does not exist or does not have any member process that is a |
| child of the calling process. |
| - ``EINTR``. The function was interrupted by a signal. The value of the |
| location pointed to by ``stat_loc`` is undefined. |
| - ``EINVAL``. The ``options`` argument is not valid. |
| |
| **Assumptions/Limitations:** |
| |
| **POSIX Compatibility:** Comparable to the POSIX interface of the same |
| name, but the implementation is incomplete (as detailed above). |
| |
| .. c:function:: int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options) |
| |
| .. note:: |
| |
| The following discussion is a general description of the ``waitid()`` |
| interface. However, as of this writing, the implementation of |
| ``waitid()`` is incomplete (but usable). If |
| ``CONFIG_SCHED_HAVE_PARENT`` is defined, ``waitid()`` will be a |
| little more compliant to specifications. ``waitpid()`` simply |
| supports waiting a specific child task (``P_PID`` or for any child |
| task ``P_ALL`` to complete execution. ``SIGCHLD`` is used. The |
| implementation is incomplete in either case, however: NuttX does not |
| support any concept of process groups. Nor does NuttX retain the |
| status of exited tasks so if ``waitpid()`` is called after a task has |
| exited, then no status will be available. The options argument is |
| currently ignored. |
| |
| The ``waitid()`` function suspends the calling thread until one child of |
| the process containing the calling thread changes state. It records the |
| current state of a child in the structure pointed to by ``info``. If a |
| child process changed state prior to the call to ``waitid()``, |
| ``waitid()`` returns immediately. If more than one thread is suspended |
| in ``wait()`` or ``waitpid()`` waiting termination of the same process, |
| exactly one thread will return the process status at the time of the |
| target process termination |
| |
| The ``idtype`` and ``id`` arguments are used to specify which children |
| ``waitid()`` will wait for. |
| |
| - If ``idtype`` is P_PID, ``waitid()`` will wait for the child with a |
| process ID equal to (pid_t)``id``. |
| - If ``idtype`` is P_PGID, ``waitid()`` will wait for any child with a |
| process group ID equal to (pid_t)``id``. |
| - If ``idtype`` is P_ALL, ``waitid()`` will wait for any children and |
| ``id`` is ignored. |
| |
| The ``options`` argument is used to specify which state changes |
| ``waitid()`` will will wait for. It is formed by OR-ing together one or |
| more of the following flags: |
| |
| - ``WEXITED``: Wait for processes that have exited. |
| - ``WSTOPPED``: Status will be returned for any child that has stopped |
| upon receipt of a signal. |
| - ``WCONTINUES``: Status will be returned for any child that was |
| stopped and has been continued. |
| - ``WNOHANG``: Return immediately if there are no children to wait for. |
| - ``WNOWAIT``: Keep the process whose status is returned in ``info`` in |
| a waitable state. This will not affect the state of the process; the |
| process may be waited for again after this call completes. |
| |
| The ``info`` argument must point to a ``siginfo_t`` structure. If |
| ``waitid()`` returns because a child process was found that satisfied |
| the conditions indicated by the arguments ``idtype`` and options, then |
| the structure pointed to by ``info`` will be filled in by the system |
| with the status of the process. The ``si_signo`` member will always be |
| equal to ``SIGCHLD``. |
| |
| :return: If ``waitid()`` returns due to the change of state |
| of one of its children, 0 is returned. Otherwise, -1 is returned and |
| ``errno`` is set to indicate the error. |
| |
| The ``waitid()`` function will fail if: |
| |
| - ``ECHILD``: |
| - ``EINTR``: |
| - ``EINVAL``: An invalid value was specified for ``options``, or |
| ``idtype`` and ``id`` specify an invalid set of processes. |
| |
| **POSIX Compatibility:** Comparable to the POSIX interface of the same |
| name, but the implementation is incomplete (as detailed in the |
| description above). |
| |
| .. c:function:: pid_t wait(FAR int *stat_loc) |
| |
| .. note:: |
| The following discussion is a general description of the :c:func:`wait` |
| interface. However, as of this writing, the implementation of |
| :c:func:`wait` is incomplete (but usable). :c:func:`wait` is based |
| on :c:func:`waitpid` (see description for further information). |
| |
| The ``wait()`` function will suspend execution of the calling thread |
| until status information for one of its terminated child processes is |
| available, or until delivery of a signal whose action is either to |
| execute a signal-catching function or to terminate the process. If more |
| than one thread is suspended in ``wait()`` awaiting termination of the |
| same process, exactly one thread will return the process status at the |
| time of the target process termination. If status information is |
| available prior to the call to\ ``wait()``, return will be immediate. |
| |
| The ``waitpid()`` function will behave identically to ``wait()``, if its |
| ``pid`` argument is (pid_t)-1 and the options argument is 0. Otherwise, |
| its behavior will be modified by the values of the ``pid`` and |
| ``options`` arguments. |
| |
| :param stat_loc: The location to return the exit status |
| :return: See the values returned by :c:func:`waitpid` |
| |
| **POSIX Compatibility:** Comparable to the POSIX interface of the same |
| name, but the implementation is incomplete (as detailed in the |
| description ```waitpaid()`` <#waitpid>`__). |
| |
| .. c:function:: int atexit(void (*func)(void)) |
| |
| Registers a function to be called at program exit. The |
| ``atexit()`` function registers the given function to be called at |
| normal process termination, whether via ``exit()`` or via return from |
| the program's ``main()``. |
| |
| .. note:: ``CONFIG_SCHED_ATEXIT`` must be defined to enable this function. |
| |
| :param func: A pointer to the function to be called when the task exits. |
| :return: On success, ``atexit()`` returns OK (0). On error, |
| ERROR (-1) is returned, and ```errno`` <#ErrnoAccess>`__ is set to |
| indicate the cause of the failure. |
| |
| **POSIX Compatibility:** Comparable to the ISO C interface of the same |
| name. Limitations in the current implementation: |
| |
| #. Only a single ``atexit`` function can be registered unless |
| ``CONFIG_SCHED_ATEXIT_MAX`` defines a larger number. |
| #. ``atexit()`` functions are not inherited when a new task is created. |
| |
| .. c:function:: int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg) |
| |
| Registers a function to be called at program exit. The |
| ``on_exit()`` function registers the given function to be called at |
| normal process termination, whether via ``exit()`` or via return from |
| the program's ``main()``. The function is passed the status argument |
| given to the last call to ``exit()`` and the ``arg`` argument from |
| ``on_exit()``. |
| |
| .. note: ``CONFIG_SCHED_ONEXIT`` must be defined to enable this |
| function |
| |
| :param func: A pointer to the function to be called when the task exits. |
| :param arg: An argument that will be provided to the ``on_exit()`` |
| function when the task exits. |
| |
| :return: On success, ``on_exit()`` returns OK (0). On error, |
| ERROR (-1) is returned, and ```errno`` <#ErrnoAccess>`__ is set to |
| indicate the cause of the failure. |
| |
| **POSIX Compatibility:** This function comes from SunOS 4, but is also |
| present in libc4, libc5 and glibc. It no longer occurs in Solaris (SunOS |
| 5). Avoid this function, and use the standard ``atexit()`` instead. |
| |
| #. Only a single ``on_exit`` function can be registered unless |
| ``CONFIG_SCHED_ONEXIT_MAX`` defines a larger number. |
| #. ``on_exit()`` functions are not inherited when a new task is created. |