From 78545a641cb93811640e95792eb7f87f810e7aea Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Mon, 25 Jul 2011 15:05:03 +0200 Subject: [PATCH] Add GWakeup GWakeup is a utility class to handle the cross-thread signalling needs of GMainContext and GCancellable. It may find some other users as well. The desire here is to properly hide the implementation details in a module which can be properly unit tested and used in GMainContext and GCancellable without a rats nest of #ifdef. --- glib/Makefile.am | 2 + glib/glib.h | 1 + glib/glib.symbols | 5 ++ glib/gwakeup.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ glib/gwakeup.h | 38 +++++++++++ 5 files changed, 203 insertions(+) create mode 100644 glib/gwakeup.c create mode 100644 glib/gwakeup.h diff --git a/glib/Makefile.am b/glib/Makefile.am index 22680b8b2..b4eaefec2 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -198,6 +198,7 @@ libglib_2_0_la_SOURCES = \ gvarianttypeinfo.h \ gvarianttypeinfo.c \ gvarianttype.c \ + gwakeup.c \ gdebug.h \ gprintf.c \ gprintfint.h @@ -286,6 +287,7 @@ glibsubinclude_HEADERS = \ gutils.h \ gvarianttype.h \ gvariant.h \ + gwakeup.h \ gwin32.h \ gprintf.h diff --git a/glib/glib.h b/glib/glib.h index 06d0190b2..d2ce71d7e 100644 --- a/glib/glib.h +++ b/glib/glib.h @@ -90,6 +90,7 @@ #include #include #include +#include #ifdef G_PLATFORM_WIN32 #include #endif diff --git a/glib/glib.symbols b/glib/glib.symbols index ba24a194d..18ba34de1 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1581,3 +1581,8 @@ glib_micro_version glib_minor_version glib_on_error_halt g_mem_gc_friendly +g_wakeup_new +g_wakeup_free +g_wakeup_signal +g_wakeup_acknowledge +g_wakeup_get_pollfd diff --git a/glib/gwakeup.c b/glib/gwakeup.c new file mode 100644 index 000000000..60c2a9eb5 --- /dev/null +++ b/glib/gwakeup.c @@ -0,0 +1,157 @@ +/* + * Copyright © 2011 Canonical Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ryan Lortie + */ + +#include "config.h" + +#include "gwakeup.h" + +#ifdef _WIN32 + +#include +#include "gmessages.h" +#include "giochannel.h" +#include "gwin32.h" + +GWakeup * +g_wakeup_new (void) +{ + HANDLE wakeup; + + wakeup = CreateEvent (NULL, TRUE, FALSE, NULL); + + if (wakeup == NULL) + g_error ("Cannot create event for GWakeup: %s", + g_win32_error_message (GetLastError ())); + + return (GWakeup *) wakeup; +} + +void +g_wakeup_get_pollfd (GWakeup *wakeup, + GPollFD *fd) +{ + fd->fd = (gintptr) wakeup; + fd->events = G_IO_IN; +} + +void +g_wakeup_acknowledge (GWakeup *wakeup) +{ + ResetEvent ((HANDLE) wakeup); +} + +void +g_wakeup_signal (GWakeup *wakeup) +{ + SetEvent ((HANDLE) wakeup); +} + +void +g_wakeup_free (GWakeup *wakeup) +{ + CloseHandle ((HANDLE) wakeup); +} + +#else + +#include "glib-unix.h" +#include + +#if defined (HAVE_EVENTFD) +#include +#endif + +struct _GWakeup +{ + gint fds[2]; +}; + +GWakeup * +g_wakeup_new (void) +{ + GError *error = NULL; + GWakeup *wakeup; + + wakeup = g_slice_new (GWakeup); + + /* try eventfd first, if we think we can */ +#if defined (HAVE_EVENTFD) + wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK); + + if (wakeup->fds[0] != -1) + { + wakeup->fds[1] = -1; + return wakeup; + } + + /* for any failure, try a pipe instead */ +#endif + + if (!g_unix_open_pipe (wakeup->fds, FD_CLOEXEC, &error)) + g_error ("Creating pipes for GWakeup: %s\n", error->message); + + if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) || + !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error)) + g_error ("Set pipes non-blocking for GWakeup: %s\n", error->message); + + return wakeup; +} + +void +g_wakeup_get_pollfd (GWakeup *wakeup, + GPollFD *fd) +{ + fd->fd = wakeup->fds[0]; + fd->events = G_IO_IN; +} + +void +g_wakeup_acknowledge (GWakeup *wakeup) +{ + char buffer[16]; + + /* read until it is empty */ + while (read (wakeup->fds[0], buffer, sizeof buffer) == sizeof buffer); +} + +void +g_wakeup_signal (GWakeup *wakeup) +{ + guint64 one = 1; + + if (wakeup->fds[1] == -1) + write (wakeup->fds[0], &one, sizeof one); + else + write (wakeup->fds[1], &one, 1); +} + +void +g_wakeup_free (GWakeup *wakeup) +{ + close (wakeup->fds[0]); + + if (wakeup->fds[1] != -1) + close (wakeup->fds[1]); + + g_slice_free (GWakeup, wakeup); +} + +#endif /* !_WIN32 */ diff --git a/glib/gwakeup.h b/glib/gwakeup.h new file mode 100644 index 000000000..58d592f63 --- /dev/null +++ b/glib/gwakeup.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2011 Canonical Limited + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Ryan Lortie + */ + +#ifndef __G_WAKEUP_H__ +#define __G_WAKEUP_H__ + +#include +#include + +typedef struct _GWakeup GWakeup; + +GWakeup * g_wakeup_new (void); +void g_wakeup_free (GWakeup *wakeup); + +void g_wakeup_get_pollfd (GWakeup *wakeup, + GPollFD *fd); +void g_wakeup_signal (GWakeup *wakeup); +void g_wakeup_acknowledge (GWakeup *wakeup); + +#endif