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
+AC_MSG_CHECKING([for eventfd(2) system call])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <sys/eventfd.h>
+#include <unistd.h>
+],[
+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 ****************************************
dnl ****************************************
dnl *** GLib POLL* compatibility defines ***
dnl ****************************************
#ifdef G_OS_UNIX
#include "glib-unix.h"
#ifdef G_OS_UNIX
#include "glib-unix.h"
+#ifdef HAVE_EVENTFD
+#include <sys/eventfd.h>
+#endif
#endif
#include <signal.h>
#endif
#include <signal.h>
+#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.
*/
/* The UNIX signal pipe contains a single byte specifying which
* signal was received.
*/
if (g_thread_supported())
{
#ifndef G_OS_WIN32
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
#else
CloseHandle (context->wake_up_semaphore);
#endif
if (context->wake_up_pipe[0] != -1)
return;
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);
if (!g_unix_open_pipe (context->wake_up_pipe, FD_CLOEXEC, &error))
g_error ("Cannot create pipe main loop wake-up: %s", error->message);
context->wake_up_rec.fd = context->wake_up_pipe[0];
context->wake_up_rec.events = G_IO_IN;
context->wake_up_rec.fd = context->wake_up_pipe[0];
context->wake_up_rec.events = G_IO_IN;
void
_g_main_thread_init (void)
{
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);
while (curr)
{
g_main_context_init_pipe ((GMainContext *)curr->data);
if (!context->poll_waiting)
{
#ifndef G_OS_WIN32
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);
+ }
{
context->poll_waiting = FALSE;
#ifndef G_OS_WIN32
{
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
#else
ReleaseSemaphore (context->wake_up_semaphore, 1, NULL);
#endif