<div dir="ltr"><div><div><div><div><div><div><div><div>Hi,<br><br>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.<br></div>My doubt is about spinlocks are working together with interrupts.<br><br></div>As far I could understand:<br><br></div>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.<br></div>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).<br><br></div>A graphical example would be:<br><br>static int hardware_tx(struct net_device *dev) /* This is the function that the network subsystem calls when has a packet to transmit */<br>{<br>        struct rtl_t *rtl_p = netdev_priv(dev);<br>        int pkt_len = rtl8139_p-&gt;skb_d-&gt;len;<br>        unsigned long flags;<br><br>        spin_lock_irqsave(&amp;rtl_p-&gt;lock, flags);  /* We acquire a lock, disabling the interrupts in the local CPU */<br>        /*<br>                Do some private stuff<br>                Do some private stuff<br>                At some point an interrupt is raised, so we go to the handler <br>                Since i_handler has to spin, we continue here<br>                Do some private stuff<br>        */<br>        spin_unlock_irqsave(&amp;rtl_p-&gt;lock, flags); /* We are releasing the lock, and put the interrupts in the old state( in this case enabled)  */<br>                                                  /* 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? */<br><br>        return 0;<br>}<br><br><br>static irqreturn_t i_handler(int irq, void *dev_id)   /* This is the interrupt handler */<br>{<br>        struct rtl_t *rtl_p = netdev_priv(dev);<br><br>        /* Now we are on the handler */<br><br>        spin_lock(&amp;rtl8139_p-&gt;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*/<br>        /*<br>                Ok, hardware_tx released the lock, now we can continue<br>                Do some private stuff<br>                Do some private stuff<br>                Do some private stuff<br>        */<br>        spin_unlock(&amp;rtl_p-&gt;lock, flags); /* Lock released */<br>}<br><br><br></div>Hopefully now I explained it better.<br></div>Thank you very much<br><br></div>Kind regards<br><div><div><div><br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">2014-10-24 21:16 GMT+02:00 anish singh <span dir="ltr">&lt;<a href="mailto:anish198519851985@gmail.com" target="_blank">anish198519851985@gmail.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">inline answers.<div class="gmail_extra"><br><div class="gmail_quote"><span class="">On Fri, Oct 24, 2014 at 8:04 AM, Oscar Salvador <span dir="ltr">&lt;<a href="mailto:osalvador.vilardaga@gmail.com" target="_blank">osalvador.vilardaga@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi!<br><br>I have a doubt about interrupts and spin locks.<br>I&#39;m not sure if I&#39;m in the good way:<br><br>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.<br><br>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 ), <br>so if we have to lock the code we can do a spin_lock().<br>But with a spin_lock, even other CPU&#39;s can execute part of your code(code that is not part of the handler interrupt). <br>For example:<br><br>(this is an example in a network device driver)<br>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.<br><br>As far I could understand( I have read <a href="http://www.makelinux.net/ldd3/chp-5-sect-5" target="_blank">http://www.makelinux.net/ldd3/chp-5-sect-5</a> ), spin_lock_irqsave only disables the interrupts for the local cpu(where the code is executed), <br>so I think that another cpu took the handler interrupt.<br></div></blockquote></span><div>Yes this can happen and if you expect that the interrupt can come in other CPU then you should handle that as well.</div><div>Generally interrupts are disabled so you won&#39;t get any interrupt on other CPU if any cpu is currently handling the interrupt.</div><div>However your explained sceneraio happens for network packets and that is why kernel uses  softirq mechanism for network</div><div>packets. Read about softirq.</div><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">The problem is if I&#39;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&#39;m trying to keep safe.<br>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?<br></div></blockquote></span><div>Your question is not quite coherent. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><div dir="ltr"><br>Thank you very much<span><font color="#888888"><br>Oscar Salvador<br></font></span></div>
<br></span><span class="">_______________________________________________<br>
Kernelnewbies mailing list<br>
<a href="mailto:Kernelnewbies@kernelnewbies.org" target="_blank">Kernelnewbies@kernelnewbies.org</a><br>
<a href="http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies" target="_blank">http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies</a><br>
<br></span></blockquote></div><br></div></div>
</blockquote></div><br></div>