Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Aug 2016 18:59:24 +0000 (UTC)
From:      Bruce Evans <bde@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r304773 - head/sys/dev/syscons
Message-ID:  <201608241859.u7OIxOEj067818@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bde
Date: Wed Aug 24 18:59:24 2016
New Revision: 304773
URL: https://svnweb.freebsd.org/changeset/base/304773

Log:
  Flesh out the state and flags args to sccnopen().  Set state flags to
  indicate (potentially partial) success of the open.  Use these to
  decide what to close in sccnclose().  Only grab/ungrab use open/close
  so far.
  
  Add a per-sc variable to count successful keyboard opens and use
  this instead of the grab count to decide if the keyboad state has
  been switched.
  
  Start fixing the locking by using atomic ops for the most important
  counter -- the grab level one.  Other racy counting will eventually
  be fixed by normal mutex or kdb locking in most cases.
  
  Use a 2-entry per-sc stack of states for grabbing.  2 is just enough
  to debug grabbing, e.g., for gets().  gets() grabs once and might not
  be able to do a full (or any) state switch.  ddb grabs again and has
  a better chance of doing a full state switch and needs a place to
  stack the previous state.  For more than 3 levels, grabbing just
  changes the count.  Console drivers should try to switch on every i/o
  in case lower levels of nesting failed to switch but the current level
  succeeds, but then the switch (back) must be completed on every i/o
  and this flaps the state unless the switch is null.  The main point
  of grabbing is to make it null quite often.  Syscons grabbing also
  does a carefully chosen screen focus that is not done on every i/o.
  
  Add a large comment about grabbing.
  
  Restore some small lost comments.

Modified:
  head/sys/dev/syscons/syscons.c
  head/sys/dev/syscons/syscons.h

Modified: head/sys/dev/syscons/syscons.c
==============================================================================
--- head/sys/dev/syscons/syscons.c	Wed Aug 24 17:45:11 2016	(r304772)
+++ head/sys/dev/syscons/syscons.c	Wed Aug 24 18:59:24 2016	(r304773)
@@ -79,8 +79,6 @@ __FBSDID("$FreeBSD$");
 #include <dev/fb/splashreg.h>
 #include <dev/syscons/syscons.h>
 
-struct sc_cnstate;		/* not used yet */
-
 #define COLD 0
 #define WARM 1
 
