mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
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
This commit is contained in:
parent
29bb7638a5
commit
3904c8761a
20
configure.ac
20
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 <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 ****************************************
|
||||
|
69
glib/gmain.c
69
glib/gmain.c
@ -49,6 +49,9 @@
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include "glib-unix.h"
|
||||
#ifdef HAVE_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user