-
Notifications
You must be signed in to change notification settings - Fork 4
Execution Model Proposal (alevy)
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.