[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