Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibuv/src/unix/signal.c
Line
Count
Source
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
 * Permission is hereby granted, free of charge, to any person obtaining a copy
3
 * of this software and associated documentation files (the "Software"), to
4
 * deal in the Software without restriction, including without limitation the
5
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6
 * sell copies of the Software, and to permit persons to whom the Software is
7
 * furnished to do so, subject to the following conditions:
8
 *
9
 * The above copyright notice and this permission notice shall be included in
10
 * all copies or substantial portions of the Software.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18
 * IN THE SOFTWARE.
19
 */
20
21
#include "uv.h"
22
#include "internal.h"
23
24
#include <assert.h>
25
#include <errno.h>
26
#include <signal.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
#ifndef SA_RESTART
32
# define SA_RESTART 0
33
#endif
34
35
typedef struct {
36
  uv_signal_t* handle;
37
  int signum;
38
} uv__signal_msg_t;
39
40
RB_HEAD(uv__signal_tree_s, uv_signal_s);
41
42
43
static int uv__signal_unlock(void);
44
static int uv__signal_start(uv_signal_t* handle,
45
                            uv_signal_cb signal_cb,
46
                            int signum,
47
                            int oneshot);
48
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
49
static void uv__signal_stop(uv_signal_t* handle);
50
static void uv__signal_unregister_handler(int signum);
51
52
53
static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
54
static struct uv__signal_tree_s uv__signal_tree =
55
    RB_INITIALIZER(uv__signal_tree);
56
static int uv__signal_lock_pipefd[2] = { -1, -1 };
57
58
0
RB_GENERATE_STATIC(uv__signal_tree_s,
Unexecuted instantiation: signal.c:uv__signal_tree_s_RB_NFIND
Unexecuted instantiation: signal.c:uv__signal_tree_s_RB_INSERT
Unexecuted instantiation: signal.c:uv__signal_tree_s_RB_INSERT_COLOR
Unexecuted instantiation: signal.c:uv__signal_tree_s_RB_REMOVE
Unexecuted instantiation: signal.c:uv__signal_tree_s_RB_REMOVE_COLOR
59
0
                   uv_signal_s, tree_entry,
60
0
                   uv__signal_compare)
61
0
62
0
static void uv__signal_global_reinit(void);
63
0
64
0
static void uv__signal_global_init(void) {
65
0
  if (uv__signal_lock_pipefd[0] == -1)
66
    /* pthread_atfork can register before and after handlers, one
67
     * for each child. This only registers one for the child. That
68
     * state is both persistent and cumulative, so if we keep doing
69
     * it the handler functions will be called multiple times. Thus
70
     * we only want to do it once.
71
     */
72
0
    if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
73
0
      abort();
74
75
0
  uv__signal_global_reinit();
76
0
}
77
78
79
0
void uv__signal_cleanup(void) {
80
  /* We can only use signal-safe functions here.
81
   * That includes read/write and close, fortunately.
82
   * We do all of this directly here instead of resetting
83
   * uv__signal_global_init_guard because
84
   * uv__signal_global_once_init is only called from uv_loop_init
85
   * and this needs to function in existing loops.
86
   */
87
0
  if (uv__signal_lock_pipefd[0] != -1) {
88
0
    uv__close(uv__signal_lock_pipefd[0]);
89
0
    uv__signal_lock_pipefd[0] = -1;
90
0
  }
91
92
0
  if (uv__signal_lock_pipefd[1] != -1) {
93
0
    uv__close(uv__signal_lock_pipefd[1]);
94
0
    uv__signal_lock_pipefd[1] = -1;
95
0
  }
96
0
}
97
98
99
0
static void uv__signal_global_reinit(void) {
100
0
  uv__signal_cleanup();
101
102
0
  if (uv__make_pipe(uv__signal_lock_pipefd, 0))
103
0
    abort();
104
105
0
  if (uv__signal_unlock())
106
0
    abort();
107
0
}
108
109
110
0
void uv__signal_global_once_init(void) {
111
0
  uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
112
0
}
113
114
115
0
static int uv__signal_lock(void) {
116
0
  int r;
117
0
  char data;
118
119
0
  do {
120
0
    r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
121
0
  } while (r < 0 && errno == EINTR);
122
123
0
  return (r < 0) ? -1 : 0;
124
0
}
125
126
127
0
static int uv__signal_unlock(void) {
128
0
  int r;
129
0
  char data = 42;
130
131
0
  do {
132
0
    r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
133
0
  } while (r < 0 && errno == EINTR);
134
135
0
  return (r < 0) ? -1 : 0;
136
0
}
137
138
139
0
static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
140
0
  sigset_t new_mask;
141
142
0
  if (sigfillset(&new_mask))
