blob: a70eb137892b5c3b72ce74df77357ecb8c175088 [file] [log] [blame]
.. _nanokernel_example:
Semaphore, Timer, and Fiber Example
###################################
The following example is intended to provide a basic picture of how Zephyr's
semaphores, timers, and fibers work. The actual implementations of the
standard hello_world are much simpler, see
:file:`ZEPHYR_BASE/samples/hello_world`
Example Code
************
.. code-block:: c
#include <nanokernel.h>
#include <nanokernel/cpu.h>
/* specify delay between greetings (in ms); compute equivalent in ticks */
#define SLEEPTIME
#define SLEEPTICKS (SLEEPTIME * CONFIG_TICKFREQ / 1000)
#define STACKSIZE 2000
char fiberStack[STACKSIZE];
struct nano_sem nanoSemTask;
struct nano_sem nanoSemFiber;
void fiberEntry (void)
{
struct nano_timer timer;
uint32_t data[2] = {0, 0};
nano_sem_init (&nanoSemFiber);
nano_timer_init (&timer, data);
while (1)
{
/* wait for task to let us have a turn */
nano_fiber_sem_take(&nanoSemFiber, TICKS_UNLIMITED);
/* say "hello" */
PRINT ("%s: Hello World!\n", __FUNCTION__);
/* wait a while, then let task have a turn */
nano_fiber_timer_start (&timer, SLEEPTICKS);
nano_fiber_timer_test (&timer, TICKS_UNLIMITED);
nano_fiber_sem_give (&nanoSemTask);
}
}
void main (void)
{
struct nano_timer timer;
uint32_t data[2] = {0, 0};
task_fiber_start (&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberEntry, 0, 0, 7, 0);
nano_sem_init (&nanoSemTask);
nano_timer_init (&timer, data);
while (1)
{
/* say "hello" */
PRINT ("%s: Hello World!\n", __FUNCTION__);
/* wait a while, then let fiber have a turn */
nano_task_timer_start (&timer, SLEEPTICKS);
nano_task_timer_test (&timer, TICKS_UNLIMITED);
nano_task_sem_give (&nanoSemFiber);
/* now wait for fiber to let us have a turn */
nano_task_sem_take (&nanoSemTask, TICKS_UNLIMITED);
}
}
Step-by-Step Description
************************
A quick breakdown of the major objects in use by this sample includes:
- One fiber, executing in the :c:func:`fiberEntry()` routine.
- The background task, executing in the :c:func:`main()` routine.
- Two semaphores (*nanoSemTask*, *nanoSemFiber*),
- Two timers:
+ One local to the fiber (timer)
+ One local to background task (timer)
First, the background task starts executing main(). The background task
calls task_fiber_start initializing and starting the fiber. Since a
fiber is available to be run, the background task is pre-empted and the
fiber begins running.
Execution jumps to fiberEntry. nanoSemFiber and the fiber-local timer
before dropping into the while loop, where it takes and waits on
nanoSemFiber. task_fiber_start.
The background task initializes nanoSemTask and the task-local timer.
The following steps repeat endlessly:
#. The background task execution begins at the top of the main while
loop and prints, “main: Hello World!”
#. The background task then starts a timer for SLEEPTICKS in the
future, and waits for that timer to expire.
#. Once the timer expires, it signals the fiber by giving the
nanoSemFiber semaphore, which in turn marks the fiber as runnable.
#. The fiber, now marked as runnable, pre-empts the background
task, allowing execution to jump to the fiber.
nano_fiber_sem_take.
#. The fiber then prints, “fiberEntry: Hello World!” It starts a time
for SLEEPTICKS in the future and waits for that timer to expire. The
fiber is marked as not runnable, and execution jumps to the
background task.
#. The background task then takes and waits on the nanoSemTask
semaphore.
#. Once the timer expires, the fiber signals the background task by
giving the nanoSemFiber semaphore. The background task is marked as
runnable, but code execution continues in the fiber, since fibers
take priority over the background task. The fiber execution
continues to the top of the while loop, where it takes and waits on
nanoSemFiber. The fiber is marked as not runnable, and the
background task is scheduled.
#. The background task execution picks up after the call to
:c:func:`nano_task_sem_take()`. It jumps to the top of the
while loop.