2 * Copyright © 2011 Canonical Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Ryan Lortie <desrt@desrt.ca>
29 * @short_description: portable cross-thread event signal mechanism
31 * #GWakeup is a simple and portable way of signaling events between
32 * different threads in a way that integrates nicely with g_poll().
33 * GLib uses it internally for cross-thread signalling in the
34 * implementation of #GMainContext and #GCancellable.
36 * You first create a #GWakeup with g_wakeup_new() and initialise a
37 * #GPollFD from it using g_wakeup_get_pollfd(). Polling on the created
38 * #GPollFD will block until g_wakeup_signal() is called, at which point
39 * it will immediately return. Future attempts to poll will continue to
40 * return until g_wakeup_acknowledge() is called. g_wakeup_free() is
41 * used to free a #GWakeup.
43 * On sufficiently modern Linux, this is implemented using eventfd. On
44 * Windows it is implemented using an event handle. On other systems it
45 * is implemented with a pair of pipes.
52 #include "gmessages.h"
53 #include "giochannel.h"
61 wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
64 g_error ("Cannot create event for GWakeup: %s",
65 g_win32_error_message (GetLastError ()));
67 return (GWakeup *) wakeup;
71 g_wakeup_get_pollfd (GWakeup *wakeup,
74 poll_fd->fd = (gintptr) wakeup;
75 poll_fd->events = G_IO_IN;
79 g_wakeup_acknowledge (GWakeup *wakeup)
81 ResetEvent ((HANDLE) wakeup);
85 g_wakeup_signal (GWakeup *wakeup)
87 SetEvent ((HANDLE) wakeup);
91 g_wakeup_free (GWakeup *wakeup)
93 CloseHandle ((HANDLE) wakeup);
98 #include "glib-unix.h"
101 #if defined (HAVE_EVENTFD)
102 #include <sys/eventfd.h>
113 * Creates a new #GWakeup.
115 * You should use g_wakeup_free() to free it when you are done.
117 * Returns: a new #GWakeup
124 GError *error = NULL;
127 wakeup = g_slice_new (GWakeup);
129 /* try eventfd first, if we think we can */
130 #if defined (HAVE_EVENTFD)
131 wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
133 if (wakeup->fds[0] != -1)
139 /* for any failure, try a pipe instead */
142 if (!g_unix_open_pipe (wakeup->fds, FD_CLOEXEC, &error))
143 g_error ("Creating pipes for GWakeup: %s\n", error->message);
145 if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
146 !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
147 g_error ("Set pipes non-blocking for GWakeup: %s\n", error->message);
153 * g_wakeup_get_pollfd:
154 * @wakeup: a #GWakeup
155 * @poll_fd: a #GPollFD
157 * Prepares a @poll_fd such that polling on it will succeed when
158 * g_wakeup_signal() has been called on @wakeup.
160 * @poll_fd is valid until @wakeup is freed.
165 g_wakeup_get_pollfd (GWakeup *wakeup,
168 poll_fd->fd = wakeup->fds[0];
169 poll_fd->events = G_IO_IN;
173 * g_wakeup_acknowledge:
174 * @wakeup: a #GWakeup
176 * Acknowledges receipt of a wakeup signal on @wakeup.
178 * You must call this after @wakeup polls as ready. If not, it will
179 * continue to poll as ready until you do so.
181 * If you call this function and @wakeup is not signaled, nothing
187 g_wakeup_acknowledge (GWakeup *wakeup)
191 /* read until it is empty */
192 while (read (wakeup->fds[0], buffer, sizeof buffer) == sizeof buffer);
197 * @wakeup: a #GWakeup
201 * Any future (or present) polling on the #GPollFD returned by
202 * g_wakeup_get_pollfd() will immediately succeed until such a time as
203 * g_wakeup_acknowledge() is called.
208 g_wakeup_signal (GWakeup *wakeup)
212 if (wakeup->fds[1] == -1)
213 write (wakeup->fds[0], &one, sizeof one);
215 write (wakeup->fds[1], &one, 1);
220 * @wakeup: a #GWakeup
224 * You must not currently be polling on the #GPollFD returned by
225 * g_wakeup_get_pollfd(), or the result is undefined.
228 g_wakeup_free (GWakeup *wakeup)
230 close (wakeup->fds[0]);
232 if (wakeup->fds[1] != -1)
233 close (wakeup->fds[1]);
235 g_slice_free (GWakeup, wakeup);