Wednesday, October 20, 2010

Things to know of spinlocks

Spin locks can be used in interrupt handlers, whereas semaphores cannot be used because they sleep
If a lock is used in an interrupt handler, you must also disable local interrupts (interrupt requests on the current processor) before obtaining the lock

So the pseudo code of spin lock

{
Disable preempt()
acquire_lock()
}

If used in ISR
{
Disable interrupts()
spin lock()
//critical region
spin_unlock()
}

OR

{
spinlock_t mr_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;

spin_lock_irqsave(&mr_lock, flags);
/* critical region ... */
spin_unlock_irqrestore(&mr_lock, flags);


}

The fact that a contended spin lock causes threads to spin (essentially wasting processor time) while waiting for the lock to become available is important. This behavior is the point of the spin lock. It is not wise to hold a spin lock for a long time. This is the nature of the spin lock: a lightweight single-holder lock that should be held for short durations. An alternative behavior when the lock is contended is to put the current thread to sleep and wake it up when it becomes available. Then the processor can go off and execute other code. This incurs a bit of overhead most notably the two context switches required to switch out of and back into the blocking thread, which is certainly a lot more code than the handful of lines used to implement a spin lock. Therefore, it is wise to hold spin locks for less than the duration of two context switches. Because most of us have better things to do than measure context switches, just try to hold the lock as little time as possible[1]. The semaphores provide a lock that makes the waiting thread sleep, rather than spin, when contended.

Method
Description

spin_lock()
Acquires given lock

spin_lock_irq()
Disables local interrupts and acquires given lock

spin_lock_irqsave()
Saves current state of local interrupts, disables local interrupts, and acquires given lock

spin_unlock()
Releases given lock

spin_unlock_irq()
Releases given lock and enables local interrupts

spin_unlock_irqrestore()
Releases given lock and restores local interrupts to given previous state

spin_lock_init()
Dynamically initializes given spinlock_t

spin_trylock()
Tries to acquire given lock; if unavailable, returns nonzero

spin_is_locked()
Returns nonzero if the given lock is currently acquired, otherwise it returns zero


certain locking precautions must be taken when working with bottom halves. The function spin_lock_bh() obtains the given lock and disables all bottom halves. The function spin_unlock_bh() performs the inverse.

Because a bottom half may preempt process context code, if data is shared between a bottom half process context, you must protect the data in process context with both a lock and the disabling of bottom halves. Likewise, because an interrupt handler may preempt a bottom half, if data is shared between an interrupt handler and a bottom half, you must both obtain the appropriate lock and disable interrupts.

No comments:

Post a Comment