@@ -1655,7 +1653,13 @@ sccnopen(sc_softc_t *sc, struct sc_cnsta
 {
     int kbd_mode;
 
-    if (sc->kbd == NULL)
+    /* assert(sc_console_unit >= 0) */
+
+    sp->kbd_opened = FALSE;
+    sp->scr_opened = FALSE;
+
+    /* Opening the keyboard is optional. */
+    if (!(flags & 1) || sc->kbd == NULL)
 	goto over_keyboard;
 
     /*
@@ -1667,48 +1671,79 @@ sccnopen(sc_softc_t *sc, struct sc_cnsta
     /* Switch the keyboard to console mode (K_XLATE, polled) on all scp's. */
     kbd_mode = K_XLATE;
     (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&kbd_mode);
+    sc->kbd_open_level++;
     kbdd_poll(sc->kbd, TRUE);
+
+    sp->kbd_opened = TRUE;
 over_keyboard: ;
 
+    /* The screen is opened iff locking it succeeds. */
+    sp->scr_opened = TRUE;
+
+    /* The screen switch is optional. */
+    if (!(flags & 2))
+	return;
+
+    /* try to switch to the kernel console screen */
     if (!cold &&
 	sc->cur_scp->index != sc_console->index &&
 	sc->cur_scp->smode.mode == VT_AUTO &&
 	sc_console->smode.mode == VT_AUTO)
 	    sc_switch_scr(sc, sc_console->index);
-
 }
 
 static void
 sccnclose(sc_softc_t *sc, struct sc_cnstate *sp)
 {
-    if (sc->kbd == NULL)
+    sp->scr_opened = FALSE;
+
+    if (!sp->kbd_opened)
 	return;
 
     /* Restore keyboard mode (for the current, possibly-changed scp). */
     kbdd_poll(sc->kbd, FALSE);
-    (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode);
+    if (--sc->kbd_open_level == 0)
+	(void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode);
 
     kbdd_disable(sc->kbd);
+    sp->kbd_opened = FALSE;
 }
 
+/*
+ * Grabbing switches the screen and keyboard focus to sc_console and the
+ * keyboard mode to (K_XLATE, polled).  Only switching to polled mode is
+ * essential (for preventing the interrupt handler from eating input
+ * between polls).  Focus is part of the UI, and the other switches are
+ * work just was well when they are done on every entry and exit.
+ *
+ * Screen switches while grabbed are supported, and to maintain focus for
+ * this ungrabbing and closing only restore the polling state and then
+ * the keyboard mode if on the original screen.
+ */
+
 static void
 sc_cngrab(struct consdev *cp)
 {
     sc_softc_t *sc;
+    int lev;
 
     sc = sc_console->sc;
-    if (sc->grab_level++ == 0)
-	sccnopen(sc, NULL, 0);
+    lev = atomic_fetchadd_int(&sc->grab_level, 1);
+    if (lev >= 0 || lev < 2)
+	sccnopen(sc, &sc->grab_state[lev], 1 | 2);
 }
 
 static void
 sc_cnungrab(struct consdev *cp)
 {
     sc_softc_t *sc;
+    int lev;
 
     sc = sc_console->sc;
-    if (--sc->grab_level == 0)
-	sccnclose(sc, NULL);
+    lev = atomic_load_acq_int(&sc->grab_level) - 1;
+    if (lev >= 0 || lev < 2)
+	sccnclose(sc, &sc->grab_state[lev]);
+    atomic_add_int(&sc->grab_level, -1);
 }
 
 static void
@@ -2681,7 +2716,7 @@ exchange_scr(sc_softc_t *sc)
     sc_set_border(scp, scp->border);
 
     /* set up the keyboard for the new screen */
-    if (sc->grab_level == 0 && sc->old_scp->kbd_mode != scp->kbd_mode)
+    if (sc->kbd_open_level == 0 && sc->old_scp->kbd_mode != scp->kbd_mode)
 	(void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
     update_kbd_state(scp, scp->status, LOCK_MASK);
 
@@ -3426,7 +3461,7 @@ next_code:
     if (!(flags & SCGETC_CN))
 	random_harvest_queue(&c, sizeof(c), 1, RANDOM_KEYBOARD);
 
-    if (sc->grab_level == 0 && scp->kbd_mode != K_XLATE)
+    if (sc->kbd_open_level == 0 && scp->kbd_mode != K_XLATE)
 	return KEYCHAR(c);
 
     /* if scroll-lock pressed allow history browsing */

Modified: head/sys/dev/syscons/syscons.h
==============================================================================
--- head/sys/dev/syscons/syscons.h	Wed Aug 24 17:45:11 2016	(r304772)
+++ head/sys/dev/syscons/syscons.h	Wed Aug 24 18:59:24 2016	(r304773)
@@ -188,6 +188,11 @@ struct video_adapter;
 struct scr_stat;
 struct tty;
 
+struct sc_cnstate {
+	u_char		kbd_opened;
+	u_char		scr_opened;
+};
+
 typedef struct sc_softc {
 	int		unit;			/* unit # */
 	int		config;			/* configuration flags */
@@ -231,6 +236,9 @@ typedef struct sc_softc {
 	char        	write_in_progress;
 	char        	blink_in_progress;
 	int		grab_level;
+	/* 2 is just enough for kdb to grab for stepping normal grabbing: */
+	struct sc_cnstate grab_state[2];
+	int		kbd_open_level;
 	struct mtx	scr_lock;		/* mutex for sc_puts() */
 	struct mtx	video_mtx;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608241859.u7OIxOEj067818>