Re: doubt about interrupts and spinlocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>:
inline answers.

On Fri, Oct 24, 2014 at 8:04 AM, Oscar Salvador <osalvador.vilardaga@xxxxxxxxx> 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@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies



_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux