2 * Copyright © 2011 Canonical Limited
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Author: Ryan Lortie <desrt@desrt.ca>
26 /* gwakeup.c is special -- GIO and some test cases include it. As such,
27 * it cannot include other glib headers without triggering the single
28 * includes warnings. We have to manually include its dependencies here
29 * (and at all other use sites).
31 #ifdef GLIB_COMPILATION
43 * @short_description: portable cross-thread event signal mechanism
45 * #GWakeup is a simple and portable way of signaling events between
46 * different threads in a way that integrates nicely with g_poll().
47 * GLib uses it internally for cross-thread signalling in the
48 * implementation of #GMainContext and #GCancellable.
50 * You first create a #GWakeup with g_wakeup_new() and initialise a
51 * #GPollFD from it using g_wakeup_get_pollfd(). Polling on the created
52 * #GPollFD will block until g_wakeup_signal() is called, at which point
53 * it will immediately return. Future attempts to poll will continue to
54 * return until g_wakeup_acknowledge() is called. g_wakeup_free() is
55 * used to free a #GWakeup.
57 * On sufficiently modern Linux, this is implemented using eventfd. On
58 * Windows it is implemented using an event handle. On other systems it
59 * is implemented with a pair of pipes.
67 #ifdef GLIB_COMPILATION
68 #include "gmessages.h"
69 #include "giochannel.h"
78 wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
81 g_error ("Cannot create event for GWakeup: %s",
82 g_win32_error_message (GetLastError ()));
84 return (GWakeup *) wakeup;
88 g_wakeup_get_pollfd (GWakeup *wakeup,
91 poll_fd->fd = (gintptr) wakeup;
92 poll_fd->events = G_IO_IN;
96 g_wakeup_acknowledge (GWakeup *wakeup)
98 ResetEvent ((HANDLE) wakeup);
102 g_wakeup_signal (GWakeup *wakeup)
104 SetEvent ((HANDLE) wakeup);
108 g_wakeup_free (GWakeup *wakeup)
110 CloseHandle ((HANDLE) wakeup);
115 #include "glib-unix.h"
118 #if defined (HAVE_EVENTFD)
119 #include <sys/eventfd.h>
130 * Creates a new #GWakeup.
132 * You should use g_wakeup_free() to free it when you are done.
134 * Returns: a new #GWakeup
141 GError *error = NULL;
144 wakeup = g_slice_new (GWakeup);
146 /* try eventfd first, if we think we can */
147 #if defined (HAVE_EVENTFD)
148 #ifndef TEST_EVENTFD_FALLBACK
149 wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
154 if (wakeup->fds[0] != -1)
160 /* for any failure, try a pipe instead */
163 if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
164 g_error ("Creating pipes for GWakeup: %s", error->message);
166 if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
167 !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
168 g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
174 * g_wakeup_get_pollfd:
175 * @wakeup: a #GWakeup
176 * @poll_fd: a #GPollFD
178 * Prepares a @poll_fd such that polling on it will succeed when
179 * g_wakeup_signal() has been called on @wakeup.
181 * @poll_fd is valid until @wakeup is freed.
186 g_wakeup_get_pollfd (GWakeup *wakeup,
189 poll_fd->fd = wakeup->fds[0];
190 poll_fd->events = G_IO_IN;
194 * g_wakeup_acknowledge:
195 * @wakeup: a #GWakeup
197 * Acknowledges receipt of a wakeup signal on @wakeup.
199 * You must call this after @wakeup polls as ready. If not, it will
200 * continue to poll as ready until you do so.
202 * If you call this function and @wakeup is not signaled, nothing
208 g_wakeup_acknowledge (GWakeup *wakeup)
212 if (wakeup->fds[1] == -1)
216 /* eventfd() read resets counter */
218 res = read (wakeup->fds[0], &value, sizeof (value));
219 while (G_UNLIKELY (res == -1 && errno == EINTR));
225 /* read until it is empty */
227 res = read (wakeup->fds[0], &value, sizeof (value));
228 while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
234 * @wakeup: a #GWakeup
238 * Any future (or present) polling on the #GPollFD returned by
239 * g_wakeup_get_pollfd() will immediately succeed until such a time as
240 * g_wakeup_acknowledge() is called.
242 * This function is safe to call from a UNIX signal handler.
247 g_wakeup_signal (GWakeup *wakeup)
251 if (wakeup->fds[1] == -1)
255 /* eventfd() case. It requires a 64-bit counter increment value to be
258 res = write (wakeup->fds[0], &one, sizeof one);
259 while (G_UNLIKELY (res == -1 && errno == EINTR));
265 /* Non-eventfd() case. Only a single byte needs to be written, and it can
266 * have an arbitrary value. */
268 res = write (wakeup->fds[1], &one, sizeof one);
269 while (G_UNLIKELY (res == -1 && errno == EINTR));
275 * @wakeup: a #GWakeup
279 * You must not currently be polling on the #GPollFD returned by
280 * g_wakeup_get_pollfd(), or the result is undefined.
283 g_wakeup_free (GWakeup *wakeup)
285 close (wakeup->fds[0]);
287 if (wakeup->fds[1] != -1)
288 close (wakeup->fds[1]);
290 g_slice_free (GWakeup, wakeup);