Coverage Report

Created: 2025-07-18 06:08

/src/tinysparql/subprojects/glib-2.80.3/glib/gwakeup.c
Line
Count
Source (jump to first uncovered line)
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
1
{
139
1
  GError *error = NULL;
140
1
  GWakeup *wakeup;
141
142
1
  wakeup = g_slice_new (GWakeup);
143
144
  /* try eventfd first, if we think we can */
145
1
#if defined (HAVE_EVENTFD)
146
1
#ifndef TEST_EVENTFD_FALLBACK
147
1
  wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
148
#else
149
  wakeup->fds[0] = -1;
150
#endif
151
152
1
  if (wakeup->fds[0] != -1)
153
1
    {
154
1
      wakeup->fds[1] = -1;
155
1
      return wakeup;
156
1
    }
157
158
  /* for any failure, try a pipe instead */
159
0
#endif
160
161
0
  if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
162
0
    g_error ("Creating pipes for GWakeup: %s", error->message);
163
164
0
  if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
165
0
      !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
166
0
    g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
167
168
0
  return wakeup;
169
1
}
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
1
{
187
1
  poll_fd->fd = wakeup->fds[0];
188
1
  poll_fd->events = G_IO_IN;
189
1
}
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
0
{
208
0
  int res;
209
210
0
  if (wakeup->fds[1] == -1)
211
0
    {
212
0
      uint64_t value;
213
214
      /* eventfd() read resets counter */
215
0
      do
216
0
        res = read (wakeup->fds[0], &value, sizeof (value));
217
0
      while (G_UNLIKELY (res == -1 && errno == EINTR));
218
0
    }
219
0
  else
220
0
    {
221
0
      uint8_t value;
222
223
      /* read until it is empty */
224
0
      do
225
0
        res = read (wakeup->fds[0], &value, sizeof (value));
226
0
      while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
227
0
    }
228
0
}
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
0
{
247
0
  int res;
248
249
0
  if (wakeup->fds[1] == -1)
250
0
    {
251
0
      uint64_t one = 1;
252
253
      /* eventfd() case. It requires a 64-bit counter increment value to be
254
       * written. */
255
0
      do
256
0
        res = write (wakeup->fds[0], &one, sizeof one);
257
0
      while (G_UNLIKELY (res == -1 && errno == EINTR));
258
0
    }
259
0
  else
260
0
    {
261
0
      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
0
      do
266
0
        res = write (wakeup->fds[1], &one, sizeof one);
267
0
      while (G_UNLIKELY (res == -1 && errno == EINTR));
268
0
    }
269
0
}
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
0
{
283
0
  close (wakeup->fds[0]);
284
285
0
  if (wakeup->fds[1] != -1)
286
0
    close (wakeup->fds[1]);
287
288
0
  g_slice_free (GWakeup, wakeup);
289
0
}
290
291
#endif /* !_WIN32 */