From 2782cc8d4950effbc4407455e72bd4750cef6e11 Mon Sep 17 00:00:00 2001 From: Kan-Ru Chen Date: Thu, 19 Aug 2010 13:45:03 +0800 Subject: linux: Use VT_WAITEVENT if available to avoid spawn too many threads 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 --- NEWS | 1 + src/ck-sysdeps-unix.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/ck-sysdeps.h | 2 ++ src/ck-vt-monitor.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 101cb1c..807e9c4 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Version 0.4.2 * Don't take bus name until ready (Ray Strode) * systemd hookup (Lennart Poettering) * add --since option to ck-history (William Jon McCann) + * Reduce number of threads on Linux (Kan-Ru Chen) * Other fixes (Anders Kaseor, Frederic Crozat, Matthias Clasen, Michael Biebl, William Jon McCann) ============== diff --git a/src/ck-sysdeps-unix.c b/src/ck-sysdeps-unix.c index e4ab16b..6a8b5f8 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..369c63e 100644 --- a/src/ck-vt-monitor.c +++ b/src/ck-vt-monitor.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -40,9 +41,11 @@ #include "ck-sysdeps.h" #include "ck-marshal.h" -#if defined (__sun) && defined (HAVE_SYS_VT_H) +#ifdef HAVE_SYS_VT_H #include -#include +#endif + +#ifdef __sun #include #endif @@ -163,7 +166,7 @@ ck_vt_monitor_get_active (CkVtMonitor *vt_monitor, return TRUE; } -#if defined (__sun) && defined (HAVE_SYS_VT_H) +#if defined(HAVE_SYS_VT_H) && defined(__sun) static void handle_vt_active (void) { @@ -313,11 +316,31 @@ vt_thread_start (ThreadData *data) { CkVtMonitor *vt_monitor; gboolean res; - gint32 num; + guint num; 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 +357,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) { @@ -377,10 +401,6 @@ vt_add_watch_unlocked (CkVtMonitor *vt_monitor, static void vt_add_watches (CkVtMonitor *vt_monitor) { - guint max_consoles; - int i; - gint32 current_num; - #if defined (__sun) && !defined (HAVE_SYS_VT_H) /* Best to do nothing if VT is not supported */ #elif defined (__sun) && defined (HAVE_SYS_VT_H) @@ -398,7 +418,19 @@ vt_add_watches (CkVtMonitor *vt_monitor) sigaction (SIGPOLL, &act, NULL); ioctl (vt_monitor->priv->vfd, I_SETSIG, S_MSG); +#elif defined (VT_WAITEVENT) + gpointer id; + + G_LOCK (hash_lock); + 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 + guint max_consoles; + int i; + gint32 current_num; + G_LOCK (hash_lock); current_num = vt_monitor->priv->active_num; -- cgit v1.2.3