Skip to content

Documentation: Processes and events

Simon Duquennoy edited this page Apr 28, 2018 · 13 revisions

Applications in Contiki-NG are typically written by using the Process abstraction. Processes are built on top of a lightweight threading library called Protothreads.

Process Definition

A process is first declared at the top of a source file. The PROCESS() macro takes two arguments: one is the variable with which we identify the process, and the other is the name of the process. On the second line, we tell Contiki-NG that this process should be automatically started directly after the system has booted up. Multiple processes can be specified here by separating them with commas. If the AUTOSTART_PROCESSES() line does not include an existing process, then that process has to be started manually by using the process_start() function.

#include "contiki.h" /* Main include file for OS-specific modules. */
#include <stdio.h> /* For printf. */

PROCESS(test_proc, "Test process");
AUTOSTART_PROCESSES(&test_proc);

A basic process can then be implemented as follows.

PROCESS_THREAD(test_proc, ev, data)
{
  PROCESS_BEGIN();

  printf("Hello, world!\n");

  PROCESS_END();
}

The PROCESS_THREAD() macro first takes the identifier of the processes specified in the PROCESS() call. The ev and data arguments contain the value of an incoming event, and an optional pointer to an event argument object. The PROCESS_BEGIN() marks the place where the process execution will start. In most cases, programmers should avoid placing code above this statement in the PROCESS_THREAD() body, except for variable definitions.

For our basic process implementation, we do not have to be concerned with any event handling, as we are only executing a single statement before implicitly exiting the process by letting it reach the PROCESS_END() call.

Events and Scheduling

Contiki-NG is built on an event-based execution model, where processes typically perform chunks of work before telling the scheduler that they are waiting for an event, and thereby suspend execution. Such events can be the expiration of a timer, an incoming network packet, or a serial line message being delivered.

Processes are scheduled cooperatively, which means that each process is responsible for voluntarily yielding control back to the operating system without executing for too long. Hence, the application developer must make sure that long-running operations are split into multiple process schedulings, allowing such operations to resume at the point where they last stopped.

Waiting for events

By calling PROCESS_WAIT_EVENT_UNTIL() in the area separated by the PROCESS_BEGIN() and PROCESS_END() calls, one can yield control to the scheduler, and only resume execution when an event is delivered. A condition is given as an argument to PROCESS_WAIT_EVENT_UNTIL(), and this condition must be fulfilled for the processes to continue execution after the call to PROCESS_WAIT_EVENT_UNTIL(). If the condition is not fulfilled, the process yields control back to the OS until a new event is delivered.

PROCESS_THREAD(test, ev, data)
{
  /* An event-timer variable. Note that this variable must be static
     in order to preserve the value across yielding. */
  static struct etimer et;

  PROCESS_BEGIN();

  etimer_set(&et, CLOCK_SECOND); /* Trigger a timer after 1 second. */
  while(1) {
    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
    etimer_reset(&et);
  }

  PROCESS_END();
}

Pausing and yielding

To voluntarily release control the scheduler, one can call PROCESS_PAUSE(), as in the example below. The scheduler will then deliver any queued events, and then immediately schedule the paused process.

PROCESS_THREAD(test_proc, ev, data)
{
  PROCESS_BEGIN();

  while(have_operations_to_do()) {
    do_some_operations();
    PROCESS_PAUSE();
  }

  PROCESS_END();
}

By contrast, PROCESS_YIELD() will yield control back to the scheduler without expecting to be scheduled again shortly thereafter. Instead, it will wait for an incoming event, similar to PROCESS_WAIT_EVENT_UNTIL(), but without a required condition argument. A process that has yielded can be polled by an external process or module by calling process_poll(). To poll a process declared with the variable test_proc, one can call process_poll(&test_proc);. The polled process will be scheduled immediately, and a PROCESS_EVENT_POLL event will be delivered to it.

Stopping processes

A process can be stopped in three ways:

  1. The process implicitly exits by allowing the PROCESS_END() statement to be reached and executed.
  2. The process explicitly exits by calling PROCESS_EXIT() in the PROCESS_THREAD body.
  3. Another process kills the process by calling process_exit().

After stopping a process, it can be restarted from the beginning by calling process_start().

System-defined Events

Contiki-NG uses a based of system-defined events for common operations, as listed below.

Event ID Description
PROCESS_EVENT_NONE 0x80 No event.
PROCESS_EVENT_INIT 0x81 Delivered to a process when it is started.
PROCESS_EVENT_POLL 0x82 Delivered to a process being polled.
PROCESS_EVENT_EXIT 0x83 Delivered to an exiting a process.
PROCESS_EVENT_SERVICE_REMOVED 0x84 Unused.
PROCESS_EVENT_CONTINUE 0x85 Delivered to a paused process when resuming execution.
PROCESS_EVENT_MSG 0x86 Delivered to a process upon a sensor event.
PROCESS_EVENT_EXITED 0x87 Delivered to all processes about an exited process.
PROCESS_EVENT_TIMER 0x88 Delivered to a process when one of its timers expired.
PROCESS_EVENT_COM 0x89 Unused.
PROCESS_EVENT_MAX 0x8a The maximum number of the system-defined events.

User-defined Events

One can also specify new events that are not covered in the system-defined events. The event variable should be defined and declared with an appropriate scope, so that all expected users of the event can access it. The basic case is to have it used only within a single module, and then it can be defined as static at the top of the module.

static process_event_t my_app_event;
[...]
my_app_event = process_alloc_event();

Note that there is no support for deallocating events.

Clone this wiki locally
You can’t perform that action at this time.