So far we've talked about scheduling policies and thread states, but we haven't said much yet about why and when things are rescheduled. There's a common misconception that rescheduling just occurs, without any real causes. Actually, this is a useful abstraction during design! But it's important to understand the conditions that cause rescheduling. Rescheduling occurs only because of:
Rescheduling due to a hardware interrupt occurs in two cases:
The realtime clock generates periodic interrupts for the kernel, causing time-based rescheduling.
For example, if you issue a sleep (10); call, a number of realtime clock interrupts occur; the kernel increments the time-of-day clock at each interrupt. When the time-of-day clock indicates that 10 seconds have elapsed, the kernel reschedules your thread as READY.
Other threads might wait for hardware interrupts from peripherals, such as the serial port, a hard disk, or an audio card. In this case, they are blocked in the kernel waiting for a hardware interrupt; the thread is rescheduled by the kernel only after that event is generated.
If the rescheduling is caused by a thread issuing a kernel call, the rescheduling is done immediately and can be considered asynchronous to the timer and other interrupts. For example, above we called sleep(10);. This C library function is eventually translated into a kernel call. At that point, the kernel made a rescheduling decision to take your thread off of the READY queue for that priority, and then schedule another thread that was READY.
There are many kernel calls that cause a process to be rescheduled. Most of them are fairly obvious. Here are a few:
The final cause of rescheduling, a CPU fault, is an exception, somewhere between a hardware interrupt and a kernel call. It operates asynchronously to the kernel (like an interrupt) but operates synchronously with the user code that caused it (like a kernel call—for example, a divide-by-zero exception). The same discussion as above (for hardware interrupts and kernel calls) applies to faults.
BlackBerry 10 OS offers a rich set of scheduling options with threads, the primary scheduling elements. Processes are defined as a unit of resource ownership (for example, a memory area) and contain one or more threads. Threads can use any of the following synchronization methods:
Note that mutexes, semaphores, and condition variables can be used between threads in the same or different processes, but that sleepons can be used only between threads in the same process (because the library has a mutex hidden in the process's address space).
As well as synchronization, threads can be scheduled (using a priority and a scheduling algorithm), and they'll automatically run on a single-processor box or an SMP box.
Whenever we talk about creating a process (mainly as a means of porting code from single-threaded implementations), we're really creating an address space with one thread running in it—that thread starts at main() or at fork() or vfork() depending on the function called.