...
 
Commits (5)
......@@ -11,13 +11,14 @@
* [Boot Sequence](nuttx-in-depth/boot-sequence.md)
* [C Library](nuttx-in-depth/c-library.md)
* [Taks and Threads](nuttx-in-depth/taks-and-threads.md)
* [Scheduler](nuttx-in-depth/scheduler.md)
* [Drivers](nuttx-in-depth/drivers.md)
* Filesystems
* [C++ Support](nuttx-in-depth/c++-support.md)
* [System Timer](nuttx-in-depth/system-timer.md)
* System Console
* Logging \(SYSLOG\)
* [Power Management](nuttx-in-depth/power-management.md)
* Scheduler
* [Using NuttX in Your Project](using-nuttx-in-your-project.md)
* Developing Applications
* Supporting a New Chip
......
> **[info]** work in progress
> Is this information still up to date? Where can I get the information of the state transitions?
# Scheduler
One important component of an operating system is a scheduler: the logic that controls when tasks or threads execute. Actually, more than that; the scheduler really determines what a task or a thread is! Most tiny operating systems, such as FreeRTOS are really not operating “systems” in the sense of providing a complete operating
environment. Rather these tiny operating systems consist really only of a scheduler. That is how important the scheduler is.
## State Transition Diagram
The state of a thread can then be easily represented with this simple state transition diagram:
> **[info]** to be provided
## Scheduling Policies
In order to be a real-time OS, an RTOS must support FIFO scheduling. That is, strict priority scheduling.
The thread with the highest priority runs. Period. The thread with the highest priority is always associated with the TCB at the head of the `g_readytorun` list.
NuttX supports one additional real-time scheduling policy. Specifically, it supports round-robin scheduling. In this case, NuttX supports timeslicing: If a task with round-robin scheduling policy is running, then when each timeslice elapses, it will give up the CPU to the next task that is at the same priority. Note that if there is only one task at this priority, round-robin and FIFO are the same. Moreover, FIFO tasks are never pre-empted in this
way.
1.2.1 Task Control Block (TCB)
In NuttX a thread is any controllable sequence of instruction execution that has its own stack. Each
task is represented by a data structure called a task control block or TCB. That data structure is defined
in the header file include/nuttx/sched.h.
1.2.2 Task Lists
These TCBs are retained in lists. The state of a task is indicated both by the task_state field of the
TCB and by a series of task lists. Although it is not always necessary, most of these lists are prioritized
so that common list handling logic can be used (only the g_readytorun, the g_pendingtasks,
and the g_waitingforsemaphore lists need to be prioritized).
All new tasks start in a non-running, uninitialized state:
volatile dq_queue_t g_inactivetasks;
This the list of all tasks that have been initialized, but not yet activated. NOTE: This is the only
list that is not prioritized.
When the task is initialized, it is moved to a read-to-run list. There are two lists representing ready-to-
run threads and several lists representing blocked threads. Here are the read-to-run threads:
volatile dq_queue_t g_readytorun;
This is the list of all tasks that are ready to run. The head of this list is the currently active task;
the tail of this list is always the idle task.
volatile dq_queue_t g_pendingtasks;
This is the list of all tasks that are ready-to-run, but cannot be placed in the g_readytorun
list because: (1) They are higher priority than the currently active task at the head of the
g_readytorun list, and (2) the currently active task has disabled pre-emption. These tasks will
stay in this holding list until pre-emption is again enabled (or the until the currently active task
voluntarily relinquishes the CPU).
Tasks in the g_readytorun list may become blocked. In this cased, their TCB will be moved to
one of the blocked lists. When the block task is ready-to-run, its TCB will be moved back to either the
g_readytorun to to the g_pendingtasks lists, depending up if pre-emption is disabled and
upon the priority of the tasks.
Here are the block task lists:
volatile dq_queue_t g_waitingforsemaphore;
This is the list of all tasks that are blocked waiting for a semaphore.
volatile dq_queue_t g_waitingforsignal;
This is the list of all tasks that are blocked waiting for a signal (only if signal support has not
been disabled)
volatile dq_queue_t g_waitingformqnotempty;
This is the list of all tasks that are blocked waiting for a message queue to become non-empty
(only if message queue support has not been disabled).
volatile dq_queue_t g_waitingformqnotfull;
This is the list of all tasks that are blocked waiting for a message queue to become non-full
(only if message queue support has not been disabled).
volatile dq_queue_t g_waitingforfill;
This is the list of all tasks that are blocking waiting for a page fill (only if on-demand paging is
selected).
(Reference nuttx/sched/os_internal.h).
1.2.5 Task IDs
Each task is represented not only by a TCB but also by a numeric task ID. Given a task ID, the RTOS
can find the TCB; given a TCB, the RTOS can find the task ID. So they are functionally equivalent.
Only the task ID, however, is exposed at the RTOS/application interfaces.
\ No newline at end of file
> **TODO** port from here http://nuttx.org/doku.php?id=documentation:overview
\ No newline at end of file
# Tasks and Threads
## Task vs Process
When using NuttX, there's a distinction between *tasks* and *threads*. In few words, a *task* is similar to a typical Linux process. However, a key difference is that in NuttX, in contrast to other OS such as Linux or Windows, tasks do not have their own private space (and thus the term *process* is not used for NuttX).
In order to implement private address spaces, the processor must support a memory management unit (MMU). The MMU is used to enforce the protected process environment. However, NuttX was designed to support the more resource constrained, lower-end, deeply embedded MCUs. Those MCUs seldom have an MMU and, as a consequence, can never support processes as are support by Windows and Linux. So NuttX does not support processes.
For this reason, NuttX is a flat address OS. As such, it does not support processes each with its own separate address space. In other words, it only supports simple tasks and threads running within the same address space.
However, a distinction can be made between the two.
## Task vs Thread
Tasks are threads which have a degree of independence, while threads share some resources. This applies, in particular, in the area of opened file descriptors and streams. When a task is started, it inherits (receives a duplicate) the open file descriptors of its parent task. Since these are duplicates, the child task can close them or manipulate them in any way without effecting the parent task. File-related operations (`open`, `close`, etc.) within a task will have no effect on other tasks. It is also possible to perform some level of redirection.
If the NuttX system console is defined (as will be in most cases), the first three file descriptors inherted by a task will correspond to `stdin`, `stdout` and `stderr`.
Threads, on the other hand, will always share file descriptors with the parent thread (as it will with any other resource acquired in the task). In this case, file operations will have effect only all pthreads the were started from the same parent thread.
Threads, on the other hand, will always share file descriptors with the parent thread (as it will with any other resource acquired in the task). In this case, file operations will have effect only all pthreads the were started from the same parent thread.
In general, a task is a thread with an environment associated with it, which is private and unique to the task. This environment consists of a number of resources. Of interest in this discussion are the following (note that any of these task resources may be disabled in the NuttX
configuration to reduce the NuttX memory footprint).
1. **Environment Variables**. This is the collection of variable assignments of the form: `VARIABLE=VALUE`
2. **File Descriptors**. A file descriptor is a task specific number that represents an open resource (a file or a device driver, for example).
3. **Sockets**. A socket descriptor is like a file descriptor, but the open resource in this case is a
network socket.
4. **Streams**. Streams represent standard C buffered I/O. Streams wrap file descriptors or sockets a provide a new set of interface functions for dealing with the standard C I/O (like `fprintf()`, `fwrite()`, etc.).
In NuttX, a task is created using the interface `task_create()`.
## Programs (or applications) and tasks
A task can be considered an instance of a specific application. New tasks can be spawned in NuttX during run-time (either from code via a specific API or by running commands from the NuttX Shell).
However, another difference with respect to other standard Operating Systems is that applications may not necessarilly be a separate binary from the OS. In fact, the usual case will be to build NuttX and all its components (including applications) within a single binary. Tasks are then run mainly by function calls (performed by the OS) into entry points of these applications. These applications residing in the same NuttX image are known as **builtin applications**.
NuttX also supports the capability of executing **separate application binaries** residing in a filesystem. Different binary formats are supported, such as the standard ELF format and NuttX's own [NXFLAT](http://nuttx.org/Documentation/NuttXNxFlat.html) format.