Interlocks sckbdevent() and sccngetch() with the low-level atomic semaphores. --- sys/dev/syscons/syscons.c.orig 2008-08-31 14:17:40.000000000 +0400 +++ sys/dev/syscons/syscons.c 2008-11-24 08:39:07.000000000 +0300 @@ -60,6 +60,7 @@ #include #include +#include #include #if defined(__sparc64__) || defined(__powerpc__) #include @@ -165,6 +166,13 @@ static int debugger; +/* + * Semaphore that uses for locking within syscons. As was noted by + * Bruce Evans, locks can't be accessed in the debugger mode, but + * debugger uses keyboard sometimes ;)) + */ +static int _syscons_semaphore; + /* prototypes */ static int sc_allocate_keyboard(sc_softc_t *sc, int unit); static int scvidprobe(int unit, int flags, int cons); @@ -609,7 +617,7 @@ { sc_softc_t *sc; struct tty *cur_tty; - int c, error = 0; + int c, error = 0, sem_owned = 0; size_t len; u_char *cp; @@ -631,12 +639,20 @@ goto done; } + /* + * Grab semaphore to notify others that we're doing our job. + */ + sem_owned = atomic_cmpset_acq_int(&_syscons_semaphore, 0, 1); + /* * Loop while there is still input to get from the keyboard. * I don't think this is nessesary, and it doesn't fix * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX + * + * If semaphore is already grabbed, don't poll. */ - while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) { + while (sem_owned && + (c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) { cur_tty = SC_DEV(sc, sc->cur_scp->index); if (!tty_opened(cur_tty)) @@ -677,6 +693,8 @@ sc->cur_scp->status |= MOUSE_HIDDEN; done: + if (sem_owned) + atomic_clear_int(&_syscons_semaphore, 1); mtx_unlock(&Giant); return (error); } @@ -1569,10 +1587,10 @@ scr_stat *scp; u_char *p; int cur_mode; - int s = spltty(); /* block sckbdevent and scrn_timer while we poll */ int c; - /* assert(sc_console != NULL) */ + if (!atomic_cmpset_acq_int(&_syscons_semaphore, 0, 1)) + return -1; /* * Stop the screen saver and update the screen if necessary. @@ -1583,12 +1601,13 @@ sccnupdate(scp); if (fkeycp < fkey.len) { - splx(s); - return fkey.str[fkeycp++]; + c = fkey.str[fkeycp++]; + atomic_clear_int(&_syscons_semaphore, 1); + return c; } if (scp->sc->kbd == NULL) { - splx(s); + atomic_clear_int(&_syscons_semaphore, 1); return -1; } @@ -1610,26 +1629,29 @@ scp->kbd_mode = cur_mode; kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); kbdd_disable(scp->sc->kbd); - splx(s); switch (KEYFLAGS(c)) { case 0: /* normal char */ - return KEYCHAR(c); + c = KEYCHAR(c); + break; case FKEY: /* function key */ p = kbdd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp); fkey.len = fkeycp; if ((p != NULL) && (fkey.len > 0)) { bcopy(p, fkey.str, fkey.len); fkeycp = 1; - return fkey.str[0]; + c = fkey.str[0]; } - return c; /* XXX */ + /* XXX */ + break; case NOKEY: case ERRKEY: default: - return -1; + c = -1; + break; } - /* NOT REACHED */ + atomic_clear_int(&_syscons_semaphore, 1); + return c; } static void