143
0
    abort();
144
145
  /* to shut up valgrind */
146
0
  sigemptyset(saved_sigmask);
147
0
  if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
148
0
    abort();
149
150
0
  if (uv__signal_lock())
151
0
    abort();
152
0
}
153
154
155
0
static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
156
0
  if (uv__signal_unlock())
157
0
    abort();
158
159
0
  if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
160
0
    abort();
161
0
}
162
163
164
0
static uv_signal_t* uv__signal_first_handle(int signum) {
165
  /* This function must be called with the signal lock held. */
166
0
  uv_signal_t lookup;
167
0
  uv_signal_t* handle;
168
169
0
  lookup.signum = signum;
170
0
  lookup.flags = 0;
171
0
  lookup.loop = NULL;
172
173
0
  handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
174
175
0
  if (handle != NULL && handle->signum == signum)
176
0
    return handle;
177
178
0
  return NULL;
179
0
}
180
181
182
0
static void uv__signal_handler(int signum) {
183
0
  uv__signal_msg_t msg;
184
0
  uv_signal_t* handle;
185
0
  int saved_errno;
186
187
0
  saved_errno = errno;
188
0
  memset(&msg, 0, sizeof msg);
189
190
0
  if (uv__signal_lock()) {
191
0
    errno = saved_errno;
192
0
    return;
193
0
  }
194
195
0
  for (handle = uv__signal_first_handle(signum);
196
0
       handle != NULL && handle->signum == signum;
197
0
       handle = RB_NEXT(uv__signal_tree_s, handle)) {
198
0
    int r;
199
200
0
    msg.signum = signum;
201
0
    msg.handle = handle;
202
203
    /* write() should be atomic for small data chunks, so the entire message
204
     * should be written at once. In theory the pipe could become full, in
205
     * which case the user is out of luck.
206
     */
207
0
    do {
208
0
      r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
209
0
    } while (r == -1 && errno == EINTR);
210
211
0
    assert(r == sizeof msg ||
212
0
           (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
213
214
0
    if (r != -1)
215
0
      handle->caught_signals++;
216
0
  }
217
218
0
  uv__signal_unlock();
219
0
  errno = saved_errno;
220
0
}
221
222
223
0
static int uv__signal_register_handler(int signum, int oneshot) {
224
  /* When this function is called, the signal lock must be held. */
225
0
  struct sigaction sa;
226
227
  /* XXX use a separate signal stack? */
228
0
  memset(&sa, 0, sizeof(sa));
229
0
  if (sigfillset(&sa.sa_mask))
230
0
    abort();
231
0
  sa.sa_handler = uv__signal_handler;
232
0
  sa.sa_flags = SA_RESTART;
233
0
  if (oneshot)
234
0
    sa.sa_flags |= SA_RESETHAND;
235
236
  /* XXX save old action so we can restore it later on? */
237
0
  if (sigaction(signum, &sa, NULL))
238
0
    return UV__ERR(errno);
239
240
0
  return 0;
241
0
}
242
243
244
0
static void uv__signal_unregister_handler(int signum) {
245
  /* When this function is called, the signal lock must be held. */
246
0
  struct sigaction sa;
247
248
0
  memset(&sa, 0, sizeof(sa));
249
0
  sa.sa_handler = SIG_DFL;
250
251
  /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
252
   * signal implies that it was successfully registered earlier, so EINVAL
253
   * should never happen.
254
   */
255
0
  if (sigaction(signum, &sa, NULL))
256
0
    abort();
257
0
}
258
259
260
0
static int uv__signal_loop_once_init(uv_loop_t* loop) {
261
0
  int* pipefd;
262
0
  int err;
263
264
  /* Return if already initialized. */
265
0
  pipefd = loop->signal_pipefd;
266
0
  if (pipefd[0] != -1)
267
0
    return 0;
268
269
0
  err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
270
0
  if (err)
271
0
    return err;
272
273
0
  err = uv__io_init_start(loop, &loop->signal_io_watcher, UV__SIGNAL_EVENT,
274
0
                          pipefd[0], POLLIN);
275
0
  if (err) {
276
0
    uv__close(pipefd[0]);
277
0
    uv__close(pipefd[1]);
278
0
    pipefd[0] = -1;
279
0
    pipefd[1] = -1;
280
0
  }
281
282
0
  return err;
283
0
}
284
285
286
0
int uv__signal_loop_fork(uv_loop_t* loop) {
287
0
  struct uv__queue* q;
288
289
0
  if (loop->signal_pipefd[0] == -1)
290
0
    return 0;
291
0
  uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
292
0
  uv__close(loop->signal_pipefd[0]);
293
0
  uv__close(loop->signal_pipefd[1]);
294
0
  loop->signal_pipefd[0] = -1;
295
0
  loop->signal_pipefd[1] = -1;
296
297
0
  uv__queue_foreach(q, &loop->handle_queue) {
298
0
    uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
299
0
    uv_signal_t* sh;
300
301
0
    if (handle->type != UV_SIGNAL)
302
0
      continue;
303
304
0
    sh = (uv_signal_t*) handle;
305
0
    sh->caught_signals = 0;
306
0
    sh->dispatched_signals = 0;
307
0
  }
308
309
0
  return uv__signal_loop_once_init(loop);
310
0
}
311
312
313
0
void uv__signal_loop_cleanup(uv_loop_t* loop) {
314
0
  struct uv__queue* q;
315
316
  /* Stop all the signal watchers that are still attached to this loop. This
317
   * ensures that the (shared) signal tree doesn't contain any invalid entries
318
   * entries, and that signal handlers are removed when appropriate.
319
   * It's safe to use uv__queue_foreach here because the handles and the handle
320
   * queue are not modified by uv__signal_stop().
321
   */
322
0
  uv__queue_foreach(q, &loop->handle_queue) {
323
0
    uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
324
325
0
    if (handle->type == UV_SIGNAL)
326
0
      uv__signal_stop((uv_signal_t*) handle);
327
0
  }
328
329
0
  if (loop->signal_pipefd[0] != -1) {
330
0
    uv__close(loop->signal_pipefd[0]);
331
0
    loop->signal_pipefd[0] = -1;
332
0
  }
333
334
0
  if (loop->signal_pipefd[1] != -1) {
335
0
    uv__close(loop->signal_pipefd[1]);
336
0
    loop->signal_pipefd[1] = -1;
337
0
  }
338
0
}
339
340
341
0
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
342
0
  int err;
343
344
0
  err = uv__signal_loop_once_init(loop);
345
0
  if (err)
346
0
    return err;
347
348
0
  uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
349
0
  handle->signum = 0;
350
0
  handle->caught_signals = 0;
351
0
  handle->dispatched_signals = 0;
352
353
0
  return 0;
354
0
}
355
356
357
0
void uv__signal_close(uv_signal_t* handle) {
358
0
  uv__signal_stop(handle);
359
0
}
360
361
362
0
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
363
0
  return uv__signal_start(handle, signal_cb, signum, 0);
364
0
}
365
366
367
int uv_signal_start_oneshot(uv_signal_t* handle,
368
                            uv_signal_cb signal_cb,
369
0
                            int signum) {
370
0
  return uv__signal_start(handle, signal_cb, signum, 1);
371
0
}
372
373
374
static int uv__signal_start(uv_signal_t* handle,
375
                            uv_signal_cb signal_cb,
376
                            int signum,
377
0
                            int oneshot) {
378
0
  sigset_t saved_sigmask;
379
0
  int err;
380
0
  uv_signal_t* first_handle;
381
382
0
  assert(!uv__is_closing(handle));
383
384
  /* If the user supplies signum == 0, then return an error already. If the
385
   * signum is otherwise invalid then uv__signal_register will find out
386
   * eventually.
387
   */
388
0
  if (signum == 0)
389
0
    return UV_EINVAL;
390
391
  /* Short circuit: if the signal watcher is already watching {signum} don't
392
   * go through the process of deregistering and registering the handler.
393
   * Additionally, this avoids pending signals getting lost in the small
394
   * time frame that handle->signum == 0.
395
   */
396
0
  if (signum == handle->signum) {
397
0
    handle->signal_cb = signal_cb;
398
0
    return 0;
399
0
  }
400
401
  /* If the signal handler was already active, stop it first. */
402
0
  if (handle->signum != 0) {
403
0
    uv__signal_stop(handle);
404
0
  }
405
406
0
  uv__signal_block_and_lock(&saved_sigmask);
407
408
  /* If at this point there are no active signal watchers for this signum (in
409
   * any of the loops), it's time to try and register a handler for it here.
410
   * Also in case there's only one-shot handlers and a regular handler comes in.
411
   */
412
0
  first_handle = uv__signal_first_handle(signum);
413
0
  if (first_handle == NULL ||
414
0
      (!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
415
0
    err = uv__signal_register_handler(signum, oneshot);
416
0
    if (err) {
417
      /* Registering the signal handler failed. Must be an invalid signal. */
418
0
      uv__signal_unlock_and_unblock(&saved_sigmask);
419
0
      return err;
420
0
    }
421
0
  }
422
423
0
  handle->signum = signum;
424
0
  if (oneshot)
425
0
    handle->flags |= UV_SIGNAL_ONE_SHOT;
426
427
0
  RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
428
429
0
  uv__signal_unlock_and_unblock(&saved_sigmask);
430
431
0
  handle->signal_cb = signal_cb;
432
0
  uv__handle_start(handle);
433
434
0
  return 0;
435
0
}
436
437
438
0
void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
439
0
  uv__signal_msg_t* msg;
440
0
  uv_signal_t* handle;
441
0
  char buf[sizeof(uv__signal_msg_t) * 32];
442
0
  size_t bytes, end, i;
443
0
  int r;
444
445
0
  bytes = 0;
446
0
  end = 0;
447
448
0
  do {
449
0
    r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
450
451
0
    if (r == -1 && errno == EINTR)
452
0
      continue;
453
454
0
    if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
455
      /* If there are bytes in the buffer already (which really is extremely
456
       * unlikely if possible at all) we can't exit the function here. We'll
457
       * spin until more bytes are read instead.
458
       */
459
0
      if (bytes > 0)
460
0
        continue;
461
462
      /* Otherwise, there was nothing there. */
463
0
      return;
464
0
    }
465
466
    /* Other errors really should never happen. */
467
0
    if (r == -1)
468
0
      abort();
469
470
0
    bytes += r;
471
472
    /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
473
0
    end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
474
475
0
    for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
476
0
      msg = (uv__signal_msg_t*) (buf + i);
477
0
      handle = msg->handle;
478
479
0
      if (msg->signum == handle->signum) {
480
0
        assert(!(handle->flags & UV_HANDLE_CLOSING));
481
0
        handle->signal_cb(handle, handle->signum);
482
0
      }
483
484
0
      handle->dispatched_signals++;
485
486
0
      if (handle->flags & UV_SIGNAL_ONE_SHOT)
487
0
        uv__signal_stop(handle);
488
0
    }
