doubt about interrupts and spinlocks

Oscar Salvador osalvador.vilardaga at gmail.com
Mon Oct 27 06:58:57 EDT 2014


Hi,

Sorry, I was a little bit confused on Friday, but I read about this topic
on the weekend and I think that now this is more clear for me.
My doubt is about spinlocks are working together with interrupts.

As far I could understand:

If you are working with a code that can handle and interrupt, and this
interrupt can hold a lock,  you must use spinlocks with irq version(
spin_lock_irqsave and spin_lock_irqrestore) in the functions that you need
to lock, otherwise, if you acquire a lock in CPU0, and then an interrupt is
raised in the same CPU0 and tries to acquire the same lock, we will have a
deadlock problem.
But if you acquire a lock disabling the IRQ in the CPU0, and then an
interrupt is raised at CPU1 and tries to acquire a lock, the interrupt will
spin till the lock is released in the other function(the function that
acquire the lock first).

A graphical example would be:

static int hardware_tx(struct net_device *dev) /* This is the function that
the network subsystem calls when has a packet to transmit */
{
        struct rtl_t *rtl_p = netdev_priv(dev);
        int pkt_len = rtl8139_p->skb_d->len;
        unsigned long flags;

        spin_lock_irqsave(&rtl_p->lock, flags);  /* We acquire a lock,
disabling the interrupts in the local CPU */
        /*
                Do some private stuff
                Do some private stuff
                At some point an interrupt is raised, so we go to the
handler
                Since i_handler has to spin, we continue here
                Do some private stuff
        */
        spin_unlock_irqsave(&rtl_p->lock, flags); /* We are releasing the
lock, and put the interrupts in the old state( in this case enabled)  */
                                                  /* This is safe since
kernel ensures that only one interrupt in the same line can be processed
at the same time, so since i_handler is executing, kernel it will not
execute it again, no? */

        return 0;
}


static irqreturn_t i_handler(int irq, void *dev_id)   /* This is the
interrupt handler */
{
        struct rtl_t *rtl_p = netdev_priv(dev);

        /* Now we are on the handler */

        spin_lock(&rtl8139_p->lock);   /* We try to acquire a lock, but we
can not since hardware_tx has already taken a lock, so we have to spin here
till hardware_tx finish his work*/
        /*
                Ok, hardware_tx released the lock, now we can continue
                Do some private stuff
                Do some private stuff
                Do some private stuff
        */
        spin_unlock(&rtl_p->lock, flags); /* Lock released */
}


Hopefully now I explained it better.
Thank you very much

Kind regards


2014-10-24 21:16 GMT+02:00 anish singh <anish198519851985 at gmail.com>:

> inline answers.
>
> On Fri, Oct 24, 2014 at 8:04 AM, Oscar Salvador <
> osalvador.vilardaga at gmail.com> wrote:
>
>> Hi!
>>
>> I have a doubt about interrupts and spin locks.
>> I'm not sure if I'm in the good way:
>>
>> When an interrupt is raised, the kernel (through do_IRQ and etc)
>> acknowledges the interrupt and locks this IRQ taking a spin lock, so any
>> other cpu can not handle this interrupt, and then the kernel executes the
>> handler, if there is a handler available for that interrupt.
>>
>> When we are on the handler interrupt , maybe we need to lock the cpu till
>> we finish( if we are in a network driver, may we need to process some TX/RX
>> packets ),
>> so if we have to lock the code we can do a spin_lock().
>> But with a spin_lock, even other CPU's can execute part of your code(code
>> that is not part of the handler interrupt).
>> For example:
>>
>> (this is an example in a network device driver)
>> The system has to transmit a packet, so network subsystem calls
>> ndo_start_xmit. Inside this function we take a lock disabling the
>> interrupts(spin_lock_irqsave) because we have to do some private things,
>> but suddenly an interrupt is raised and we go to the interrupt handler, we
>> take a spin_lock, we do some work (processing some RX/TX packets), and
>> exites from the interrupt handler, and then we come back to the
>> ndo_start_xmit when we were.
>>
>> As far I could understand( I have read
>> http://www.makelinux.net/ldd3/chp-5-sect-5 ), spin_lock_irqsave only
>> disables the interrupts for the local cpu(where the code is executed),
>> so I think that another cpu took the handler interrupt.
>>
> Yes this can happen and if you expect that the interrupt can come in other
> CPU then you should handle that as well.
> Generally interrupts are disabled so you won't get any interrupt on other
> CPU if any cpu is currently handling the interrupt.
> However your explained sceneraio happens for network packets and that is
> why kernel uses  softirq mechanism for network
> packets. Read about softirq.
>
>> The problem is if I'm working with irq disabled, because I have to handle
>> a private structure and suddenly interrupts is taking place, the interrupt
>> can manipulate the code that I'm trying to keep safe.
>> Is there any advice? Maybe that is happened because the code within my
>> critical section on ndo_start_xmit has to be atomic? Otherwise it can go to
>> sleep and I can lose my lock?
>>
> Your question is not quite coherent.
>
>>
>> Thank you very much
>> Oscar Salvador
>>
>> _______________________________________________
>> Kernelnewbies mailing list
>> Kernelnewbies at kernelnewbies.org
>> http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20141027/9ff859a7/attachment.html 


More information about the Kernelnewbies mailing list