Change log level at g_log_remove_handler
[platform/upstream/glib.git] / glib / gwakeup.c
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  * SECTION:gwakeup
42  * @title: GWakeup
43  * @short_description: portable cross-thread event signal mechanism
44  *
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.
49  *
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.
56  *
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.
60  *
61  * Since: 2.30
62  **/
63 #ifdef _WIN32
64
65 #include <windows.h>
66
67 #ifdef GLIB_COMPILATION
68 #include "gmessages.h"
69 #include "giochannel.h"
70 #include "gwin32.h"
71 #endif
72
73 GWakeup *
74 g_wakeup_new (void)
75 {
76   HANDLE wakeup;
77
78   wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
79
80   if (wakeup == NULL)
81     g_error ("Cannot create event for GWakeup: %s",
82              g_win32_error_message (GetLastError ()));
83
84   return (GWakeup *) wakeup;
85 }
86
87 void
88 g_wakeup_get_pollfd (GWakeup *wakeup,
89                      GPollFD *poll_fd)
90 {
91   poll_fd->fd = (gintptr) wakeup;
92   poll_fd->events = G_IO_IN;
93 }
94
95 void
96 g_wakeup_acknowledge (GWakeup *wakeup)
97 {
98   ResetEvent ((HANDLE) wakeup);
99 }
100
101 void
102 g_wakeup_signal (GWakeup *wakeup)
103 {
104   SetEvent ((HANDLE) wakeup);
105 }
106
107 void
108 g_wakeup_free (GWakeup *wakeup)
109 {
110   CloseHandle ((HANDLE) wakeup);
111 }
112
113 #else
114
115 #include "glib-unix.h"
116 #include <fcntl.h>
117
118 #if defined (HAVE_EVENTFD)
119 #include <sys/eventfd.h>
120 #endif
121
122 struct _GWakeup
123 {
124   gint fds[2];
125 };
126
127 /**
128  * g_wakeup_new:
129  *
130  * Creates a new #GWakeup.
131  *
132  * You should use g_wakeup_free() to free it when you are done.
133  *
134  * Returns: a new #GWakeup
135  *
136  * Since: 2.30
137  **/
138 GWakeup *
139 g_wakeup_new (void)
140 {
141   GError *error = NULL;
142   GWakeup *wakeup;
143
144   wakeup = g_slice_new (GWakeup);
145
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);
150 #else
151   wakeup->fds[0] = -1;
152 #endif
153
154   if (wakeup->fds[0] != -1)
155     {
156       wakeup->fds[1] = -1;
157       return wakeup;
158     }
159
160   /* for any failure, try a pipe instead */
161 #endif
162
163   if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
164     g_error ("Creating pipes for GWakeup: %s", error->message);
165
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);
169
170   return wakeup;
171 }
172
173 /**
174  * g_wakeup_get_pollfd:
175  * @wakeup: a #GWakeup
176  * @poll_fd: a #GPollFD
177  *
178  * Prepares a @poll_fd such that polling on it will succeed when
179  * g_wakeup_signal() has been called on @wakeup.
180  *
181  * @poll_fd is valid until @wakeup is freed.
182  *
183  * Since: 2.30
184  **/
185 void
186 g_wakeup_get_pollfd (GWakeup *wakeup,
187                      GPollFD *poll_fd)
188 {
189   poll_fd->fd = wakeup->fds[0];
190   poll_fd->events = G_IO_IN;
191 }
192
193 /**
194  * g_wakeup_acknowledge:
195  * @wakeup: a #GWakeup
196  *
197  * Acknowledges receipt of a wakeup signal on @wakeup.
198  *
199  * You must call this after @wakeup polls as ready.  If not, it will
200  * continue to poll as ready until you do so.
201  *
202  * If you call this function and @wakeup is not signaled, nothing
203  * happens.
204  *
205  * Since: 2.30
206  **/
207 void
208 g_wakeup_acknowledge (GWakeup *wakeup)
209 {
210   int res;
211
212   if (wakeup->fds[1] == -1)
213     {
214       uint64_t value;
215
216       /* eventfd() read resets counter */
217       do
218         res = read (wakeup->fds[0], &value, sizeof (value));
219       while (G_UNLIKELY (res == -1 && errno == EINTR));
220     }
221   else
222     {
223       uint8_t value;
224
225       /* read until it is empty */
226       do
227         res = read (wakeup->fds[0], &value, sizeof (value));
228       while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
229     }
230 }
231
232 /**
233  * g_wakeup_signal:
234  * @wakeup: a #GWakeup
235  *
236  * Signals @wakeup.
237  *
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.
241  *
242  * This function is safe to call from a UNIX signal handler.
243  *
244  * Since: 2.30
245  **/
246 void
247 g_wakeup_signal (GWakeup *wakeup)
248 {
249   int res;
250
251   if (wakeup->fds[1] == -1)
252     {
253       uint64_t one = 1;
254
255       /* eventfd() case. It requires a 64-bit counter increment value to be
256        * written. */
257       do
258         res = write (wakeup->fds[0], &one, sizeof one);
259       while (G_UNLIKELY (res == -1 && errno == EINTR));
260     }
261   else
262     {
263       uint8_t one = 1;
264
265       /* Non-eventfd() case. Only a single byte needs to be written, and it can
266        * have an arbitrary value. */
267       do
268         res = write (wakeup->fds[1], &one, sizeof one);
269       while (G_UNLIKELY (res == -1 && errno == EINTR));
270     }
271 }
272
273 /**
274  * g_wakeup_free:
275  * @wakeup: a #GWakeup
276  *
277  * Frees @wakeup.
278  *
279  * You must not currently be polling on the #GPollFD returned by
280  * g_wakeup_get_pollfd(), or the result is undefined.
281  **/
282 void
283 g_wakeup_free (GWakeup *wakeup)
284 {
285   close (wakeup->fds[0]);
286
287   if (wakeup->fds[1] != -1)
288     close (wakeup->fds[1]);
289
290   g_slice_free (GWakeup, wakeup);
291 }
292
293 #endif /* !_WIN32 */