Skip to content

Execution Model Proposal (alevy)

Amit Levy edited this page Jan 17, 2015 · 1 revision

Apps have an entry point that is called at boot time, and any number of event callbacks (which it must register explicitly through the syscall interface). Internally, an application has cooperative scheduling, i.e. the kernel will not call a function in the app while another function is running (unless the app uses the wait system call, explained below). However, scheduling is time sliced between apps.

Applications can interact with drivers in two ways. They may subscribe to events and invoke commands. In general, commands execute synchronously with their invocation (e.g. toggle a GPIO pin, read an ADC value, send a command over SPI), although they might actually be queued for later execution (e.g. transmit a reliable TCP packet). On the other hand, subscription return control to the app as soon as the callback has been registered, and fires asynchronously. If multiple events are ready to fire concurrently, callbacks can be queued in a buffer allocated by the app (defaults to?).

Examples of events that an app might register callbacks for are a virtual alarm firing, packet reception on a particular port or a gpio pin interrupt. An app subscribes to an event by invoking the subscribe system call, which indicates the particular event, the app callback function to be invoked when the event fires, as well as any additional arguments required to setup the event (e.g. when to fire an alarm, or which GPIO pin interrupt to listen for).

A typical application, then, has an init function that sets up initial events to listen for and callbacks reponding to those events:

char buf[16];
int val = -1;
void process_incoming();
void sensor_value_changed();

void init() {
  listen_net_port(process_incoming, 8888, buf, sizeof(buf));
  subscribe_gpio_interrupt(sensor_value_changed, 12);
}

void process_infoming() {
  if (buf == "current val\r\n") {
    int val = read_sensor_value(12);
    char outbuf[16]
    sprintf(outbuf, "%d\r\n", val);
    send_net_packet(outbuf, 8888);
  }
}

void sensor_value_changed() {
  val = read_sensor_value(12);
}

The systemcall interface is two-layered. The core kernel must be aware of three (maybe four) "kinds" of system calls in order to make scheduling decisions. However, device drivers can expose an arbitrary number of system calls subject to those types. In particular there are three (maybe four) SVC numbers: subscribe, command and wait. The first argument to subscribe and command are an integer specifying the driver and driver specific functionality.

Wait stops execution of the app until there is an event that the app has a registered callback for. Once a callback is ready, the kernel pushes a frame onto the app's stack and invokes the callback. This means that when the callback returns, it will return the execution state when wait was called.

Clone this wiki locally