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, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
23 /* gwakeup.c is special -- GIO and some test cases include it. As such,
24 * it cannot include other glib headers without triggering the single
25 * includes warnings. We have to manually include its dependencies here
26 * (and at all other use sites).
28 #ifdef GLIB_COMPILATION
40 * @short_description: portable cross-thread event signal mechanism
42 * #GWakeup is a simple and portable way of signaling events between
43 * different threads in a way that integrates nicely with g_poll().
44 * GLib uses it internally for cross-thread signalling in the
45 * implementation of #GMainContext and #GCancellable.
47 * You first create a #GWakeup with g_wakeup_new() and initialise a
48 * #GPollFD from it using g_wakeup_get_pollfd(). Polling on the created
49 * #GPollFD will block until g_wakeup_signal() is called, at which point
50 * it will immediately return. Future attempts to poll will continue to
51 * return until g_wakeup_acknowledge() is called. g_wakeup_free() is
52 * used to free a #GWakeup.
54 * On sufficiently modern Linux, this is implemented using eventfd. On
55 * Windows it is implemented using an event handle. On other systems it
56 * is implemented with a pair of pipes.
64 #ifdef GLIB_COMPILATION
65 #include "gmessages.h"
66 #include "giochannel.h"
75 wakeup
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
78 g_error ("Cannot create event for GWakeup: %s",
79 g_win32_error_message (GetLastError ()));
81 return (GWakeup
*) wakeup
;
85 g_wakeup_get_pollfd (GWakeup
*wakeup
,
88 poll_fd
->fd
= (gintptr
) wakeup
;
89 poll_fd
->events
= G_IO_IN
;
93 g_wakeup_acknowledge (GWakeup
*wakeup
)
95 ResetEvent ((HANDLE
) wakeup
);
99 g_wakeup_signal (GWakeup
*wakeup
)
101 SetEvent ((HANDLE
) wakeup
);
105 g_wakeup_free (GWakeup
*wakeup
)
107 CloseHandle ((HANDLE
) wakeup
);
112 #include "glib-unix.h"
115 #if defined (HAVE_EVENTFD)
116 #include <sys/eventfd.h>
127 * Creates a new #GWakeup.
129 * You should use g_wakeup_free() to free it when you are done.
131 * Returns: a new #GWakeup
138 GError
*error
= NULL
;
141 wakeup
= g_slice_new (GWakeup
);
143 /* try eventfd first, if we think we can */
144 #if defined (HAVE_EVENTFD)
145 #ifndef TEST_EVENTFD_FALLBACK
146 wakeup
->fds
[0] = eventfd (0, EFD_CLOEXEC
| EFD_NONBLOCK
);
151 if (wakeup
->fds
[0] != -1)
157 /* for any failure, try a pipe instead */
160 if (!g_unix_open_pipe (wakeup
->fds
, FD_CLOEXEC
, &error
))
161 g_error ("Creating pipes for GWakeup: %s\n", error
->message
);
163 if (!g_unix_set_fd_nonblocking (wakeup
->fds
[0], TRUE
, &error
) ||
164 !g_unix_set_fd_nonblocking (wakeup
->fds
[1], TRUE
, &error
))
165 g_error ("Set pipes non-blocking for GWakeup: %s\n", error
->message
);
171 * g_wakeup_get_pollfd:
172 * @wakeup: a #GWakeup
173 * @poll_fd: a #GPollFD
175 * Prepares a @poll_fd such that polling on it will succeed when
176 * g_wakeup_signal() has been called on @wakeup.
178 * @poll_fd is valid until @wakeup is freed.
183 g_wakeup_get_pollfd (GWakeup
*wakeup
,
186 poll_fd
->fd
= wakeup
->fds
[0];
187 poll_fd
->events
= G_IO_IN
;
191 * g_wakeup_acknowledge:
192 * @wakeup: a #GWakeup
194 * Acknowledges receipt of a wakeup signal on @wakeup.
196 * You must call this after @wakeup polls as ready. If not, it will
197 * continue to poll as ready until you do so.
199 * If you call this function and @wakeup is not signaled, nothing
205 g_wakeup_acknowledge (GWakeup
*wakeup
)
209 /* read until it is empty */
210 while (read (wakeup
->fds
[0], buffer
, sizeof buffer
) == sizeof buffer
);
215 * @wakeup: a #GWakeup
219 * Any future (or present) polling on the #GPollFD returned by
220 * g_wakeup_get_pollfd() will immediately succeed until such a time as
221 * g_wakeup_acknowledge() is called.
223 * This function is safe to call from a UNIX signal handler.
228 g_wakeup_signal (GWakeup
*wakeup
)
232 if (wakeup
->fds
[1] == -1)
236 /* eventfd() case. It requires a 64-bit counter increment value to be
239 res
= write (wakeup
->fds
[0], &one
, sizeof one
);
240 while (G_UNLIKELY (res
== -1 && errno
== EINTR
));
246 /* Non-eventfd() case. Only a single byte needs to be written, and it can
247 * have an arbitrary value. */
249 res
= write (wakeup
->fds
[1], &one
, sizeof one
);
250 while (G_UNLIKELY (res
== -1 && errno
== EINTR
));
256 * @wakeup: a #GWakeup
260 * You must not currently be polling on the #GPollFD returned by
261 * g_wakeup_get_pollfd(), or the result is undefined.
264 g_wakeup_free (GWakeup
*wakeup
)
266 close (wakeup
->fds
[0]);
268 if (wakeup
->fds
[1] != -1)
269 close (wakeup
->fds
[1]);
271 g_slice_free (GWakeup
, wakeup
);