Skip to content

Events

Overview

MiraOS is depending on an event-driven execution model. Each process typically executes small chunks of instructions before telling the scheduler that they are waiting for an event, and thereby handing control back to the scheduler.

Events can be for instance expiration of an event timer, an incoming network packet, or a user defined event.

Waiting for events

It's only possible to wait for events in the part of a process definition that is between the PROCESS_BEGIN() and PROCESS_END() statements. Waiting for an event is done by calling the PROCESS_WAIT_EVENT() or PROCESS_WAIT_EVENT_UNTIL() system calls. Doing so yields the control back to the scheduler, and execution is resumed only after an event has been sent to the process.

PROCESS_WAIT_EVENT_UNTIL() also takes a statement as an argument, if this statement is evaluated to FALSE the process immediately yields back to the scheduler again waiting for the next event.

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

  PROCESS_BEGIN();

  while (1) {
    etimer_set(&et, CLOCK_SECOND); /* Set the timer to 1 second. */
    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
    printf("Hello, world!\n");
  }

  PROCESS_END();
}

System events

The following events are defined by the kernel.

Event Description
PROCESS_EVENT_INIT Delivered to a process when it is started.
PROCESS_EVENT_POLL Delivered to a process being polled.
PROCESS_EVENT_EXIT Delivered to an exiting a process.
PROCESS_EVENT_CONTINUE Delivered to a paused process when resuming execution.
PROCESS_EVENT_EXITED Delivered to all processes about an exited process.
PROCESS_EVENT_TIMER Delivered to a process when one of its timers expired.

User-defined events

The application developer may also create new events that are not covered by the system-defined events.

The event variable must have an appropriate scope, so that all code using the event can access it.

static process_event_t my_event;

my_event = process_alloc_event();

Note that there is no support for deallocating events.

Asynchronous events

Posting an asynchronous event places the event on MiraOS kernel's event queue. Asynchronous events are delivered to the receiving process some time after they have been posted.

The events on the event queue are delivered to the receiving process by the kernel. The kernel loops through the event queue and delivers the events to the processes on the queue by invoking the processes.

The receiver of an asynchronous event can either be a specific process, or all running processes. When the receiver is a specific process, the kernel invokes this process to deliver the event. When an event is sent to all processes in the system, the kernel devlivers the event sequentially to all processes, one after another.

Asynchronous events are posted with the process_post() call. It first checks the size of the current event queue to determine if there is room for the event on the queue. If not, the function returns an error. If there is room for the event on the queue, the function inserts the event at the end of the event queue and returns.

Note

Care should be taken when posting events. They can't be used from Interrupt subroutines.

Example

process_event_t my_event;

PROCESS(receiving_proc, "Receiving process");
PROCESS(sending_proc, "Sending process");

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

  while (1) {
    PROCESS_WAIT_EVENT_UNTIL(ev == my_event);

    printf("Got event\n");
  }

  PROCESS_END();
}

PROCESS_THREAD(sending_proc, ev, data)
{
  static struct etimer timer;
  PROCESS_BEGIN();

  while (1) {
    /* Sleep for three seconds */
    etimer_set(&timer, CLOCK_SECOND * 3);
    PROCESS_WAIT_UNTIL(etimer_expired(&timer));

    /* Post event */
    printf("Sending event\n");
    process_post(&receiving_proc, my_event, NULL);
    printf("Event sent\n");
  }

  PROCESS_END();
}

void start_sender_receiver(void)
{
  my_event = process_alloc_event();
  process_start(&sending_proc, NULL);
  process_start(&receiving_proc, NULL);
}

Synchronous Events

Synchronous events are posted using the process_post_synch() system call. Unlike asynchronous events, synchronous events are delivered directly when they are posted. Synchronous events can only be posted to a specific process.

Because synchronous events are delivered immediately, posting a synchronous event is functionally equivalent to a function call: the process to which the event is delivered is directly invoked, and the process that posted the event is blocked until the receiving process has finished processing the event.

The receiving process is, however, not informed whether the event was posted synchronously or asynchronously.

Note

Care should be taken when posting events. They can't be used from Interrupt subroutines.

Polling processes

process_post() is not allowed from interrupts. Therefore, to wake up processes another method is needed.

To wake up a process from an interrupt process_poll() is used. The process will then wake.

However, using process_poll(), no specific event or data can be passed to the process. It is up to the process to check, or poll, what is updated to decide what action the process should take.

Usually, a global variable is set in the interrupt that can be checked from the process.

Example

static volatile int got_irq_a = 0;
static volatile int got_irq_b = 0;

static process_event_t an_event; /* Should be set from process_alloc_event() */

PROCESS(receiving_proc, "Receiving process");

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

  while (1) {
    /* Sleep until next event, regardless of reason */
    PROCESS_YIELD();

    if(got_irq_a) {
      got_irq_a = 0;
      printf("Got IRQ A\n");
    }

    if(got_irq_b) {
      got_irq_b = 0;
      printf("Got IRQ B\n");
    }

    if(ev == an_event) {
      printf("Got an event\n");
    }
  }

  PROCESS_END();
}

void isr_a(void)
{
    got_irq_a = 1;
    process_poll(&receiving_proc);
}

void isr_b(void)
{
    got_irq_b = 1;
    process_poll(&receiving_proc);
}