Event handling
The Bossa framework replaces scheduling code scattered throughout the kernel by a fixed interface of scheduling events. In this section we will see which events are available and how to handle them. As this article is just an overview of what is Bossa, we will just introduce the main events: new, block, unblock, clocktick, schedule and end.
First let's see how the set of event handlers is declared:
handler(event e) {
On event_name_1 {
/* statements */
}
On event_name_2 {
e.target.attribute = X;
//e.target is the process targeted by the event e
e.source.attribute = Y;
//e.source is the process which generated the event e
}
}
new
The new event is the first step in the life of a process. The Linux kernel allocates the process structure and other resources. The policy only needs to initialize the scheduling data and state of the process.
On process.new {
e.target.time_slice = 30;
e.target => active;
}
This code initializes the process's time_slice value to 30 units and places the process in the state active. The process is now eligible to run.
block
This event is quite frequent in the life of I/O based applications. It occurs when a process blocks, for instance to wait for user input.
On block.* { // we can use the wild card * to handle all block events
e.target => blocked;
}
For all of the block events we change the process state to the state blocked, making the process ineligible to run.
unblock
As a counterpart to the block.* event, the unblock.* event happens when a process unblocks, which may for example occur when the user types on the keyboard.
On unblock.* {
if (e.target in blocked) { // if e.target is in the blocked state
e.target => active;
}
}
This handler checks whether the process is in the state blocked. If so, we change its state from blocked to active. The => operation automatically removes the process from the data structure (queue, process variable, list, tree, ...) associated with its current state.
clocktick
The clocktick event is triggered at each CPU clock tick. Basically, a policy can use the processor clocktick as a unit of time, which is how the round-robin policy manages the time_slice process attribute. Back in the new event handler we set the time_slice attribute to 30 meaning that a process can run on the CPU for as long as 30 clockticks. Here is how we handle this event in the round robin scheduler:
On system.clocktick {
running.time_slice--; // process just used some time
if (running.time_slice <= 0) { // the process timeslice is over
running.time_slice = 30; // we reload its timeslice
running => active; // and preempt it
}
}
If the process has used up its time slice, it is preempted.
schedule
We have seen that a process can be preempted during a block and a clocktick. When the running process has been preempted, the scheduler needs to elect a new process to run. The round robin algorithm just selects the next process in the state active. Thus, the implementation of the schedule event handler is very simple:
On bossa.schedule {
select() => running;
}
select() returns a process from the sorted queue, selected according to the ordering_criteria and any extra information about the ordering of this queue (here fifo ordering). By changing the state of this process to running (using =>) we declare that the newly elected process is to be executed (we change its state from active to running).
end
Finally, the end event indicates process termination. We generally don't care about terminated processes so this event handler will often just contain:
On process.end {
e.target => terminated;
}
This event handler is typically more complex in the case of policies that have an acceptance criteria based on the current load on the scheduler (for example, EDF1). These policies have to know when processes depart, thus reducing the load.
- "Bossa, Page 1/4"
- "Bossa, Page 2/4"
- "Bossa, Page 3/4"
- "Bossa, Page 4/4"



