[Mesa-dev] [PATCH kmscube] Init and clean up VT settings

Kristian H. Kristensen hoegsberg at gmail.com
Sat Dec 2 06:08:48 UTC 2017


This puts VT input into raw (unbuffered) mode so that we can detect
single key strokes. Also uses KD_GRAPHICS mode so that fbcon gets
restored properly on exit and inhibits VT switching since we don't
properly get/set drm master. Finally, handle signals and clean up if
we catch one.
---
 common.c     | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 common.h     |  6 +++++
 configure.ac |  3 +++
 drm-atomic.c |  2 +-
 drm-legacy.c |  2 +-
 kmscube.c    |  3 +++
 6 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/common.c b/common.c
index b76c994..c495187 100644
--- a/common.c
+++ b/common.c
@@ -24,10 +24,20 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
+#include <signal.h>
+#include <termios.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/major.h>
 
 #include "common.h"
 
@@ -288,3 +298,79 @@ int link_program(unsigned program)
 
 	return 0;
 }
+
+static struct termios save_tio;
+
+static void restore_vt(void)
+{
+	struct vt_mode mode = { .mode = VT_AUTO };
+	ioctl(STDIN_FILENO, VT_SETMODE, &mode);
+
+	tcsetattr(STDIN_FILENO, TCSANOW, &save_tio);
+	ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT);
+}
+
+static void handle_signal(int sig)
+{
+	restore_vt();
+
+	raise(sig);
+}
+
+int init_vt(void)
+{
+	struct termios tio;
+	struct stat buf;
+	int ret;
+
+	/* If we're not on a VT, we're probably logged in as root over
+	 * ssh. Skip all this then. */
+	ret = fstat(STDIN_FILENO, &buf);
+	if (ret == -1 || major(buf.st_rdev) != TTY_MAJOR)
+		return 0;
+
+	/* First, save term io setting so we can restore properly. */
+	tcgetattr(STDIN_FILENO, &save_tio);
+
+	/* We don't drop drm master, so block VT switching while we're
+	 * running. Otherwise, switching to X on another VT will crash X when it
+	 * fails to get drm master. */
+	struct vt_mode mode = { .mode = VT_PROCESS, .relsig = 0, .acqsig = 0 };
+	ret = ioctl(STDIN_FILENO, VT_SETMODE, &mode);
+	if (ret == -1) {
+		printf("failed to take control of vt handling\n");
+		return -1;
+	}
+
+	/* Set KD_GRAPHICS to disable fbcon while we render. */
+	ret = ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS);
+	if (ret == -1) {
+		printf("failed to switch console to graphics mode\n");
+		return -1;
+	}
+
+	atexit(restore_vt);
+
+	/* Set console input to raw mode. */
+	tio = save_tio;
+	tio.c_lflag &= ~(ICANON | ECHO);
+	tcsetattr(STDIN_FILENO, TCSANOW, &tio);
+
+	/* Restore console on SIGINT and friends. */
+	struct sigaction act = {
+		.sa_handler = handle_signal,
+		.sa_flags = SA_RESETHAND
+	};
+	sigaction(SIGINT, &act, NULL);
+	sigaction(SIGSEGV, &act, NULL);
+	sigaction(SIGABRT, &act, NULL);
+
+	return 0;
+}
+
+bool key_pressed(void)
+{
+	struct pollfd pfd[1] = { { .fd = 0, .events = POLLIN } };
+
+	return poll(pfd, 1, 0) == 1;
+}
diff --git a/common.h b/common.h
index 11ec26e..e6a3c93 100644
--- a/common.h
+++ b/common.h
@@ -24,6 +24,8 @@
 #ifndef _COMMON_H
 #define _COMMON_H
 
+#include <stdbool.h>
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <EGL/egl.h>
@@ -130,4 +132,8 @@ init_cube_video(const struct gbm *gbm, const char *video)
 }
 #endif
 
+int init_vt(void);
+bool key_pressed(void);
+
+
 #endif /* _COMMON_H */
diff --git a/configure.ac b/configure.ac
index 8397f7b..3ee11ed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,9 @@ AM_INIT_AUTOMAKE([foreign dist-bzip2])
 
 AC_PROG_CC
 
+# For sigaction
+AC_USE_SYSTEM_EXTENSIONS
+
 # Enable quiet compiles on automake 1.11.
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
diff --git a/drm-atomic.c b/drm-atomic.c
index 82531d3..4c0b16e 100644
--- a/drm-atomic.c
+++ b/drm-atomic.c
@@ -191,7 +191,7 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl)
 	/* Allow a modeset change for the first commit only. */
 	flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 
-	while (1) {
+	while (!key_pressed()) {
 		struct gbm_bo *next_bo;
 		EGLSyncKHR gpu_fence = NULL;   /* out-fence from gpu, in-fence to kms */
 		EGLSyncKHR kms_fence = NULL;   /* in-fence to gpu, out-fence from kms */
diff --git a/drm-legacy.c b/drm-legacy.c
index a0b419a..d3a9391 100644
--- a/drm-legacy.c
+++ b/drm-legacy.c
@@ -73,7 +73,7 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl)
 		return ret;
 	}
 
-	while (1) {
+	while (!key_pressed()) {
 		struct gbm_bo *next_bo;
 		int waiting_for_flip = 1;
 
diff --git a/kmscube.c b/kmscube.c
index 3a2c4dd..4615430 100644
--- a/kmscube.c
+++ b/kmscube.c
@@ -153,5 +153,8 @@ int main(int argc, char *argv[])
 	glClearColor(0.5, 0.5, 0.5, 1.0);
 	glClear(GL_COLOR_BUFFER_BIT);
 
+	if (init_vt())
+		return -1;
+
 	return drm->run(gbm, egl);
 }
-- 
2.14.3



More information about the mesa-dev mailing list