Subject: Re: Synchronization with locks in kernel
To: None <ianzag@megasignal.com>
From: Ben Harris <bjh21@netbsd.org>
List: tech-kern
Date: 06/22/2003 15:01:19
In article <200306222007.38719.ianzag@megasignal.com> you write:
>So i want to block inside client's code waiting for some external
>asynchronous event [hardware interrupt in my case].
>
>I have tried to do this with tsleep()/wakeup() synchronization calls like
>this:
>
>--------
>void dev_interrupt_handler(void *aux) {
>    struct dev_softc *sc =3D aux;
>
>    wakeup(sc);
>}
>
>dev_do_something() {
>    struct dev_softc *sc = device_lookup().
>
>    dev_request_interrupt(sc);    /* 1 */
>    print("tralala\n");           /* 2 */
>    tsleep(sc);                   /* 3 */
>}
>--------
>
>...but [obviously] i do loose interrupts when interrupt is occured fast
>enough i.e. between points 1 and 3 so tsleep(sc) is blocked too late and
>for nothing.

The usual way around this is to block interrupts in that period, so you'd do
something like:

dev_do_something() {
    struct dev_softc *sc = device_lookup();
    int s;

    s = spldev();
    dev_request_interrupt(sc);
    printf("tralala\n");
    tsleep(sc);
    splx(s);
}

where spldev() is whatever spl*() function is correct for your device, which
depends on the level at which you established your interrupt handler. 
tsleep() handles saving and restoring the interrupt level in a way that
won't lose wakeup()s.

In the modern, SMP-capable world, you might want to use locks, but I'll
leave them to someone else to explain, as I've never written a device driver
using them.

-- 
Ben Harris                                                   <bjh21@netbsd.org>
Portmaster, NetBSD/acorn26           <URL:http://www.netbsd.org/Ports/acorn26/>