26 #if _POSIX_C_SOURCE >= 200112L
28 #include "../sigset.h"
50 #define LELY_NSIG _NSIG
63 #define IO_SIGSET_NODE_INIT(signo) \
78 } io_sigset_shared = {
80 PTHREAD_MUTEX_INITIALIZER,
85 static struct sigaction io_sigset_action[LELY_NSIG - 1];
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);
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);
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
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(
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
123 static int io_sigset_impl_svc_notify_fork(
125 static void io_sigset_impl_svc_shutdown(
struct io_svc *svc);
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
148 unsigned shutdown : 1;
149 unsigned read_posted : 1;
150 unsigned wait_posted : 1;
151 unsigned pending : 1;
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);
165 const struct io_svc *svc);
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);
176 static size_t io_sigset_impl_do_abort_tasks(
struct io_sigset_impl *impl);
179 io_sigset_alloc(
void)
183 return impl ? &impl->sigset_vptr : NULL;
187 io_sigset_free(
void *ptr)
190 free(io_sigset_impl_from_sigset(ptr));
204 impl->dev_vptr = &io_sigset_impl_dev_vtbl;
205 impl->sigset_vptr = &io_sigset_impl_vtbl;
215 &io_sigset_impl_watch_func);
216 impl->fds[0] = impl->fds[1] = -1;
219 impl->
exec, &io_sigset_impl_read_task_func);
221 impl->
exec, &io_sigset_impl_wait_task_func);
224 if ((errsv = pthread_mutex_init(&impl->mtx, NULL)))
229 impl->read_posted = 0;
230 impl->wait_posted = 0;
235 for (
int i = 1; i < LELY_NSIG; i++)
239 if (io_sigset_impl_open(impl) == -1) {
251 pthread_mutex_destroy(&impl->mtx);
265 io_sigset_impl_svc_shutdown(&impl->svc);
268 io_sigset_impl_clear(sigset);
272 pthread_mutex_lock(&impl->mtx);
275 while (impl->read_posted || impl->wait_posted) {
276 if (io_sigset_impl_do_abort_tasks(impl))
278 pthread_mutex_unlock(&impl->mtx);
282 "io_sigset_fini() invoked with pending operations");
285 pthread_mutex_lock(&impl->mtx);
287 pthread_mutex_unlock(&impl->mtx);
291 io_sigset_impl_close(impl);
294 pthread_mutex_destroy(&impl->mtx);
309 io_sigset_t *tmp = io_sigset_init(sigset, poll, exec);
319 io_sigset_free((
void *)sigset);
329 io_sigset_fini(sigset);
330 io_sigset_free((
void *)sigset);
335 io_sigset_handler(
int signo)
337 io_sigset_shared.sig[signo - 1].pending = 1;
338 io_sigset_shared.pending = 1;
340 io_sigset_kill(signo);
344 io_sigset_kill(
int signo)
350 result = write(io_sigset_shared.sig[signo - 1].fd - 1,
"", 1);
351 }
while (result == -1 && errno == EINTR);
356 io_sigset_process_all(
void)
362 pthread_mutex_lock(&io_sigset_shared.mtx);
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);
374 pthread_mutex_unlock(&io_sigset_shared.mtx);
385 io_sigset_process_sig(
int signo,
struct sllist *queue)
387 for (
struct io_sigset_node *node = io_sigset_shared.sig[signo - 1].list;
388 node; node = node->
next) {
392 pthread_mutex_lock(&impl->mtx);
394 assert(node->watched);
395 if (!node->pending) {
398 if (!impl->wait_posted) {
399 impl->wait_posted = 1;
404 pthread_mutex_unlock(&impl->mtx);
410 io_sigset_impl_dev_get_ctx(
const io_dev_t *dev)
418 io_sigset_impl_dev_get_exec(
const io_dev_t *dev)
433 io_sigset_impl_pop(impl, &queue, task);
435 return io_sigset_wait_queue_post(&queue, 0);
446 io_sigset_impl_pop(impl, &queue, task);
454 const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
456 return &impl->dev_vptr;
466 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
474 for (
int i = 1; i < LELY_NSIG; i++) {
475 if (io_sigset_impl_do_remove(impl, i) == -1)
480 pthread_mutex_unlock(&io_sigset_shared.mtx);
487 io_sigset_impl_insert(
io_sigset_t *sigset,
int signo)
491 if (signo <= 0 || signo >= LELY_NSIG) {
498 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
505 int result = io_sigset_impl_do_insert(impl, signo);
508 pthread_mutex_unlock(&io_sigset_shared.mtx);
515 io_sigset_impl_remove(
io_sigset_t *sigset,
int signo)
519 if (signo <= 0 || signo >= LELY_NSIG) {
526 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
533 int result = io_sigset_impl_do_remove(impl, signo);
536 pthread_mutex_unlock(&io_sigset_shared.mtx);
550 task->
exec = impl->exec;
554 pthread_mutex_lock(&impl->mtx);
556 if (impl->shutdown) {
558 pthread_mutex_unlock(&impl->mtx);
560 io_sigset_wait_post(wait, 0);
563 int post_wait = !impl->wait_posted && impl->pending;
565 impl->wait_posted = 1;
567 pthread_mutex_unlock(&impl->mtx);
585 if (io_sigset_impl_close(impl) == -1 && !result) {
590 if (io_sigset_impl_open(impl) == -1 && !result) {
600 io_sigset_impl_svc_shutdown(
struct io_svc *svc)
606 pthread_mutex_lock(&impl->mtx);
608 int shutdown = !impl->shutdown;
615 io_sigset_impl_do_abort_tasks(impl);
618 pthread_mutex_unlock(&impl->mtx);
623 io_sigset_impl_dev_cancel(dev, NULL);
627 io_sigset_impl_watch_func(
struct io_poll_watch *watch,
int events)
635 pthread_mutex_lock(&impl->mtx);
637 int post_read = !impl->read_posted;
638 impl->read_posted = 1;
640 pthread_mutex_unlock(&impl->mtx);
648 io_sigset_impl_read_task_func(
struct ev_task *task)
662 result = read(impl->fds[0], buf,
sizeof(buf));
665 }
while (result > 0 || (result == -1 && errno == EINTR));
666 if (result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
670 io_sigset_process_all();
673 pthread_mutex_lock(&impl->mtx);
675 if (events && !impl->shutdown)
676 io_poll_watch(impl->poll, impl->fds[0], events, &impl->watch);
677 impl->read_posted = 0;
679 pthread_mutex_unlock(&impl->mtx);
686 io_sigset_impl_wait_task_func(
struct ev_task *task)
693 int signo = LELY_NSIG;
696 pthread_mutex_lock(&impl->mtx);
711 impl->pending = signo != LELY_NSIG;
712 int post_wait = impl->wait_posted = impl->pending
715 pthread_mutex_unlock(&impl->mtx);
719 io_sigset_wait_post(wait, signo);
726 io_sigset_impl_from_dev(
const io_dev_t *dev)
734 io_sigset_impl_from_sigset(
const io_sigset_t *sigset)
742 io_sigset_impl_from_svc(
const struct io_svc *svc)
757 pthread_mutex_lock(&impl->mtx);
764 pthread_mutex_unlock(&impl->mtx);
775 if (io_sigset_impl_close(impl) == -1) {
781 if (pipe2(impl->fds, O_CLOEXEC | O_NONBLOCK) == -1) {
783 if (pipe(impl->fds) == -1) {
791 if (impl->fds[1] - 1 > SIG_ATOMIC_MAX) {
793 goto error_sig_atomic;
823 goto error_poll_watch;
836 impl->fds[0] = impl->fds[1] = -1;
848 int fds[2] = { impl->fds[0], impl->fds[1] };
851 impl->fds[0] = impl->fds[1] = -1;
864 if (close(fds[1]) == -1 && !result) {
869 if (close(fds[0]) == -1 && !result) {
883 assert(signo < LELY_NSIG);
886 assert(node->signo == signo);
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;
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;
901 if (sigaction(signo, &act, &io_sigset_action[signo - 1])
903 io_sigset_shared.sig[signo - 1].fd = 0;
908 node->next = io_sigset_shared.sig[signo - 1].list;
909 io_sigset_shared.sig[signo - 1].list = node;
912 assert(!node->pending);
922 assert(signo < LELY_NSIG);
925 assert(node->signo == signo);
932 while (*
pnode != node)
934 assert(*
pnode == node);
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],
949 io_sigset_shared.sig[signo - 1].fd = 0;
954 io_sigset_shared.sig[signo - 1].fd = impl->fds[1] + 1;
955 io_sigset_kill(signo);
974 impl->read_posted = 0;
983 impl->wait_posted = 0;
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.
io_fork_event
The type of event generated by an I/O context before and after a process fork.
@ IO_FORK_CHILD
The event generated after the fork in the child process.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
This header file is part of the utilities library; it contains the diagnostic declarations.
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
@ IO_EVENT_IN
Data (other than priority data) MAY be read without blocking.
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...
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
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.
int io_fd_set_cloexec(int fd)
Sets the FD_CLOEXEC flag of the file descriptor fd.
int io_fd_set_nonblock(int fd)
Sets the O_NONBLOCK flag of the file descriptor fd.
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.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
const struct io_sigset_vtbl *const io_sigset_t
An abstract signal handler.
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.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
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.
#define IO_POLL_WATCH_INIT(func)
The static initializer for io_poll_watch.
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.
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a system signal handler.
io_sigset_t * io_sigset_create(io_poll_t *poll, ev_exec_t *exec)
Creates a new system signal handler.
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.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
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.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
An object representing a file descriptor being monitored for I/O events.
A wait operation suitable for use with a signal handler.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
int signo
The signal number, or 0 if the wait operation was canceled.
The virtual table of an I/O service.
A node in a pairing heap.
struct pnode * next
A pointer to the next sibling node.
A node in a singly-linked list.
struct slnode * next
A pointer to the next node in the list.
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.
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.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....