Coverage Report

Created: 2026-02-14 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rauc/subprojects/glib-2.76.5/glib/gwakeup.c
Line
Count
Source
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
0
{
141
0
  GError *error = NULL;
142
0
  GWakeup *wakeup;
143
144
0
  wakeup = g_slice_new (GWakeup);
145
146
  /* try eventfd first, if we think we can */
147
0
#if defined (HAVE_EVENTFD)
148
0
#ifndef TEST_EVENTFD_FALLBACK
149
0
  wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
150
#else
151
  wakeup->fds[0] = -1;
152
#endif
153
154
0
  if (wakeup->fds[0] != -1)
155
0
    {
156
0
      wakeup->fds[1] = -1;
157
0
      return wakeup;
158
0
    }
159
160
  /* for any failure, try a pipe instead */
161
0
#endif
162
163
0
  if (!g_unix_open_pipe (wakeup->fds, FD_CLOEXEC, &error))
164
0
    g_error ("Creating pipes for GWakeup: %s", error->message);
165
166
0
  if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
167
0
      !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
168
0
    g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
169
170
0
  return wakeup;
171
0
}
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
0
{
189
0
  poll_fd->fd = wakeup->fds[0];
190
0
  poll_fd->events = G_IO_IN;
191
0
}
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
0
{
210
  /* read until it is empty */
211
212
0
  if (wakeup->fds[1] == -1)
213
0
    {
214
0
      uint64_t value;
215
216
0
      while (read (wakeup->fds[0], &value, sizeof (value)) == sizeof (value));
217
0
    }
218
0
  else
219
0
    {
220
0
      uint8_t value;
221
222
0
      while (read (wakeup->fds[0], &value, sizeof (value)) == sizeof (value));
223
0
    }
224
0
}
225
226
/**
227
 * g_wakeup_signal:
228
 * @wakeup: a #GWakeup
229
 *
230
 * Signals @wakeup.
231
 *
232
 * Any future (or present) polling on the #GPollFD returned by
233
 * g_wakeup_get_pollfd() will immediately succeed until such a time as
234
 * g_wakeup_acknowledge() is called.
235
 *
236
 * This function is safe to call from a UNIX signal handler.
237
 *
238
 * Since: 2.30
239
 **/
240
void
241
g_wakeup_signal (GWakeup *wakeup)
242
0
{
243
0
  int res;
244
245
0
  if (wakeup->fds[1] == -1)
246
0
    {
247
0
      uint64_t one = 1;
248
249
      /* eventfd() case. It requires a 64-bit counter increment value to be
250
       * written. */
251
0
      do
252
0
        res = write (wakeup->fds[0], &one, sizeof one);
253
0
      while (G_UNLIKELY (res == -1 && errno == EINTR));
254
0
    }
255
0
  else
256
0
    {
257
0
      uint8_t one = 1;
258
259
      /* Non-eventfd() case. Only a single byte needs to be written, and it can
260
       * have an arbitrary value. */
261
0
      do
262
0
        res = write (wakeup->fds[1], &one, sizeof one);
263
0
      while (G_UNLIKELY (res == -1 && errno == EINTR));
264
0
    }
265
0
}
266
267
/**
268
 * g_wakeup_free:
269
 * @wakeup: a #GWakeup
270
 *
271
 * Frees @wakeup.
272
 *
273
 * You must not currently be polling on the #GPollFD returned by
274
 * g_wakeup_get_pollfd(), or the result is undefined.
275
 **/
276
void
277
g_wakeup_free (GWakeup *wakeup)
278
0
{
279
0
  close (wakeup->fds[0]);
280
281
0
  if (wakeup->fds[1] != -1)
282
0
    close (wakeup->fds[1]);
283
284
0
  g_slice_free (GWakeup, wakeup);
285
0
}
286
287
#endif /* !_WIN32 */