next up previous contents
Next: Reference of Practical Thread Up: Reference of Primitive Thread Previous: Interrupt Service Routines

Primitive Synchronization

# include  <ucr/ucr.h>
typedef spl_cookie_t;
extern "C" spl_cookie_t thread_splhi();
extern "C" spl_cookie_t thread_spl(spl_cookie_t cookie);
extern "C" void thread_pause();

At the most primitive level, uCR programs run as a bunch of cooperative threads interrupted by interrupt handlers. Everything runs on a single CPU. The most primitive form of synchronization available in this kind of environment is the ability of threads to block interrupts. A thread that has the CPU can block interrupts, then can be sure that no other thread will steal it away unless it explicitly reschedules.

The thread_splhi() function causes the CPU to raise its interrupt priority to the highest level. In other words, disable all maskable interrupts. The return value is a magic cookie that can be passed to thread_spl(cookie) to restore the current priority. The paradigm works like this:

foo() {
    // do some stuff
    spl_cookie_t cookie = thread_splhi();
    // do some stuff that must not be interrupted
    thread_spl(cookie);
}

This paradigm works well, and is general enough that functions can be coded this way and called by threads or interrupt handlers. The splhi/spl pairs can be nested arbitrarily as well. No interrupts or other threads will run between the thread_splhi() and thread_spl().

Note that other synchronization primitives in fact use this trick to protect their implementations. This means that they can be called within protected areas without breaking the protection, but remember that a thread blocked by some of the more sophisticated primitives may be preempted be explicit rescheduling, allowing interrupts to arrive when another thread is active. When the current thread resumes, interrupts will again be blocked. For example:

extern ISync sync;
spl_cookie_t cookie = thread_splhi();
// do some stuff
sync.sleep(&amp;flag);
// do more stuff
thread_spl(cookie);

Interrupts are blocked within the above protected section, except possibly during the sleep. Interrupts will be enabled during the sleep. This is actually a convenient feature, as the thread can wait in the sleep for an interesting interrupt to occur.

The thread_pause() function works much like the sigpause() function in POSIX operating systems: it pauses the CPU until an interrupt is received. thread_pause() is meant for use by the thread scheduler within uCR to stop the CPU when all threads block. It puts the processor in a low-power state, if supported, with interrupts enabled. When thread_pause() finishes, interrupts are restored.

It is unlikely that an application will need to use thread_pause(), but if you do use it, be careful to protect the code around it from interrupts. For example:

spl_cookie_t cookie = thread_splhi();
// do some stuff
while (i need to wait for an interrupt) thread_pause();
// do more stuff
thread_spl(cookie());

If you fail to protect the critical section from interrupts, the interrupt may come after the test and before the call to thread_pause(). After the interrupt handler finishes, the CPU will be paused and will not be awakened by the expected interrupt.

thread_pause() will stop the CPU, no matter what the state of other threads. If you want to suspend only the current thread, consider using thread_yield() instead.


next up previous contents
Next: Reference of Practical Thread Up: Reference of Primitive Thread Previous: Interrupt Service Routines
Stephen Williams
9/2/1997