489
490
0
    bytes -= end;
491
492
    /* If there are any "partial" messages left, move them to the start of the
493
     * the buffer, and spin. This should not happen.
494
     */
495
0
    if (bytes) {
496
0
      memmove(buf, buf + end, bytes);
497
0
      continue;
498
0
    }
499
0
  } while (end == sizeof buf);
500
0
}
501
502
503
0
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
504
0
  int f1;
505
0
  int f2;
506
  /* Compare signums first so all watchers with the same signnum end up
507
   * adjacent.
508
   */
509
0
  if (w1->signum < w2->signum) return -1;
510
0
  if (w1->signum > w2->signum) return 1;
511
512
  /* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
513
   * handler returned is a one-shot handler, the rest will be too.
514
   */
515
0
  f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
516
0
  f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
517
0
  if (f1 < f2) return -1;
518
0
  if (f1 > f2) return 1;
519
520
  /* Sort by loop pointer, so we can easily look up the first item after
521
   * { .signum = x, .loop = NULL }.
522
   */
523
0
  if (w1->loop < w2->loop) return -1;
524
0
  if (w1->loop > w2->loop) return 1;
525
526
0
  if (w1 < w2) return -1;
527
0
  if (w1 > w2) return 1;
528
529
0
  return 0;
530
0
}
531
532
533
0
int uv_signal_stop(uv_signal_t* handle) {
534
0
  assert(!uv__is_closing(handle));
535
0
  uv__signal_stop(handle);
536
0
  return 0;
537
0
}
538
539
540
0
static void uv__signal_stop(uv_signal_t* handle) {
541
0
  uv_signal_t* removed_handle;
542
0
  sigset_t saved_sigmask;
543
0
  uv_signal_t* first_handle;
544
0
  int rem_oneshot;
545
0
  int first_oneshot;
546
0
  int ret;
547
548
  /* If the watcher wasn't started, this is a no-op. */
549
0
  if (handle->signum == 0)
550
0
    return;
551
552
0
  uv__signal_block_and_lock(&saved_sigmask);
553
554
0
  removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
555
0
  assert(removed_handle == handle);
556
0
  (void) removed_handle;
557
558
  /* Check if there are other active signal watchers observing this signal. If
559
   * not, unregister the signal handler.
560
   */
561
0
  first_handle = uv__signal_first_handle(handle->signum);
562
0
  if (first_handle == NULL) {
563
0
    uv__signal_unregister_handler(handle->signum);
564
0
  } else {
565
0
    rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
566
0
    first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
567
0
    if (first_oneshot && !rem_oneshot) {
568
0
      ret = uv__signal_register_handler(handle->signum, 1);
569
0
      assert(ret == 0);
570
0
      (void)ret;
571
0
    }
572
0
  }
573
574
0
  uv__signal_unlock_and_unblock(&saved_sigmask);
575
576
0
  handle->signum = 0;
577
0
  uv__handle_stop(handle);
578
0
}