[mutter/wip/wayland] wayland: Run idle loop on vt switch



commit 52fb723bf9f5819f43d2ec1c8097c109d513e23a
Author: Robert Bragg <robert linux intel com>
Date:   Tue Jan 24 22:55:50 2012 +0000

    wayland: Run idle loop on vt switch
    
    While we are switched away from the mutter vt we now run a transient
    mainloop that only listens for the SIGUSR signals that get issued when
    entering or leaving the vt. This ensures that no clutter rendering is
    attempted and that we stop servicing wayland clients.

 src/wayland/meta-tty.c             |   32 +------
 src/wayland/meta-tty.h             |   18 ++---
 src/wayland/meta-wayland-private.h |    2 +
 src/wayland/meta-wayland.c         |  166 +++++++++++++++++++++++++++++++++---
 4 files changed, 166 insertions(+), 52 deletions(-)
---
diff --git a/src/wayland/meta-tty.c b/src/wayland/meta-tty.c
index 2c4360a..13d4604 100644
--- a/src/wayland/meta-tty.c
+++ b/src/wayland/meta-tty.c
@@ -37,37 +37,24 @@
 #include "meta-tty.h"
 
 struct tty {
-	MetaWaylandCompositor *compositor;
 	int fd;
 	struct termios terminal_attributes;
 
 	struct wl_event_source *input_source;
 	struct wl_event_source *enter_vt_source;
 	struct wl_event_source *leave_vt_source;
-	MetaTTYVTFunc vt_func;
 };
 
-static int on_enter_vt(int signal_number, void *data)
+void
+meta_tty_enter_vt (struct tty *tty)
 {
-	struct tty *tty = data;
-
 	ioctl(tty->fd, VT_RELDISP, VT_ACKACQ);
-
-	tty->vt_func(tty->compositor, META_TTY_VT_EVENT_ENTER);
-
-	return 1;
 }
 
-static int
-on_leave_vt(int signal_number, void *data)
+void
+meta_tty_leave_vt (struct tty *tty)
 {
-	struct tty *tty = data;
-
-	tty->vt_func(tty->compositor, META_TTY_VT_EVENT_LEAVE);
-
 	ioctl(tty->fd, VT_RELDISP, 1);
-
-	return 1;
 }
 
 static int
@@ -118,9 +105,7 @@ try_open_vt(void)
 }
 
 struct tty *
-meta_tty_create (MetaWaylandCompositor *compositor,
-                 MetaTTYVTFunc vt_func,
-                 int tty_nr)
+meta_tty_create (MetaWaylandCompositor *compositor, int tty_nr)
 {
 	struct termios raw_attributes;
 	struct vt_mode mode = { 0 };
@@ -135,8 +120,6 @@ meta_tty_create (MetaWaylandCompositor *compositor,
 		return NULL;
 
 	memset(tty, 0, sizeof *tty);
-	tty->compositor = compositor;
-	tty->vt_func = vt_func;
 	if (tty_nr > 0) {
 		snprintf(filename, sizeof filename, "/dev/tty%d", tty_nr);
 		g_warning ("compositor: using %s\n", filename);
@@ -190,11 +173,6 @@ meta_tty_create (MetaWaylandCompositor *compositor,
 		return NULL;
 	}
 
-	tty->leave_vt_source =
-		wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, tty);
-	tty->enter_vt_source =
-		wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, tty);
-
 	return tty;
 }
 
diff --git a/src/wayland/meta-tty.h b/src/wayland/meta-tty.h
index 42e24f6..f7d3b15 100644
--- a/src/wayland/meta-tty.h
+++ b/src/wayland/meta-tty.h
@@ -24,22 +24,18 @@
 
 G_BEGIN_DECLS
 
-typedef enum {
-  META_TTY_VT_EVENT_ENTER,
-  META_TTY_VT_EVENT_LEAVE
-} MetaTTYVTEvent;
-
-typedef void (*MetaTTYVTFunc)(MetaWaylandCompositor *compositor,
-                              MetaTTYVTEvent event);
-
 struct tty *
-meta_tty_create (MetaWaylandCompositor *compositor,
-                 MetaTTYVTFunc callback,
-                 int tty_nr);
+meta_tty_create (MetaWaylandCompositor *compositor, int tty_nr);
 
 void
 meta_tty_destroy(struct tty *tty);
 
+void
+meta_tty_enter_vt (struct tty *tty);
+
+void
+meta_tty_leave_vt (struct tty *tty);
+
 G_END_DECLS
 
 #endif /* META_TTY_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 24576b8..52a9ef3 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -107,6 +107,8 @@ struct _MetaWaylandCompositor
   struct wl_shm *wayland_shm;
   struct wl_event_loop *wayland_loop;
   GMainLoop *init_loop;
+  GIOChannel *sigusr_channel;
+  GMainLoop *sigusr_loop;
   ClutterActor *stage;
   int drm_fd;
   struct tty *tty;
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index c90c0c6..83d5687 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -55,7 +55,12 @@
 #include <meta/main.h>
 #include "frame.h"
 
+static gboolean on_sigusr_channel_io (GIOChannel *channel,
+                                      GIOCondition condition,
+                                      void *user_data);
+
 static MetaWaylandCompositor _meta_wayland_compositor;
+static int sigusr_pipe_fds[2];
 
 MetaWaylandCompositor *
 meta_wayland_compositor_get_default (void)
@@ -1348,23 +1353,126 @@ event_cb (ClutterActor *stage,
 }
 
 static void
