Don't use the quote tag
[platform/upstream/glib.git] / glib / gwakeup.c
1 /*
2  * Copyright © 2011 Canonical Limited
3  *
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.
8  *
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.
13  *
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/>.
16  *
17  * Author: Ryan Lortie <desrt@desrt.ca>
18  */
19
20 #include "config.h"
21
22
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).
27  */
28 #ifdef GLIB_COMPILATION
29 #include "gtypes.h"
30 #include "gpoll.h"
31 #else
32 #include <glib.h>
33 #endif
34
35 #include "gwakeup.h"
36
37 /*< private >
38  * SECTION:gwakeup
39  * @title: GWakeup
40  * @short_description: portable cross-thread event signal mechanism
41  *
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.
46  *
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.
53  *
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.
57  *
58  * Since: 2.30
59  **/
60 #ifdef _WIN32
61
62 #include <windows.h>
63
64 #ifdef GLIB_COMPILATION
65 #include "gmessages.h"
66 #include "giochannel.h"
67 #include "gwin32.h"
68 #endif
69
70 GWakeup *
71 g_wakeup_new (void)
72 {
73   HANDLE wakeup;
74
75   wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
76
77   if (wakeup == NULL)
78     g_error ("Cannot create event for GWakeup: %s",
79              g_win32_error_message (GetLastError ()));
80
81   return (GWakeup *) wakeup;
82 }
83
84 void
85 g_wakeup_get_pollfd (GWakeup *wakeup,
86                      GPollFD *poll_fd)
87 {
88   poll_fd->fd = (gintptr) wakeup;
89   poll_fd->events = G_IO_IN;
90 }
91
92 void
93 g_wakeup_acknowledge (GWakeup *wakeup)
94 {
95   ResetEvent ((HANDLE) wakeup);
96 }
97
98 void
99 g_wakeup_signal (GWakeup *wakeup)
100 {
101   SetEvent ((HANDLE) wakeup);
102 }
103
104 void
105 g_wakeup_free (GWakeup *wakeup)
106 {
107   CloseHandle ((HANDLE) wakeup);
108 }
109
110 #else
111
112 #include "glib-unix.h"
113 #include <fcntl.h>
114
115 #if defined (HAVE_EVENTFD)
116 #include <sys/eventfd.h>
117 #endif
118
119 struct _GWakeup
120 {
121   gint fds[2];
122 };
123
124 /**
125  * g_wakeup_new:
126  *
127  * Creates a new #GWakeup.
128  *
129  * You should use g_wakeup_free() to free it when you are done.
130  *
131  * Returns: a new #GWakeup
132  *
133  * Since: 2.30
134  **/
135 GWakeup *
136 g_wakeup_new (void)
137 {
138   GError *error = NULL;
139   GWakeup *wakeup;
140
141   wakeup = g_slice_new (GWakeup);
142
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);
147 #else
148   wakeup->fds[0] = -1;
149 #endif
150
151   if (wakeup->fds[0] != -1)
152     {
153       wakeup->fds[1] = -1;
154       return wakeup;
155     }
156
157   /* for any failure, try a pipe instead */
158 #endif
159
160   if (!g_unix_open_pipe (wakeup->fds, FD_CLOEXEC, &error))
161     g_error ("Creating pipes for GWakeup: %s\n", error->message);
162
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);
166
167   return wakeup;
168 }
169
170 /**
171  * g_wakeup_get_pollfd:
172  * @wakeup: a #GWakeup
173  * @poll_fd: a #GPollFD
174  *
175  * Prepares a @poll_fd such that polling on it will succeed when
176  * g_wakeup_signal() has been called on @wakeup.
177  *
178  * @poll_fd is valid until @wakeup is freed.
179  *
180  * Since: 2.30
181  **/
182 void
183 g_wakeup_get_pollfd (GWakeup *wakeup,
184                      GPollFD *poll_fd)
185 {
186   poll_fd->fd = wakeup->fds[0];
187   poll_fd->events = G_IO_IN;
188 }
189
190 /**
191  * g_wakeup_acknowledge:
192  * @wakeup: a #GWakeup
193  *
194  * Acknowledges receipt of a wakeup signal on @wakeup.
195  *
196  * You must call this after @wakeup polls as ready.  If not, it will
197  * continue to poll as ready until you do so.
198  *
199  * If you call this function and @wakeup is not signaled, nothing
200  * happens.
201  *
202  * Since: 2.30
203  **/
204 void
205 g_wakeup_acknowledge (GWakeup *wakeup)
206 {
207   char buffer[16];
208
209   /* read until it is empty */
210   while (read (wakeup->fds[0], buffer, sizeof buffer) == sizeof buffer);
211 }
212
213 /**
214  * g_wakeup_signal:
215  * @wakeup: a #GWakeup
216  *
217  * Signals @wakeup.
218  *
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.
222  *
223  * This function is safe to call from a UNIX signal handler.
224  *
225  * Since: 2.30
226  **/
227 void
228 g_wakeup_signal (GWakeup *wakeup)
229 {
230   guint64 one = 1;
231   int res;
232
233   if (wakeup->fds[1] == -1)
234     {
235       do
236         res = write (wakeup->fds[0], &one, sizeof one);
237       while (G_UNLIKELY (res == -1 && errno == EINTR));
238     }
239   else
240     {
241       do
242         res = write (wakeup->fds[1], &one, 1);
243       while (G_UNLIKELY (res == -1 && errno == EINTR));
244     }
245 }
246
247 /**
248  * g_wakeup_free:
249  * @wakeup: a #GWakeup
250  *
251  * Frees @wakeup.
252  *
253  * You must not currently be polling on the #GPollFD returned by
254  * g_wakeup_get_pollfd(), or the result is undefined.
255  **/
256 void
257 g_wakeup_free (GWakeup *wakeup)
258 {
259   close (wakeup->fds[0]);
260
261   if (wakeup->fds[1] != -1)
262     close (wakeup->fds[1]);
263
264   g_slice_free (GWakeup, wakeup);
265 }
266
267 #endif /* !_WIN32 */