Lely core libraries  2.2.5
sigset.c
Go to the documentation of this file.
1 
24 #include "io.h"
25 
26 #if _POSIX_C_SOURCE >= 200112L
27 
28 #include "../sigset.h"
29 #include "fd.h"
30 #include <lely/io2/ctx.h>
31 #include <lely/io2/posix/poll.h>
32 #include <lely/io2/sys/sigset.h>
33 #include <lely/util/diag.h>
34 #include <lely/util/util.h>
35 
36 #include <assert.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include <fcntl.h>
42 #if !LELY_NO_THREADS
43 #include <pthread.h>
44 #include <sched.h>
45 #endif
46 #include <unistd.h>
47 
48 #ifndef LELY_NSIG
49 #ifdef _NSIG
50 #define LELY_NSIG _NSIG
51 #else
52 #define LELY_NSIG 128
53 #endif
54 #endif
55 
57  struct io_sigset_node *next;
58  unsigned signo : 30;
59  unsigned watched : 1;
60  unsigned pending : 1;
61 };
62 
63 #define IO_SIGSET_NODE_INIT(signo) \
64  { \
65  NULL, (signo), 0, 0 \
66  }
67 
68 static struct {
69 #if !LELY_NO_THREADS
70  pthread_mutex_t mtx;
71 #endif
72  sig_atomic_t pending;
73  struct {
74  sig_atomic_t pending;
75  sig_atomic_t fd;
76  struct io_sigset_node *list;
77  } sig[LELY_NSIG - 1];
78 } io_sigset_shared = {
79 #if !LELY_NO_THREADS
80  PTHREAD_MUTEX_INITIALIZER,
81 #endif
82  0, { { 0, 0, NULL } }
83 };
84 
85 static struct sigaction io_sigset_action[LELY_NSIG - 1];
86 
87 static void io_sigset_handler(int signo);
88 static void io_sigset_kill(int signo);
89 static void io_sigset_process_all(void);
90 static void io_sigset_process_sig(int signo, struct sllist *queue);
91 
92 static io_ctx_t *io_sigset_impl_dev_get_ctx(const io_dev_t *dev);
93 static ev_exec_t *io_sigset_impl_dev_get_exec(const io_dev_t *dev);
94 static size_t io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task);
95 static size_t io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task);
96 
97 // clang-format off
98 static const struct io_dev_vtbl io_sigset_impl_dev_vtbl = {
99  &io_sigset_impl_dev_get_ctx,
100  &io_sigset_impl_dev_get_exec,
101  &io_sigset_impl_dev_cancel,
102  &io_sigset_impl_dev_abort
103 };
104 // clang-format on
105 
106 static io_dev_t *io_sigset_impl_get_dev(const io_sigset_t *sigset);
107 static int io_sigset_impl_clear(io_sigset_t *sigset);
108 static int io_sigset_impl_insert(io_sigset_t *sigset, int signo);
109 static int io_sigset_impl_remove(io_sigset_t *sigset, int signo);
110 static void io_sigset_impl_submit_wait(
111  io_sigset_t *sigset, struct io_sigset_wait *wait);
112 
113 // clang-format off
114 static const struct io_sigset_vtbl io_sigset_impl_vtbl = {
115  &io_sigset_impl_get_dev,
116  &io_sigset_impl_clear,
117  &io_sigset_impl_insert,
118  &io_sigset_impl_remove,
119  &io_sigset_impl_submit_wait
120 };
121 // clang-format on
122 
123 static int io_sigset_impl_svc_notify_fork(
124  struct io_svc *svc, enum io_fork_event e);
125 static void io_sigset_impl_svc_shutdown(struct io_svc *svc);
126 
127 // clang-format off
128 static const struct io_svc_vtbl io_sigset_impl_svc_vtbl = {
129  &io_sigset_impl_svc_notify_fork,
130  &io_sigset_impl_svc_shutdown
131 };
132 // clang-format on
133 
135  const struct io_dev_vtbl *dev_vptr;
136  const struct io_sigset_vtbl *sigset_vptr;
137  io_poll_t *poll;
138  struct io_svc svc;
139  io_ctx_t *ctx;
140  ev_exec_t *exec;
141  struct io_poll_watch watch;
142  int fds[2];
143  struct ev_task read_task;
144  struct ev_task wait_task;
145 #if !LELY_NO_THREADS
146  pthread_mutex_t mtx;
147 #endif
148  unsigned shutdown : 1;
149  unsigned read_posted : 1;
150  unsigned wait_posted : 1;
151  unsigned pending : 1;
152  struct sllist queue;
153  struct io_sigset_node nodes[LELY_NSIG - 1];
154 };
155 
156 static void io_sigset_impl_watch_func(struct io_poll_watch *watch, int events);
157 static void io_sigset_impl_read_task_func(struct ev_task *task);
158 static void io_sigset_impl_wait_task_func(struct ev_task *task);
159 
160 static inline struct io_sigset_impl *io_sigset_impl_from_dev(
161  const io_dev_t *dev);
162 static inline struct io_sigset_impl *io_sigset_impl_from_sigset(
163  const io_sigset_t *sigset);
164 static inline struct io_sigset_impl *io_sigset_impl_from_svc(
165  const struct io_svc *svc);
166 
167 static void io_sigset_impl_pop(struct io_sigset_impl *impl,
168  struct sllist *queue, struct ev_task *task);
169 
170 static int io_sigset_impl_open(struct io_sigset_impl *impl);
171 static int io_sigset_impl_close(struct io_sigset_impl *impl);
172 
173 static int io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo);
174 static int io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo);
175 
176 static size_t io_sigset_impl_do_abort_tasks(struct io_sigset_impl *impl);
177 
178 void *
179 io_sigset_alloc(void)
180 {
181  struct io_sigset_impl *impl = malloc(sizeof(*impl));
182  // cppcheck-suppress memleak symbolName=impl
183  return impl ? &impl->sigset_vptr : NULL;
184 }
185 
186 void
187 io_sigset_free(void *ptr)
188 {
189  if (ptr)
190  free(io_sigset_impl_from_sigset(ptr));
191 }
192 
193 io_sigset_t *
194 io_sigset_init(io_sigset_t *sigset, io_poll_t *poll, ev_exec_t *exec)
195 {
196  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
197  assert(poll);
198  assert(exec);
199  io_ctx_t *ctx = io_poll_get_ctx(poll);
200  assert(ctx);
201 
202  int errsv = 0;
203 
204  impl->dev_vptr = &io_sigset_impl_dev_vtbl;
205  impl->sigset_vptr = &io_sigset_impl_vtbl;
206 
207  impl->poll = poll;
208 
209  impl->svc = (struct io_svc)IO_SVC_INIT(&io_sigset_impl_svc_vtbl);
210  impl->ctx = ctx;
211 
212  impl->exec = exec;
213 
214  impl->watch = (struct io_poll_watch)IO_POLL_WATCH_INIT(
215  &io_sigset_impl_watch_func);
216  impl->fds[0] = impl->fds[1] = -1;
217 
218  impl->read_task = (struct ev_task)EV_TASK_INIT(
219  impl->exec, &io_sigset_impl_read_task_func);
220  impl->wait_task = (struct ev_task)EV_TASK_INIT(
221  impl->exec, &io_sigset_impl_wait_task_func);
222 
223 #if !LELY_NO_THREADS
224  if ((errsv = pthread_mutex_init(&impl->mtx, NULL)))
225  goto error_init_mtx;
226 #endif
227 
228  impl->shutdown = 0;
229  impl->read_posted = 0;
230  impl->wait_posted = 0;
231  impl->pending = 0;
232 
233  sllist_init(&impl->queue);
234 
235  for (int i = 1; i < LELY_NSIG; i++)
236  impl->nodes[i - 1] =
237  (struct io_sigset_node)IO_SIGSET_NODE_INIT(i);
238 
239  if (io_sigset_impl_open(impl) == -1) {
240  errsv = errno;
241  goto error_open;
242  }
243 
244  io_ctx_insert(impl->ctx, &impl->svc);
245 
246  return sigset;
247 
248  // io_sigset_impl_close(impl);
249 error_open:
250 #if !LELY_NO_THREADS
251  pthread_mutex_destroy(&impl->mtx);
252 error_init_mtx:
253 #endif
254  errno = errsv;
255  return NULL;
256 }
257 
258 void
259 io_sigset_fini(io_sigset_t *sigset)
260 {
261  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
262 
263  io_ctx_remove(impl->ctx, &impl->svc);
264  // Cancel all pending tasks.
265  io_sigset_impl_svc_shutdown(&impl->svc);
266 
267  // Stop monitoring signals.
268  io_sigset_impl_clear(sigset);
269 
270 #if !LELY_NO_THREADS
271  int warning = 0;
272  pthread_mutex_lock(&impl->mtx);
273  // If necessary, busy-wait until io_sigset_impl_read_task_func() and
274  // io_sigset_impl_wait_task_func() complete.
275  while (impl->read_posted || impl->wait_posted) {
276  if (io_sigset_impl_do_abort_tasks(impl))
277  continue;
278  pthread_mutex_unlock(&impl->mtx);
279  if (!warning) {
280  warning = 1;
281  diag(DIAG_WARNING, 0,
282  "io_sigset_fini() invoked with pending operations");
283  }
284  sched_yield();
285  pthread_mutex_lock(&impl->mtx);
286  }
287  pthread_mutex_unlock(&impl->mtx);
288 #endif
289 
290  // Close the self-pipe.
291  io_sigset_impl_close(impl);
292 
293 #if !LELY_NO_THREADS
294  pthread_mutex_destroy(&impl->mtx);
295 #endif
296 }
297 
298 io_sigset_t *
300 {
301  int errsv = 0;
302 
303  io_sigset_t *sigset = io_sigset_alloc();
304  if (!sigset) {
305  errsv = errno;
306  goto error_alloc;
307  }
308 
309  io_sigset_t *tmp = io_sigset_init(sigset, poll, exec);
310  if (!tmp) {
311  errsv = errno;
312  goto error_init;
313  }
314  sigset = tmp;
315 
316  return sigset;
317 
318 error_init:
319  io_sigset_free((void *)sigset);
320 error_alloc:
321  errno = errsv;
322  return NULL;
323 }
324 
325 void
327 {
328  if (sigset) {
329  io_sigset_fini(sigset);
330  io_sigset_free((void *)sigset);
331  }
332 }
333 
334 static void
335 io_sigset_handler(int signo)
336 {
337  io_sigset_shared.sig[signo - 1].pending = 1;
338  io_sigset_shared.pending = 1;
339 
340  io_sigset_kill(signo);
341 }
342 
343 static void
344 io_sigset_kill(int signo)
345 {
346  int errsv = errno;
347  ssize_t result;
348  do {
349  errno = 0;
350  result = write(io_sigset_shared.sig[signo - 1].fd - 1, "", 1);
351  } while (result == -1 && errno == EINTR);
352  errno = errsv;
353 }
354 
355 static void
356 io_sigset_process_all(void)
357 {
358  struct sllist queue;
359  sllist_init(&queue);
360 
361 #if !LELY_NO_THREADS
362  pthread_mutex_lock(&io_sigset_shared.mtx);
363 #endif
364  while (io_sigset_shared.pending) {
365  io_sigset_shared.pending = 0;
366  for (int i = 1; i < LELY_NSIG; i++) {
367  if (io_sigset_shared.sig[i - 1].pending) {
368  io_sigset_shared.sig[i - 1].pending = 0;
369  io_sigset_process_sig(i, &queue);
370  }
371  }
372  }
373 #if !LELY_NO_THREADS
374  pthread_mutex_unlock(&io_sigset_shared.mtx);
375 #endif
376 
377  struct slnode *node;
378  while ((node = sllist_pop_front(&queue))) {
379  struct ev_task *task = ev_task_from_node(node);
380  ev_exec_post(task->exec, task);
381  }
382 }
383 
384 static void
385 io_sigset_process_sig(int signo, struct sllist *queue)
386 {
387  for (struct io_sigset_node *node = io_sigset_shared.sig[signo - 1].list;
388  node; node = node->next) {
389  struct io_sigset_impl *impl = structof(
390  node, struct io_sigset_impl, nodes[signo - 1]);
391 #if !LELY_NO_THREADS
392  pthread_mutex_lock(&impl->mtx);
393 #endif
394  assert(node->watched);
395  if (!node->pending) {
396  node->pending = 1;
397  impl->pending = 1;
398  if (!impl->wait_posted) {
399  impl->wait_posted = 1;
400  sllist_push_back(queue, &impl->wait_task._node);
401  }
402  }
403 #if !LELY_NO_THREADS
404  pthread_mutex_unlock(&impl->mtx);
405 #endif
406  }
407 }
408 
409 static io_ctx_t *
410 io_sigset_impl_dev_get_ctx(const io_dev_t *dev)
411 {
412  const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
413 
414  return impl->ctx;
415 }
416 
417 static ev_exec_t *
418 io_sigset_impl_dev_get_exec(const io_dev_t *dev)
419 {
420  const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
421 
422  return impl->exec;
423 }
424 
425 static size_t
426 io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task)
427 {
428  struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
429 
430  struct sllist queue;
431  sllist_init(&queue);
432 
433  io_sigset_impl_pop(impl, &queue, task);
434 
435  return io_sigset_wait_queue_post(&queue, 0);
436 }
437 
438 static size_t
439 io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task)
440 {
441  struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
442 
443  struct sllist queue;
444  sllist_init(&queue);
445 
446  io_sigset_impl_pop(impl, &queue, task);
447 
448  return ev_task_queue_abort(&queue);
449 }
450 
451 static io_dev_t *
452 io_sigset_impl_get_dev(const io_sigset_t *sigset)
453 {
454  const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
455 
456  return &impl->dev_vptr;
457 }
458 
459 static int
460 io_sigset_impl_clear(io_sigset_t *sigset)
461 {
462  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
463 
464 #if !LELY_NO_THREADS
465  // Locking this mutex may fail since it is statically initialized.
466  int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
467  if (errsv) {
468  errno = errsv;
469  return -1;
470  }
471 #endif
472 
473  int result = 0;
474  for (int i = 1; i < LELY_NSIG; i++) {
475  if (io_sigset_impl_do_remove(impl, i) == -1)
476  result = -1;
477  }
478 
479 #if !LELY_NO_THREADS
480  pthread_mutex_unlock(&io_sigset_shared.mtx);
481 #endif
482 
483  return result;
484 }
485 
486 static int
487 io_sigset_impl_insert(io_sigset_t *sigset, int signo)
488 {
489  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
490 
491  if (signo <= 0 || signo >= LELY_NSIG) {
492  errno = EINVAL;
493  return -1;
494  }
495 
496 #if !LELY_NO_THREADS
497  // Locking this mutex may fail since it is statically initialized.
498  int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
499  if (errsv) {
500  errno = errsv;
501  return -1;
502  }
503 #endif
504 
505  int result = io_sigset_impl_do_insert(impl, signo);
506 
507 #if !LELY_NO_THREADS
508  pthread_mutex_unlock(&io_sigset_shared.mtx);
509 #endif
510 
511  return result;
512 }
513 
514 static int
515 io_sigset_impl_remove(io_sigset_t *sigset, int signo)
516 {
517  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
518 
519  if (signo <= 0 || signo >= LELY_NSIG) {
520  errno = EINVAL;
521  return -1;
522  }
523 
524 #if !LELY_NO_THREADS
525  // Locking this mutex may fail since it is statically initialized.
526  int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
527  if (errsv) {
528  errno = errsv;
529  return -1;
530  }
531 #endif
532 
533  int result = io_sigset_impl_do_remove(impl, signo);
534 
535 #if !LELY_NO_THREADS
536  pthread_mutex_unlock(&io_sigset_shared.mtx);
537 #endif
538 
539  return result;
540 }
541 
542 static void
543 io_sigset_impl_submit_wait(io_sigset_t *sigset, struct io_sigset_wait *wait)
544 {
545  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
546  assert(wait);
547  struct ev_task *task = &wait->task;
548 
549  if (!task->exec)
550  task->exec = impl->exec;
551  ev_exec_on_task_init(task->exec);
552 
553 #if !LELY_NO_THREADS
554  pthread_mutex_lock(&impl->mtx);
555 #endif
556  if (impl->shutdown) {
557 #if !LELY_NO_THREADS
558  pthread_mutex_unlock(&impl->mtx);
559 #endif
560  io_sigset_wait_post(wait, 0);
561  } else {
562  sllist_push_back(&impl->queue, &task->_node);
563  int post_wait = !impl->wait_posted && impl->pending;
564  if (post_wait)
565  impl->wait_posted = 1;
566 #if !LELY_NO_THREADS
567  pthread_mutex_unlock(&impl->mtx);
568 #endif
569  if (post_wait)
570  ev_exec_post(impl->wait_task.exec, &impl->wait_task);
571  }
572 }
573 
574 static int
575 io_sigset_impl_svc_notify_fork(struct io_svc *svc, enum io_fork_event e)
576 {
577  struct io_sigset_impl *impl = io_sigset_impl_from_svc(svc);
578 
579  if (e != IO_FORK_CHILD || impl->shutdown)
580  return 0;
581 
582  int result = 0;
583  int errsv = errno;
584 
585  if (io_sigset_impl_close(impl) == -1 && !result) {
586  errsv = errno;
587  result = -1;
588  }
589 
590  if (io_sigset_impl_open(impl) == -1 && !result) {
591  errsv = errno;
592  result = -1;
593  }
594 
595  errno = errsv;
596  return result;
597 }
598 
599 static void
600 io_sigset_impl_svc_shutdown(struct io_svc *svc)
601 {
602  struct io_sigset_impl *impl = io_sigset_impl_from_svc(svc);
603  io_dev_t *dev = &impl->dev_vptr;
604 
605 #if !LELY_NO_THREADS
606  pthread_mutex_lock(&impl->mtx);
607 #endif
608  int shutdown = !impl->shutdown;
609  impl->shutdown = 1;
610  if (shutdown) {
611  // Stop monitoring the self-pipe.
612  io_poll_watch(impl->poll, impl->fds[0], 0, &impl->watch);
613  // Try to abort io_sigset_impl_read_task_func() and
614  // io_sigset_impl_wait_task_func().
615  io_sigset_impl_do_abort_tasks(impl);
616  }
617 #if !LELY_NO_THREADS
618  pthread_mutex_unlock(&impl->mtx);
619 #endif
620 
621  if (shutdown)
622  // Cancel all pending operations.
623  io_sigset_impl_dev_cancel(dev, NULL);
624 }
625 
626 static void
627 io_sigset_impl_watch_func(struct io_poll_watch *watch, int events)
628 {
629  assert(watch);
630  struct io_sigset_impl *impl =
631  structof(watch, struct io_sigset_impl, watch);
632  (void)events;
633 
634 #if !LELY_NO_THREADS
635  pthread_mutex_lock(&impl->mtx);
636 #endif
637  int post_read = !impl->read_posted;
638  impl->read_posted = 1;
639 #if !LELY_NO_THREADS
640  pthread_mutex_unlock(&impl->mtx);
641 #endif
642 
643  if (post_read)
644  ev_exec_post(impl->read_task.exec, &impl->read_task);
645 }
646 
647 static void
648 io_sigset_impl_read_task_func(struct ev_task *task)
649 {
650  assert(task);
651  struct io_sigset_impl *impl =
652  structof(task, struct io_sigset_impl, read_task);
653 
654  int errsv = errno;
655  int pending = 0;
656  int events = 0;
657 
658  ssize_t result;
659  do {
660  char buf[LELY_VLA_SIZE_MAX];
661  errno = 0;
662  result = read(impl->fds[0], buf, sizeof(buf));
663  if (result > 0)
664  pending = 1;
665  } while (result > 0 || (result == -1 && errno == EINTR));
666  if (result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
667  events |= IO_EVENT_IN;
668 
669  if (pending)
670  io_sigset_process_all();
671 
672 #if !LELY_NO_THREADS
673  pthread_mutex_lock(&impl->mtx);
674 #endif
675  if (events && !impl->shutdown)
676  io_poll_watch(impl->poll, impl->fds[0], events, &impl->watch);
677  impl->read_posted = 0;
678 #if !LELY_NO_THREADS
679  pthread_mutex_unlock(&impl->mtx);
680 #endif
681 
682  errno = errsv;
683 }
684 
685 static void
686 io_sigset_impl_wait_task_func(struct ev_task *task)
687 {
688  assert(task);
689  struct io_sigset_impl *impl =
690  structof(task, struct io_sigset_impl, wait_task);
691 
692  struct io_sigset_wait *wait = NULL;
693  int signo = LELY_NSIG;
694 
695 #if !LELY_NO_THREADS
696  pthread_mutex_lock(&impl->mtx);
697 #endif
698  if (!sllist_empty(&impl->queue)) {
699  for (signo = 1; signo < LELY_NSIG; signo++) {
700  struct io_sigset_node *node = &impl->nodes[signo - 1];
701  if (node->pending) {
702  node->pending = 0;
703  task = ev_task_from_node(
704  sllist_pop_front(&impl->queue));
705  wait = io_sigset_wait_from_task(task);
706  break;
707  }
708  }
709  }
710 
711  impl->pending = signo != LELY_NSIG;
712  int post_wait = impl->wait_posted = impl->pending
713  && !sllist_empty(&impl->queue) && !impl->shutdown;
714 #if !LELY_NO_THREADS
715  pthread_mutex_unlock(&impl->mtx);
716 #endif
717 
718  if (wait)
719  io_sigset_wait_post(wait, signo);
720 
721  if (post_wait)
722  ev_exec_post(impl->wait_task.exec, &impl->wait_task);
723 }
724 
725 static inline struct io_sigset_impl *
726 io_sigset_impl_from_dev(const io_dev_t *dev)
727 {
728  assert(dev);
729 
730  return structof(dev, struct io_sigset_impl, dev_vptr);
731 }
732 
733 static inline struct io_sigset_impl *
734 io_sigset_impl_from_sigset(const io_sigset_t *sigset)
735 {
736  assert(sigset);
737 
738  return structof(sigset, struct io_sigset_impl, sigset_vptr);
739 }
740 
741 static inline struct io_sigset_impl *
742 io_sigset_impl_from_svc(const struct io_svc *svc)
743 {
744  assert(svc);
745 
746  return structof(svc, struct io_sigset_impl, svc);
747 }
748 
749 static void
750 io_sigset_impl_pop(struct io_sigset_impl *impl, struct sllist *queue,
751  struct ev_task *task)
752 {
753  assert(impl);
754  assert(queue);
755 
756 #if !LELY_NO_THREADS
757  pthread_mutex_lock(&impl->mtx);
758 #endif
759  if (!task)
760  sllist_append(queue, &impl->queue);
761  else if (sllist_remove(&impl->queue, &task->_node))
762  sllist_push_back(queue, &task->_node);
763 #if !LELY_NO_THREADS
764  pthread_mutex_unlock(&impl->mtx);
765 #endif
766 }
767 
768 static int
769 io_sigset_impl_open(struct io_sigset_impl *impl)
770 {
771  assert(impl);
772 
773  int errsv = 0;
774 
775  if (io_sigset_impl_close(impl) == -1) {
776  errsv = errno;
777  goto error_close;
778  }
779 
780 #ifdef __linux__
781  if (pipe2(impl->fds, O_CLOEXEC | O_NONBLOCK) == -1) {
782 #else
783  if (pipe(impl->fds) == -1) {
784 #endif
785  errsv = errno;
786  goto error_pipe;
787  }
788 
789  // We need to be able to store the write end of the pipe in a
790  // sig_atomic_t variable.
791  if (impl->fds[1] - 1 > SIG_ATOMIC_MAX) {
792  errno = EBADF;
793  goto error_sig_atomic;
794  }
795 
796 #ifndef __linux__
797  if (io_fd_set_cloexec(impl->fds[0]) == -1) {
798  errsv = errno;
799  goto error_cloexec;
800  }
801 
802  if (io_fd_set_cloexec(impl->fds[1]) == -1) {
803  errsv = errno;
804  goto error_cloexec;
805  }
806 
807  if (io_fd_set_nonblock(impl->fds[0]) == -1) {
808  errsv = errno;
809  goto error_nonblock;
810  }
811 
812  if (io_fd_set_nonblock(impl->fds[1]) == -1) {
813  errsv = errno;
814  goto error_nonblock;
815  }
816 #endif // !__linux__
817 
818  // clang-format off
819  if (io_poll_watch(impl->poll, impl->fds[0], IO_EVENT_IN, &impl->watch)
820  == -1) {
821  // clang-format on
822  errsv = errno;
823  goto error_poll_watch;
824  }
825 
826  return 0;
827 
828 error_poll_watch:
829 #ifndef __linux__
830 error_nonblock:
831 error_cloexec:
832 #endif
833 error_sig_atomic:
834  close(impl->fds[1]);
835  close(impl->fds[0]);
836  impl->fds[0] = impl->fds[1] = -1;
837 error_pipe:
838 error_close:
839  errno = errsv;
840  return -1;
841 }
842 
843 static int
844 io_sigset_impl_close(struct io_sigset_impl *impl)
845 {
846  assert(impl);
847 
848  int fds[2] = { impl->fds[0], impl->fds[1] };
849  if (fds[0] == -1)
850  return 0;
851  impl->fds[0] = impl->fds[1] = -1;
852 
853  int result = 0;
854  int errsv = errno;
855 
856  if (!impl->shutdown
857  && io_poll_watch(impl->poll, fds[0], 0, &impl->watch)
858  == -1
859  && !result) {
860  errsv = errno;
861  result = -1;
862  }
863 
864  if (close(fds[1]) == -1 && !result) {
865  errsv = errno;
866  result = -1;
867  }
868 
869  if (close(fds[0]) == -1 && !result) {
870  errsv = errno;
871  result = -1;
872  }
873 
874  errno = errsv;
875  return result;
876 }
877 
878 static int
879 io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo)
880 {
881  assert(impl);
882  assert(signo > 0);
883  assert(signo < LELY_NSIG);
884 
885  struct io_sigset_node *node = &impl->nodes[signo - 1];
886  assert(node->signo == signo);
887 
888  if (node->watched)
889  return 0;
890 
891  if (!io_sigset_shared.sig[signo - 1].list) {
892  assert(!io_sigset_shared.sig[signo - 1].fd);
893  io_sigset_shared.sig[signo - 1].fd = impl->fds[1] + 1;
894 
895  struct sigaction act;
896  memset(&act, 0, sizeof(act));
897  act.sa_handler = &io_sigset_handler;
898  sigemptyset(&act.sa_mask);
899  act.sa_flags = SA_RESTART;
900 
901  if (sigaction(signo, &act, &io_sigset_action[signo - 1])
902  == -1) {
903  io_sigset_shared.sig[signo - 1].fd = 0;
904  return -1;
905  }
906  }
907 
908  node->next = io_sigset_shared.sig[signo - 1].list;
909  io_sigset_shared.sig[signo - 1].list = node;
910 
911  node->watched = 1;
912  assert(!node->pending);
913 
914  return 0;
915 }
916 
917 static int
918 io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo)
919 {
920  assert(impl);
921  assert(signo > 0);
922  assert(signo < LELY_NSIG);
923 
924  struct io_sigset_node *node = &impl->nodes[signo - 1];
925  assert(node->signo == signo);
926 
927  if (!node->watched)
928  return 0;
929 
930  struct io_sigset_node **pnode = &io_sigset_shared.sig[signo - 1].list;
931  assert(*pnode);
932  while (*pnode != node)
933  pnode = &(*pnode)->next;
934  assert(*pnode == node);
935  *pnode = node->next;
936  node->next = NULL;
937 
938  node->watched = 0;
939  node->pending = 0;
940 
941  int result = 0;
942 
943  if (!*pnode) {
944  assert(io_sigset_shared.sig[signo - 1].fd == impl->fds[1] + 1);
945  if (pnode == &io_sigset_shared.sig[signo - 1].list) {
946  result = sigaction(signo, &io_sigset_action[signo - 1],
947  NULL);
948 
949  io_sigset_shared.sig[signo - 1].fd = 0;
950  } else {
951  node = structof(pnode, struct io_sigset_node, next);
952  impl = structof(node, struct io_sigset_impl,
953  nodes[signo - 1]);
954  io_sigset_shared.sig[signo - 1].fd = impl->fds[1] + 1;
955  io_sigset_kill(signo);
956  }
957  }
958 
959  return result;
960 }
961 
962 static size_t
963 io_sigset_impl_do_abort_tasks(struct io_sigset_impl *impl)
964 {
965  assert(impl);
966 
967  size_t n = 0;
968 
969  // Try to abort io_sigset_impl_read_task_func().
970  // clang-format off
971  if (impl->read_posted && ev_exec_abort(impl->read_task.exec,
972  &impl->read_task)) {
973  // clang-format on
974  impl->read_posted = 0;
975  n++;
976  }
977 
978  // Try to abort io_sigset_impl_wait_task_func().
979  // clang-format off
980  if (impl->wait_posted && ev_exec_abort(impl->wait_task.exec,
981  &impl->wait_task)) {
982  // clang-format on
983  impl->wait_posted = 0;
984  n++;
985  }
986 
987  return n;
988 }
989 
990 #endif // _POSIX_C_SOURCE >= 200112L
This header file is part of the I/O library; it contains the I/O context and service declarations.
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
Definition: ctx.c:121
io_fork_event
The type of event generated by an I/O context before and after a process fork.
Definition: ctx.h:37
@ IO_FORK_CHILD
The event generated after the fork in the child process.
Definition: ctx.h:43
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
Definition: ctx.h:57
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
Definition: ctx.c:136
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_WARNING
A warning.
Definition: diag.h:47
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
@ IO_EVENT_IN
Data (other than priority data) MAY be read without blocking.
Definition: event.h:35
size_t ev_exec_abort(ev_exec_t *exec, struct ev_task *task)
Aborts the specified task submitted to *exec, if it has not yet begun executing, or all pending tasks...
Definition: exec.h:138
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
Definition: exec.h:126
void ev_exec_on_task_init(ev_exec_t *exec)
Indicates to the specified executor that a task will be submitted for execution in the future.
Definition: exec.h:108
int io_fd_set_cloexec(int fd)
Sets the FD_CLOEXEC flag of the file descriptor fd.
Definition: fd.c:33
int io_fd_set_nonblock(int fd)
Sets the O_NONBLOCK flag of the file descriptor fd.
Definition: fd.c:44
This is the internal header file of the common file descriptor functions.
#define LELY_VLA_SIZE_MAX
The maximum size (in bytes) of stack-allocated arrays.
Definition: features.h:300
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
const struct io_sigset_vtbl *const io_sigset_t
An abstract signal handler.
Definition: sigset.h:40
This header file is part of the I/O library; it contains the system signal handler declarations.
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
This header file is part of the I/O library; it contains the I/O polling declarations for POSIX platf...
io_ctx_t * io_poll_get_ctx(const io_poll_t *poll)
Returns a pointer to the I/O context with which the I/O polling instance is registered.
Definition: poll.c:275
#define IO_POLL_WATCH_INIT(func)
The static initializer for io_poll_watch.
Definition: poll.h:65
int io_poll_watch(io_poll_t *poll, io_handle_t handle, struct io_event *event, int keep)
Registers an I/O device with an I/O polling interface and instructs it to watch for certain events.
Definition: poll.c:249
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a system signal handler.
Definition: sigset.c:326
io_sigset_t * io_sigset_create(io_poll_t *poll, ev_exec_t *exec)
Creates a new system signal handler.
Definition: sigset.c:299
struct io_sigset_wait * io_sigset_wait_from_task(struct ev_task *task)
Obtains a pointer to a signal wait operation from a pointer to its completion task.
Definition: sigset.c:61
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:184
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
Definition: sllist.h:233
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
Definition: sllist.c:46
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
Definition: sllist.h:213
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
Definition: sllist.h:190
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition: sllist.h:221
This is the internal header file of the Windows-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
An I/O polling interface.
Definition: poll.c:48
An executable task.
Definition: task.h:41
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
Definition: ctx.c:35
An object representing a file descriptor being monitored for I/O events.
Definition: poll.h:56
A wait operation suitable for use with a signal handler.
Definition: sigset.h:43
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
Definition: sigset.h:48
int signo
The signal number, or 0 if the wait operation was canceled.
Definition: sigset.h:50
The virtual table of an I/O service.
Definition: ctx.h:67
An I/O service.
Definition: ctx.h:49
A node in a pairing heap.
Definition: pheap.h:51
struct pnode * next
A pointer to the next sibling node.
Definition: pheap.h:61
A singly-linked list.
Definition: sllist.h:51
A node in a singly-linked list.
Definition: sllist.h:39
struct slnode * next
A pointer to the next node in the list.
Definition: sllist.h:41
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
Definition: task.c:55
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node.
Definition: task.c:32
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....