1 /*
2 * Copyright © 2011 Canonical Limited
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author: Ryan Lortie <desrt@desrt.ca>
20 */
21
22 #include "config.h"
23
24 #include <stdint.h>
25
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).
30 */
31 #ifdef GLIB_COMPILATION
32 #include "gtypes.h"
33 #include "gpoll.h"
34 #else
35 #include <glib.h>
36 #endif
37
38 #include "gwakeup.h"
39
40 /*< private >
41 * GWakeup:
42 *
43 * `GWakeup` is a simple and portable way of signaling events between
44 * different threads in a way that integrates nicely with g_poll().
45 * GLib uses it internally for cross-thread signalling in the
46 * implementation of #GMainContext and #GCancellable.
47 *
48 * You first create a #GWakeup with g_wakeup_new() and initialise a
49 * #GPollFD from it using g_wakeup_get_pollfd(). Polling on the created
50 * #GPollFD will block until g_wakeup_signal() is called, at which point
51 * it will immediately return. Future attempts to poll will continue to
52 * return until g_wakeup_acknowledge() is called. g_wakeup_free() is
53 * used to free a #GWakeup.
54 *
55 * On sufficiently modern Linux, this is implemented using eventfd. On
56 * Windows it is implemented using an event handle. On other systems it
57 * is implemented with a pair of pipes.
58 *
59 * Since: 2.30
60 */
61 #ifdef _WIN32
62
63 #include <windows.h>
64
65 #ifdef GLIB_COMPILATION
66 #include "gmessages.h"
67 #include "giochannel.h"
68 #include "gwin32.h"
69 #endif
70
71 GWakeup *
72 g_wakeup_new (void)
73 {
74 HANDLE wakeup;
75
76 wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
77
78 if (wakeup == NULL)
79 g_error ("Cannot create event for GWakeup: %s",
80 g_win32_error_message (GetLastError ()));
81
82 return (GWakeup *) wakeup;
83 }
84
85 void
86 g_wakeup_get_pollfd (GWakeup *wakeup,
87 GPollFD *poll_fd)
88 {
89 poll_fd->fd = (gintptr) wakeup;
90 poll_fd->events = G_IO_IN;
91 }
92
93 void
94 g_wakeup_acknowledge (GWakeup *wakeup)
95 {
96 ResetEvent ((HANDLE) wakeup);
97 }
98
99 void
100 g_wakeup_signal (GWakeup *wakeup)
101 {
102 SetEvent ((HANDLE) wakeup);
103 }
104
105 void
106 g_wakeup_free (GWakeup *wakeup)
107 {
108 CloseHandle ((HANDLE) wakeup);
109 }
110
111 #else
112
113 #include "glib-unix.h"
114 #include <fcntl.h>
115
116 #if defined (HAVE_EVENTFD)
117 #include <sys/eventfd.h>
118 #endif
119
120 struct _GWakeup
121 {
122 gint fds[2];
123 };
124
125 /*< private >
126 * g_wakeup_new:
127 *
128 * Creates a new #GWakeup.
129 *
130 * You should use g_wakeup_free() to free it when you are done.
131 *
132 * Returns: a new #GWakeup
133 *
134 * Since: 2.30
135 **/
136 GWakeup *
137 g_wakeup_new (void)
138 {
139 GError *error = NULL;
140 GWakeup *wakeup;
141
142 wakeup = g_slice_new (GWakeup);
143
144 /* try eventfd first, if we think we can */
145 #if defined (HAVE_EVENTFD)
146 #ifndef TEST_EVENTFD_FALLBACK
147 wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
148 #else
149 wakeup->fds[0] = -1;
150 #endif
151
152 if (wakeup->fds[0] != -1)
153 {
154 wakeup->fds[1] = -1;
155 return wakeup;
156 }
157
158 /* for any failure, try a pipe instead */
159 #endif
160
161 if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
162 g_error ("Creating pipes for GWakeup: %s", error->message);
163
164 if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
165 !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
166 g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
167
168 return wakeup;
169 }
170
171 /*< private >
172 * g_wakeup_get_pollfd:
173 * @wakeup: a #GWakeup
174 * @poll_fd: a #GPollFD
175 *
176 * Prepares a @poll_fd such that polling on it will succeed when
177 * g_wakeup_signal() has been called on @wakeup.
178 *
179 * @poll_fd is valid until @wakeup is freed.
180 *
181 * Since: 2.30
182 **/
183 void
184 g_wakeup_get_pollfd (GWakeup *wakeup,
185 GPollFD *poll_fd)
186 {
187 poll_fd->fd = wakeup->fds[0];
188 poll_fd->events = G_IO_IN;
189 }
190
191 /*< private >
192 * g_wakeup_acknowledge:
193 * @wakeup: a #GWakeup
194 *
195 * Acknowledges receipt of a wakeup signal on @wakeup.
196 *
197 * You must call this after @wakeup polls as ready. If not, it will
198 * continue to poll as ready until you do so.
199 *
200 * If you call this function and @wakeup is not signaled, nothing
201 * happens.
202 *
203 * Since: 2.30
204 **/
205 void
206 g_wakeup_acknowledge (GWakeup *wakeup)
207 {
208 int res;
209
210 if (wakeup->fds[1] == -1)
211 {
212 uint64_t value;
213
214 /* eventfd() read resets counter */
215 do
216 res = read (wakeup->fds[0], &value, sizeof (value));
217 while (G_UNLIKELY (res == -1 && errno == EINTR));
218 }
219 else
220 {
221 uint8_t value;
222
223 /* read until it is empty */
224 do
225 res = read (wakeup->fds[0], &value, sizeof (value));
226 while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
227 }
228 }
229
230 /*< private >
231 * g_wakeup_signal:
232 * @wakeup: a #GWakeup
233 *
234 * Signals @wakeup.
235 *
236 * Any future (or present) polling on the #GPollFD returned by
237 * g_wakeup_get_pollfd() will immediately succeed until such a time as
238 * g_wakeup_acknowledge() is called.
239 *
240 * This function is safe to call from a UNIX signal handler.
241 *
242 * Since: 2.30
243 **/
244 void
245 g_wakeup_signal (GWakeup *wakeup)
246 {
247 int res;
248
249 if (wakeup->fds[1] == -1)
250 {
251 uint64_t one = 1;
252
253 /* eventfd() case. It requires a 64-bit counter increment value to be
254 * written. */
255 do
256 res = write (wakeup->fds[0], &one, sizeof one);
257 while (G_UNLIKELY (res == -1 && errno == EINTR));
258 }
259 else
260 {
261 uint8_t one = 1;
262
263 /* Non-eventfd() case. Only a single byte needs to be written, and it can
264 * have an arbitrary value. */
265 do
266 res = write (wakeup->fds[1], &one, sizeof one);
267 while (G_UNLIKELY (res == -1 && errno == EINTR));
268 }
269 }
270
271 /*< private >
272 * g_wakeup_free:
273 * @wakeup: a #GWakeup
274 *
275 * Frees @wakeup.
276 *
277 * You must not currently be polling on the #GPollFD returned by
278 * g_wakeup_get_pollfd(), or the result is undefined.
279 **/
280 void
281 g_wakeup_free (GWakeup *wakeup)
282 {
283 close (wakeup->fds[0]);
284
285 if (wakeup->fds[1] != -1)
286 close (wakeup->fds[1]);
287
288 g_slice_free (GWakeup, wakeup);
289 }
290
291 #endif /* !_WIN32 */