From: Colin Walters Date: Tue, 21 Jun 2011 23:01:10 +0000 (-0400) Subject: gmain: use Linux eventfd() for main context wake up X-Git-Tag: 2.29.10~52 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3904c8761a60dbadbdfaf98fe23ff19cbdcc4a9a;p=platform%2Fupstream%2Fglib.git gmain: use Linux eventfd() for main context wake up The Linux eventfd() call is basically tailor made for the main loop wake up pipe - all we want is a threadsafe way to write to a file descriptor, and wake up the context on the other end; we don't care about the content at all. The eventfd manual page basically explains the benefits: Applications can use an eventfd file descriptor instead of a pipe (see pipe(2)) in all cases where a pipe is used simply to signal events. The kernel overhead of an eventfd file descriptor is much lower than that of a pipe, and only one file descriptor is required (versus the two required for a pipe). When writing my multithreaded spawn test case I actually hit the 1024 file descriptor limit quickly, because we used 2 fds per main context. This brings that down to 1. https://bugzilla.gnome.org/show_bug.cgi?id=653140 --- diff --git a/configure.ac b/configure.ac index 148d994..064b799 100644 --- a/configure.ac +++ b/configure.ac @@ -2604,6 +2604,26 @@ main (void) AC_MSG_RESULT(no) ]) +AC_MSG_CHECKING([for eventfd(2) system call]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#include +],[ +int +main (void) +{ + eventfd (0, EFD_CLOEXEC); + return 0; +} +])], +[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_EVENTFD, 1, [we have the eventfd(2) system call]) +], +[ + AC_MSG_RESULT(no) +]) + dnl **************************************** dnl *** GLib POLL* compatibility defines *** dnl **************************************** diff --git a/glib/gmain.c b/glib/gmain.c index 47b26cc..ac018cc 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -49,6 +49,9 @@ #ifdef G_OS_UNIX #include "glib-unix.h" +#ifdef HAVE_EVENTFD +#include +#endif #endif #include @@ -397,6 +400,14 @@ static GSList *main_contexts_without_pipe = NULL; #ifndef G_OS_WIN32 +#ifdef HAVE_EVENTFD +typedef struct { + guint checked_eventfd : 1; + guint have_eventfd : 1; +} EventFdState; +EventFdState event_fd_state = { 0, 0 }; +#endif + /* The UNIX signal pipe contains a single byte specifying which * signal was received. */ @@ -529,8 +540,10 @@ g_main_context_unref (GMainContext *context) if (g_thread_supported()) { #ifndef G_OS_WIN32 - close (context->wake_up_pipe[0]); - close (context->wake_up_pipe[1]); + if (context->wake_up_pipe[0] != -1) + close (context->wake_up_pipe[0]); + if (context->wake_up_pipe[1] != -1) + close (context->wake_up_pipe[1]); #else CloseHandle (context->wake_up_semaphore); #endif @@ -556,8 +569,32 @@ g_main_context_init_pipe (GMainContext *context) if (context->wake_up_pipe[0] != -1) return; +#ifdef HAVE_EVENTFD + if (!event_fd_state.checked_eventfd + || event_fd_state.have_eventfd) + { + int efd; + + event_fd_state.checked_eventfd = TRUE; + efd = eventfd (0, EFD_CLOEXEC); + if (efd == -1 && errno == ENOSYS) + { + event_fd_state.have_eventfd = FALSE; + if (!g_unix_open_pipe (context->wake_up_pipe, FD_CLOEXEC, &error)) + g_error ("Cannot create pipe main loop wake-up: %s", error->message); + } + else if (efd >= 0) + { + event_fd_state.have_eventfd = TRUE; + context->wake_up_pipe[0] = efd; + } + else + g_error ("Cannot create eventfd for main loop wake-up: %s", g_strerror (errno)); + } +#else if (!g_unix_open_pipe (context->wake_up_pipe, FD_CLOEXEC, &error)) g_error ("Cannot create pipe main loop wake-up: %s", error->message); +#endif context->wake_up_rec.fd = context->wake_up_pipe[0]; context->wake_up_rec.events = G_IO_IN; @@ -580,7 +617,9 @@ g_main_context_init_pipe (GMainContext *context) void _g_main_thread_init (void) { - GSList *curr = main_contexts_without_pipe; + GSList *curr; + + curr = main_contexts_without_pipe; while (curr) { g_main_context_init_pipe ((GMainContext *)curr->data); @@ -2942,8 +2981,18 @@ g_main_context_check (GMainContext *context, if (!context->poll_waiting) { #ifndef G_OS_WIN32 - gchar a; - read (context->wake_up_pipe[0], &a, 1); +#ifdef HAVE_EVENTFD + if (event_fd_state.have_eventfd) + { + guint64 buf; + read (context->wake_up_pipe[0], &buf, sizeof(guint64)); + } + else +#endif + { + gchar a; + read (context->wake_up_pipe[0], &a, 1); + } #endif } else @@ -3794,7 +3843,15 @@ g_main_context_wakeup_unlocked (GMainContext *context) { context->poll_waiting = FALSE; #ifndef G_OS_WIN32 - write (context->wake_up_pipe[1], "A", 1); +#ifdef HAVE_EVENTFD + if (event_fd_state.have_eventfd) + { + guint64 buf = 1; + write (context->wake_up_pipe[0], &buf, sizeof(buf)); + } + else +#endif + write (context->wake_up_pipe[1], "A", 1); #else ReleaseSemaphore (context->wake_up_semaphore, 1, NULL); #endif