Introduce a spinlock for synchronizing access to the video output hardware

in syscons.  This replaces a simple access semaphore that was assumed to be
protected by Giant but often was not.  If two threads that were otherwise
SMP-safe called printf at the same time, there was a high likelyhood that
the semaphore would get corrupted and result in a permanently frozen video
console.  This is similar to what is already done in the serial console
drivers.
This commit is contained in:
Scott Long 2006-09-13 15:48:15 +00:00
parent 7ca6b7823d
commit 988129b824
4 changed files with 39 additions and 19 deletions

View File

@ -178,13 +178,13 @@ sc_draw_mouse_image(scr_stat *scp)
if (ISGRAPHSC(scp))
return;
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
scp->mouse_oldpos = scp->mouse_pos;
scp->mouse_oldxpos = scp->mouse_xpos;
scp->mouse_oldypos = scp->mouse_ypos;
scp->status |= MOUSE_VISIBLE;
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
void
@ -196,7 +196,7 @@ sc_remove_mouse_image(scr_stat *scp)
if (ISGRAPHSC(scp))
return;
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->draw_mouse)(scp,
(scp->mouse_oldpos%scp->xsize + scp->xoff)
* scp->font_width,
@ -217,7 +217,7 @@ sc_remove_mouse_image(scr_stat *scp)
}
#endif /* PC98 */
scp->status &= ~MOUSE_VISIBLE;
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
int

View File

@ -1578,7 +1578,7 @@ sccnupdate(scr_stat *scp)
{
/* this is a cut-down version of scrn_timer()... */
if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress)
if (scp->sc->font_loading_in_progress)
return;
if (debugger > 0 || panicstr || shutdown_in_progress) {
@ -1628,7 +1628,7 @@ scrn_timer(void *arg)
return;
/* don't do anything when we are performing some I/O operations */
if (sc->font_loading_in_progress || sc->videoio_in_progress) {
if (sc->font_loading_in_progress) {
if (again)
timeout(scrn_timer, sc, hz / 10);
return;
@ -1722,7 +1722,7 @@ scrn_update(scr_stat *scp, int show_cursor)
/* assert(scp == scp->sc->cur_scp) */
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
#ifndef SC_NO_CUTPASTE
/* remove the previous mouse pointer image if necessary */
@ -1792,7 +1792,7 @@ scrn_update(scr_stat *scp, int show_cursor)
if (!show_cursor) {
scp->end = 0;
scp->start = scp->xsize*scp->ysize - 1;
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
return;
}
@ -1831,7 +1831,7 @@ scrn_update(scr_stat *scp, int show_cursor)
scp->end = 0;
scp->start = scp->xsize*scp->ysize - 1;
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
#ifdef DEV_SPLASH
@ -2094,7 +2094,7 @@ sc_switch_scr(sc_softc_t *sc, u_int next_scr)
/* delay switch if the screen is blanked or being updated */
if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
|| sc->blink_in_progress || sc->videoio_in_progress) {
|| sc->blink_in_progress) {
sc->delayed_next_scr = next_scr + 1;
sc_touch_scrn_saver();
DPRINTF(5, ("switch delayed\n"));
@ -2452,23 +2452,23 @@ void
sc_draw_cursor_image(scr_stat *scp)
{
/* assert(scp == scp->sc->cur_scp); */
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
scp->curs_attr.flags & CONS_BLINK_CURSOR, TRUE,
sc_inside_cutmark(scp, scp->cursor_pos));
scp->cursor_oldpos = scp->cursor_pos;
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
void
sc_remove_cursor_image(scr_stat *scp)
{
/* assert(scp == scp->sc->cur_scp); */
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
scp->curs_attr.flags & CONS_BLINK_CURSOR, FALSE,
sc_inside_cutmark(scp, scp->cursor_oldpos));
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
static void
@ -2499,10 +2499,10 @@ sc_set_cursor_image(scr_stat *scp)
}
/* assert(scp == scp->sc->cur_scp); */
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->set_cursor)(scp, scp->curs_attr.base, scp->curs_attr.height,
scp->curs_attr.flags & CONS_BLINK_CURSOR);
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
static void
@ -2606,6 +2606,9 @@ scinit(int unit, int flags)
* disappeared...
*/
sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
if ((sc->flags & SC_INIT_DONE) == 0)
SC_VIDEO_LOCKINIT(sc);
adp = NULL;
if (sc->adapter >= 0) {
vid_release(sc->adp, (void *)&sc->adapter);
@ -3458,9 +3461,9 @@ set_mode(scr_stat *scp)
void
sc_set_border(scr_stat *scp, int color)
{
++scp->sc->videoio_in_progress;
SC_VIDEO_LOCK(scp->sc);
(*scp->rndr->draw_border)(scp, color);
--scp->sc->videoio_in_progress;
SC_VIDEO_UNLOCK(scp->sc);
}
#ifndef SC_NO_FONT_LOADING

View File

@ -34,6 +34,9 @@
#ifndef _DEV_SYSCONS_SYSCONS_H_
#define _DEV_SYSCONS_SYSCONS_H_
#include <sys/lock.h>
#include <sys/mutex.h>
/* machine-dependent part of the header */
#ifdef PC98
@ -225,9 +228,9 @@ typedef struct sc_softc {
char font_loading_in_progress;
char switch_in_progress;
char videoio_in_progress;
char write_in_progress;
char blink_in_progress;
struct mtx video_mtx;
long scrn_time_stamp;
@ -532,6 +535,19 @@ typedef struct {
#define kbd_poll(kbd, on) \
(*kbdsw[(kbd)->kb_index]->poll)((kbd), (on))
#define SC_VIDEO_LOCKINIT(sc) \
mtx_init(&(sc)->video_mtx, "syscons video lock", NULL,MTX_SPIN);
#define SC_VIDEO_LOCK(sc) \
do { \
if (!cold) \
mtx_lock_spin(&(sc)->video_mtx); \
} while(0)
#define SC_VIDEO_UNLOCK(sc) \
do { \
if (!cold) \
mtx_unlock_spin(&(sc)->video_mtx); \
} while(0)
/* syscons.c */
extern int (*sc_user_ioctl)(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td);

View File

@ -393,6 +393,7 @@ static struct witness_order_list_entry order_lists[] = {
{ "td_contested", &lock_class_mtx_spin },
{ "callout", &lock_class_mtx_spin },
{ "entropy harvest mutex", &lock_class_mtx_spin },
{ "syscons video lock", &lock_class_mtx_spin },
/*
* leaf locks
*/