Is it safe to lock a mutex in a timer handler (kernel space)?
I have two kernel modules which read /write to the same I2C device:
- first module: launch a timer when loaded. Read I2C register under timer handler every 20 ms
- second module: read/write the same I2C register
I have seen many kernel crash (CPU 1 is freezed)
--> I suspect that when trying to unlock mutex under timer handler, kernel freezes Could you comfirm that ?
Interrupt handlers shouldn't use mutexes for locking. That is because if any code outside the ISR tries to hold the mutex, but before completing that operation, the ISR executes and then tries to hold the ISR, it may crash because the mutex will be in an undeterminate form.
Why can't I use a mutex, if I lock only from ISR and not from outside?
Mutexes are designed for threaded applications were a thread can be blocked until the other is in the critical section. Since your ISR isn't blockable, i.e. you can't pause it because the ISR itself will have to return in time by IRET.
What locking mechanism should I use in an ISR?
Spinlocks are generally safer in the ISR. But while locking and unlocking, you have to be sure to use atomic primitiives so that an ISR can't come in between and try acquire the lock when it was being locked by something else.
You could use a simple RW lock also where the readers can enter simultaneously. When a writer enters, it will wait for all the readers to exit, and will block any incoming readers by not letting go of the lock.
Related
What is Disadvantage of using mutex in interrupt context.Why spin lock is preferred here.
A Mutex will force the function to sleep if it's contended and sleeping is illegal when preemption is disabled or in interrupt context.
Many functions in the kernel sleep (ie. call schedule()) directly or
indirectly: you can never call them while holding a spinlock, or with
preemption disabled. This also means you need to be in user context:
calling them from an interrupt is illegal.
The following is worth reading...
https://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/c557.html
Theres a ton of information in that doc.
When a thread tries to acquire a mutex and if it does not succeed, either due to another thread having already acquired it or due to a context switch, the thread goes to sleep until been woken-up which is critical if used in an ISR.
Whereas when a thread fails to acquire a spin_lock, it continuously tries to acquire it, until it finally succeeds, thus avoiding sleeping in an ISR. Using spin_lock in the "top-half" is a common practice followed in writing Linux Device Driver Interrupt handlers.
Hence you should use a spin-lock instead!
What would happen if I use semaphore and mutex locks in interrupt context?
Normally semaphore is used in synchronization mechanism. What would happen if I use this one in an interrupt context?
I am working on a project on gpio pins and when interrupt happens, I have to send one signal in ISR. I am using spinlocks.
What would happen if I use semaphore and mutext in ISR?
Waiting in mutexes and semaphores are implemented using switching current task state to TASK_INTERRUPTIBLE/TASK_UNINTERRUPTIBLE and similar with futher call to schedule().
Calling schedule() with current task state differed from TASK_RUNNING leads to switching to another process. And if current refers to interrupt context, you will never return back to it, because scheduling can switch only to the process.
So, when you lock contended(that is, currently locked) semaphore/mutex in interrupt context, you just lost current execution "thread".
If you lock semaphore/mutex which is uncontended(currently not locked), execution will be correct except warning in system log about improper semaphore/mutex usage.
First of all sorry for a little bit ambiguity in Question... What I want to understand is the below scenario
Suppose porcess is running, it holds one lock, Now after acquiring the lock HW interrupt is generated, So How kernel will handle this situation, will it wait for lock ? if yes, what if the interrupt handler need to access that lock or the shared data protected by that lock in process ?
The Linux kernel has a few functions for acquiring spinlocks, to deal with issues like the one you're raising here. In particular, there is spin_lock_irq(), which disables interrupts (on the CPU the process is running on) and acquires the spinlock. This can be used when the code knows interrupts are enabled before the spinlock is acquired; in case the function might be called in different contexts, there is also spin_lock_irqsave(), which stashes away the current state of interrupts before disabling them, so that they can be reenabled by spin_unlock_irqrestore().
In any case, if a lock is used in both process and interrupt context (which is a good and very common design if there is data that needs to be shared between the contexts), then process context must disable interrupts (locally on the CPU it's running on) when acquiring the spinlock to avoid deadlocks. In fact, lockdep ("CONFIG_PROVE_LOCKING") will verify this and warn if a spinlock is used in a way that is susceptible to the "interrupt while process context holds a lock" deadlock.
Let me explain some basic properties of interrupt handler or bottom half.
A handler can’t transfer data to or from user space, because it doesn’t execute in the context of a process.
Handlers also cannot do anything that would sleep, such as calling wait_event, allocating memory with anything other than GFP_ATOMIC, or locking a semaphore
handlers cannot call schedule.
What i am trying to say is that Interrupt handler runs in atomic context. They can not sleep as they cannot be rescheduled. interrupts do not have a backing process context
The above is by design. You can do whatever you want in code, just be prepared for the consequences
Let us assume that you acquire a lock in interrupt handler(bad design).
When an interrupt occur the process saves its register on stack and start ISR. now after acquiring a lock you would be in a deadlock as their is no way ISR know what the process was doing.
The process will not be able to resume execution until it is done it with ISR
In a preemptive kernel the ISR and the process can be preempt but for a non-preemptive kernel you are dead.
I read this article http://www.linuxjournal.com/article/5833 to learn about spinlock. I try this to use it in my kernel driver.
Here is what my driver code needs to do:
In f1(), it will get the spin lock, and caller can call f2() will wait for the lock since the spin lock is not being unlock. The spin lock will be unlock in my interrupt handler (triggered by the HW).
void f1() {
spin_lock(&mylock);
// write hardware
REG_ADDR += FLAG_A;
}
void f2() {
spin_lock(&mylock);
//...
}
The hardware will send the application an interrupt and my interrupt handler will call spin_unlock(&mylock);
My question is if I call
f1()
f2() // i want this to block until the interrupt return saying setting REG_ADDR is done.
when I run this, I get an exception in kernel saying a deadlock " INFO: possible recursive locking detected"
How can I re-write my code so that kernel does not think I have a deadlock?
I want my driver code to wait until HW sends me an interrupt saying setting REG_ADDR is done.
Thank you.
First, since you'll be expecting to block while waiting for the interrupt, you shouldn't be using spinlocks to lock the hardware as you'll probably be holding the lock for a long time. Using a spinlock in this case will waste a lot of CPU cycles if that function is called frequently.
I would first use a mutex to lock access to the hardware register in question so other kernel threads can't simultaneously modify the register. A mutex is allowed to sleep so if it can't acquire the lock, the thread is able to go to sleep until it can.
Then, I'd use a wait queue to block the thread until the interrupt arrives and signals that the bit has finished setting.
Also, as an aside, I noticed you're trying to access your peripheral by using the following expression REG_ADDR += FLAG_A;. In the kernel, that's not the correct way to do it. It may seem to work but will break on some architectures. You should be using the read{b,w,l} and write{b,w,l} macros like
unsigned long reg;
reg = readl(REG_ADDR);
reg |= FLAG_A;
writel(reg, REG_ADDR);
where REG_ADDR is an address you obtained from ioremap.
I will agree with Michael that Spinlock, Semaphores, Mutex ( Or any other Locking Mechanisms) must be used when any of the resources(Memory/variable/piece of code) has the probability of getting shared among the kernel/user threads.
Instead of using any of the Locking primitives available I would suggest using other sleeping functionalities available in kernel like wait_event_interruptibleand wake_up. They are simple and easy to exploit them into your code. You can find its details and exploitation on net.
Imagine that a device function holds a spinlock to control access to the device. While the lock is held, the device issues an interrupt, which causes an interrupt handler to run. The interrupt handler, before accessing the device, must also obtain the lock.
Suppose that the interrupt handler executes in the same processor as the code that took out the lock originally.
Knowing that to hold spinlock disables preemption on the relevant processor, is it possible that the code that holds the spinlock be executed on another processor (because of preemption on this processor)? (We suppose that this is a SMP machine)
Is it possible that the code that holds the spinlock be executed on another processor (because of preemption on this processor)?
No, the code just keeps waiting for the interrupt handler to return.
Just use spin_lock_irq*(), or spin_lock_bh() if you also want to protect against softirqs/tasklets.