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