-vt_func (MetaWaylandCompositor *compositor,
-         MetaTTYVTEvent event)
+on_vt_enter (MetaWaylandCompositor *compositor)
+{
+  meta_tty_enter_vt (compositor->tty);
+
+  if (drmSetMaster (compositor->drm_fd))
+    g_critical ("failed to set master: %m\n");
+  clutter_actor_queue_redraw (compositor->stage);
+  clutter_evdev_reclaim_devices ();
+
+  /* While we are switched away from mutter we run a special mainloop
+   * that only responds to the sigusr signals we get when switching
+   * vts so now that we have regained focus we can quit that loop...
+   */
+
+  if (compositor->sigusr_loop)
+    g_main_loop_quit (compositor->sigusr_loop);
+}
+
+static GSource *
+create_sigusr_source (MetaWaylandCompositor *compositor)
+{
+  GSource *source = g_io_create_watch (compositor->sigusr_channel, G_IO_IN);
+  g_source_set_callback (source, (GSourceFunc)on_sigusr_channel_io,
+                         compositor, NULL);
+  return source;
+}
+
+static void
+on_vt_leave (MetaWaylandCompositor *compositor)
+{
+  GMainContext *tmp_context = g_main_context_new ();
+  GSource *source;
+
+  clutter_evdev_release_devices ();
+  if (drmDropMaster(compositor->drm_fd) < 0)
+    g_warning ("failed to drop master: %m\n");
+
+  /* Now we don't want to do any drawing or service clients
+   * until we regain focus so we run a new mainloop that will
+   * only respond to the SIGUSR signals we have at vt switch.
+   */
+
+  compositor->sigusr_loop = g_main_loop_new (tmp_context, TRUE);
+
+  /* XXX: glib doesn't let you remove a source from a non default
+   * context it only lets you destroy it so we have to create a
+   * new source... */
+  source = create_sigusr_source (compositor);
+
+  g_source_attach (source, tmp_context);
+
+  meta_tty_leave_vt (compositor->tty);
+
+  g_main_loop_run (compositor->sigusr_loop);
+
+  g_source_destroy (source);
+  g_main_loop_unref (compositor->sigusr_loop);
+  compositor->sigusr_loop = NULL;
+  g_main_context_unref (tmp_context);
+}
+
+static gboolean
+on_sigusr_channel_io (GIOChannel *channel,
+                      GIOCondition condition,
+                      void *user_data)
 {
-  switch (event)
+  MetaWaylandCompositor *compositor = user_data;
+  char signal;
+  int count;
+
+  for (;;)
     {
-    case META_TTY_VT_EVENT_ENTER:
-      if (drmSetMaster (compositor->drm_fd))
-        g_critical ("failed to set master: %m\n");
-      clutter_actor_queue_redraw (compositor->stage);
-      clutter_evdev_reclaim_devices ();
+      count = read (sigusr_pipe_fds[0], &signal, 1);
+      if (count == EINTR)
+        continue;
+      if (count < 0)
+        {
+          const char *msg = strerror (errno);
+          g_warning ("Error handling signal: %s", msg);
+        }
+      if (count != 1)
+        {
+          g_warning ("Unexpectedly failed to read byte from signal pipe\n");
+          return TRUE;
+        }
+      break;
+    }
+  switch (signal)
+    {
+    case '1': /* SIGUSR1 */
+      on_vt_leave (compositor);
       break;
-    case META_TTY_VT_EVENT_LEAVE:
-      clutter_evdev_release_devices ();
-      if (drmDropMaster(compositor->drm_fd) < 0)
-        g_warning ("failed to drop master: %m\n");
+    case '2': /* SIGUSR2 */
+      on_vt_enter (compositor);
       break;
-    };
+    default:
+      g_warning ("Spurious character '%c' read from sigusr signal pipe",
+                 signal);
+    }
+
+  return TRUE;
+}
+
+static void
+sigusr_signal_handler (int signum)
+{
+  if (sigusr_pipe_fds[1] >= 0)
+    {
+      switch (signum)
+        {
+        case SIGUSR1:
+          write (sigusr_pipe_fds[1], "1", 1);
+          break;
+        case SIGUSR2:
+          write (sigusr_pipe_fds[1], "2", 1);
+          break;
+        default:
+          break;
+        }
+    }
 }
 
 void
@@ -1380,7 +1488,37 @@ meta_wayland_init (void)
 
   /* XXX: Come up with a more elegant approach... */
   if (strcmp (getenv ("CLUTTER_BACKEND"), "eglnative") == 0)
-    compositor->tty = meta_tty_create (compositor, vt_func, 0);
+    {
+      struct sigaction act;
+      sigset_t empty_mask;
+      GIOChannel *channel;
+      GSource *source;
+
+      pipe (sigusr_pipe_fds);
+
+      channel = g_io_channel_unix_new (sigusr_pipe_fds[0]);
+      g_io_channel_set_close_on_unref (channel, TRUE);
+      g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
+      compositor->sigusr_channel = channel;
+
+      source = create_sigusr_source (compositor);
+      g_source_attach (source, NULL);
+      g_source_unref (source);
+
+      sigemptyset (&empty_mask);
+      act.sa_handler = &sigusr_signal_handler;
+      act.sa_mask    = empty_mask;
+      act.sa_flags   = 0;
+
+      if (sigaction (SIGUSR1,  &act, NULL) < 0)
+        g_printerr ("Failed to register SIGUSR1 handler: %s\n",
+                    g_strerror (errno));
+      if (sigaction (SIGUSR2,  &act, NULL) < 0)
+        g_printerr ("Failed to register SIGUSR1 handler: %s\n",
+                    g_strerror (errno));
+
+      compositor->tty = meta_tty_create (compositor, 0);
+    }
 
   g_queue_init (&compositor->frame_callbacks);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]