Saturday 21 July 2018

Spin Lock

In Mutex concept, when thread is trying to lock or acquire the Mutex which is not available then that thread will go to sleep until that Mutex is available. Whereas in Spinlock it is different. The spinlock is a very simple single-holder lock. If a process attempts to acquire a spinlock and it is unavailable, the process will keep trying (spinning) until it can acquire the lock. This simplicity creates a small and fast lock.




Initialize

We can initialize Spinlock in two ways.
  1. Static Method
  2. Dynamic Method

Static Method

You can statically initialize a Spinlock using the macro given below.


The macro given above will create spinlock_t variable in the name of  and initialize to UNLOCKED STATE. Take a look at the expansion of DEFINE_SPINLOCK below.


Dynamic Method

If you want to initialize dynamically you can use the method as given below.


You can use any one of the methods.

Locking between User context

Lock:
spin_lock(spinlock_t *lock)
This will take the lock if it is free, otherwise it’ll spin until that lock is free (Keep trying).
Try Lock:
spin_trylock(spinlock_t *lock)
Locks the spinlock if it is not already locked. If unable to obtain the lock it exits with an error and do not spin. It returns non-zero if obtains the lock otherwise returns zero.
Unlock:
spin_unlock(spinlock_t *lock)
It does the reverse of lock. It will unlock which is locked by above call.
Checking Lock:
spin_is_locked(spinlock_t *lock)
This is used to check whether the lock is available or not. It returns non-zero if the lock is currently acquired. otherwise returns zero.
//Thread 1
int thread_function1(void *pv)
{
    while(!kthread_should_stop()) {
        spin_lock(&etx_spinlock);
        etx_global_variable++;
        printk(KERN_INFO "In EmbeTronicX Thread Function1 %lu\n", etx_global_variable);
        spin_unlock(&etx_spinlock);
        msleep(1000);
    }
    return 0;
}
 
//Thread 2
int thread_function2(void *pv)
{  
    while(!kthread_should_stop()) {
        spin_lock(&etx_spinlock);
        etx_global_variable++;
        printk(KERN_INFO "In EmbeTronicX Thread Function2 %lu\n", etx_global_variable);
        spin_unlock(&etx_spinlock);
        msleep(1000);
    }
    return 0;
}

Locking between User context and Bottom Halves

If you share data with a bottom half and user context (like Kernel Thread), then this approach will be useful.
Lock:
spin_lock_bh(spinlock_t *lock)
It disables soft interrupts on that CPU, then grabs the lock. This has the effect of preventing softirqs, tasklets, and bottom halves from running on the local CPU. Here the suffix ‘_bh‘ refers to “Bottom Halves“.
Unlock:
spin_unlock_bh(spinlock_t *lock)

Locking between Hard IRQ and Bottom Halves)

If you share data between Hardware ISR and Bottom halves then you have to disable the IRQ before lock. Because, the bottom halves processing can be interrupted by a hardware interrupt. So this will be used in that scenario.
Lock:
spin_lock_irq(spinlock_t *lock)
This will disable interrupts on that cpu, then grab the lock.
Unlock:
spin_unlock_irq(spinlock_t *lock)

No comments:

Post a Comment