To control access to data structures that are shared between
them, threads and processes use the standard POSIX
primitives of mutexes, condvars, and semaphores.
These work without change in an SMP system.
Many realtime systems also need to protect access to shared
data structures between an interrupt handler and the thread
that owns the handler. The traditional POSIX primitives used
between threads aren't available for use by an interrupt
handler. There are two solutions here:
- One is to remove all work from the interrupt handler and
do all the work at thread time instead. Given our fast
thread scheduling, this is a very viable solution.
- In a uniprocessor system running the QNX Neutrino RTOS,
an interrupt handler may preempt a thread, but a thread will
never preempt an interrupt handler. This allows the thread to
protect itself from the interrupt handler by disabling and enabling
interrupts for very brief periods of time.
The thread on a non-SMP system protects itself with code of
the form:
InterruptDisable()
// critical section
InterruptEnable()
Or:
InterruptMask(intr)
// critical section
InterruptUnmask(intr)
Unfortunately, this code will fail on an SMP system since
the thread may be running on one processor while the
interrupt handler is concurrently running on another
processor!
One solution would be to lock the thread to a particular
processor (see
Bound Multiprocessing (BMP),
later in this chapter).
A better solution would be to use a new exclusion lock
available to both the thread and the interrupt handler. This
is provided by the following primitives, which work on both
uniprocessor and SMP machines:
- InterruptLock(intrspin_t* spinlock )
- Attempt to acquire a spinlock, a variable
shared between the interrupt handler and thread. The code
will spin in a tight loop until the lock is acquired. After
disabling interrupts, the code will acquire the lock (if it
was acquired by a thread). The lock must be
released as soon as possible (typically within a few lines of C
code without any loops).
- InterruptUnlock(intrspin_t* spinlock )
- Release a lock and reenable interrupts.
On a non-SMP system, there's no need for a spinlock.
For more information, see the
Multicore Processing
chapter of the QNX Neutrino Programmer's Guide.