[ConsoleKit] [PATCH] Use VT_WAITEVENT if available to avoid spawn too many threads

Kan-Ru Chen koster at debian.org
Thu Aug 19 02:35:05 PDT 2010


Starting from linux kernel 2.6.32 there is a new ioctl VT_WAITEVENT
which can monitor vt switches and return new vt number.

https://bugs.freedesktop.org/show_bug.cgi?id=17720
---
 Please CC me on any replies (non-subscriber)

 src/ck-sysdeps-unix.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 src/ck-sysdeps.h      |    2 ++
 src/ck-vt-monitor.c   |   32 ++++++++++++++++++++++++++++++--
 3 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/src/ck-sysdeps-unix.c b/src/ck-sysdeps-unix.c
index e4ab16b..90c514d 100644
--- a/src/ck-sysdeps-unix.c
+++ b/src/ck-sysdeps-unix.c
@@ -296,6 +296,50 @@ ck_wait_for_active_console_num (int   console_fd,
         return ret;
 }
 
+#ifdef VT_WAITEVENT
+gboolean
+ck_wait_for_console_switch (int   console_fd,
+                            guint *num)
+{
+        gboolean ret;
+        int      res;
+        struct vt_event vt;
+
+        g_assert (console_fd != -1);
+
+ again:
+        ret = FALSE;
+        errno = 0;
+        vt.event = VT_EVENT_SWITCH;
+        vt.oldev = num;
+        res = ioctl (console_fd, VT_WAITEVENT, &vt);
+
+        if (res == ERROR) {
+                const char *errmsg;
+
+                errmsg = g_strerror (errno);
+
+                if (errno == EINTR) {
+                        g_debug ("Interrupted waiting for native console event: %s",
+                                  errmsg);
+                       goto again;
+                } else if (errno == ENOTSUP) {
+                        g_debug ("Console event not supported on this system");
+                } else {
+                        g_warning ("Error waiting for native console event: %s",
+                                   errmsg);
+                }
+                goto out;
+        }
+
+        ret = TRUE;
+        *num = vt.newev;
+
+ out:
+        return ret;
+}
+#endif
+
 gboolean
 ck_activate_console_num (int   console_fd,
                          guint num)
diff --git a/src/ck-sysdeps.h b/src/ck-sysdeps.h
index 8f22d52..5dd573f 100644
--- a/src/ck-sysdeps.h
+++ b/src/ck-sysdeps.h
@@ -72,6 +72,8 @@ gboolean     ck_activate_console_num          (int             console_fd,
                                                guint           num);
 gboolean     ck_wait_for_active_console_num   (int             console_fd,
                                                guint           num);
+gboolean     ck_wait_for_console_switch       (int             console_fd,
+                                               guint          *num);
 
 G_END_DECLS
 
diff --git a/src/ck-vt-monitor.c b/src/ck-vt-monitor.c
index 67a1f49..414bdbb 100644
--- a/src/ck-vt-monitor.c
+++ b/src/ck-vt-monitor.c
@@ -40,7 +40,7 @@
 #include "ck-sysdeps.h"
 #include "ck-marshal.h"
 
-#if defined (__sun) && defined (HAVE_SYS_VT_H)
+#ifdef HAVE_SYS_VT_H
 #include <sys/vt.h>
 #include <signal.h>
 #include <stropts.h>
@@ -163,7 +163,7 @@ ck_vt_monitor_get_active (CkVtMonitor    *vt_monitor,
         return TRUE;
 }
 
-#if defined (__sun) && defined (HAVE_SYS_VT_H)
+#ifdef HAVE_SYS_VT_H
 static void
 handle_vt_active (void)
 {
@@ -318,6 +318,26 @@ vt_thread_start (ThreadData *data)
         vt_monitor = data->vt_monitor;
         num = data->num;
 
+#ifdef VT_WAITEVENT
+        for (;;) {
+                res = ck_wait_for_console_switch (vt_monitor->priv->vfd, &num);
+                if (! res) {
+                        break;
+                } else {
+                        EventData *event;
+
+                        /* add event to queue */
+                        event = g_new0 (EventData, 1);
+                        event->num = num;
+                        g_debug ("Pushing activation event for VT %d onto queue", num);
+
+                        g_async_queue_push (vt_monitor->priv->event_queue, event);
+
+                        /* schedule processing of queue */
+                        schedule_process_queue (vt_monitor);
+                }
+        }
+#else
         res = ck_wait_for_active_console_num (vt_monitor->priv->vfd, num);
         if (! res) {
                 /* FIXME: what do we do if it fails? */
@@ -334,6 +354,7 @@ vt_thread_start (ThreadData *data)
                 /* schedule processing of queue */
                 schedule_process_queue (vt_monitor);
         }
+#endif
 
         G_LOCK (hash_lock);
         if (vt_monitor->priv->vt_thread_hash != NULL) {
@@ -398,6 +419,13 @@ vt_add_watches (CkVtMonitor *vt_monitor)
         sigaction (SIGPOLL, &act, NULL);
 
         ioctl (vt_monitor->priv->vfd, I_SETSIG, S_MSG);
+#elif defined (VT_WAITEVENT)
+        G_LOCK (hash_lock);
+        gpointer id;
+        id = GINT_TO_POINTER (1);
+        if (g_hash_table_lookup (vt_monitor->priv->vt_thread_hash, id) == NULL)
+                vt_add_watch_unlocked (vt_monitor, 1);
+        G_UNLOCK (hash_lock);
 #else
         G_LOCK (hash_lock);
 
-- 
1.7.1



More information about the ConsoleKit mailing list