26#if !LELY_NO_STDIO && _POSIX_C_SOURCE >= 200112L
50#define LELY_NSIG _NSIG
63#define IO_SIGSET_NODE_INIT(signo) \
80 PTHREAD_MUTEX_INITIALIZER,
85static struct sigaction io_sigset_action[LELY_NSIG - 1];
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);
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);
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
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(
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
123static int io_sigset_impl_svc_notify_fork(
125static void io_sigset_impl_svc_shutdown(
struct io_svc *svc);
128static 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;
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);
165 const struct io_svc *svc);
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);
176static size_t io_sigset_impl_do_abort_tasks(
struct io_sigset_impl *impl);
185 impl->sigset_vptr = NULL;
187 return &impl->sigset_vptr;
191io_sigset_free(
void *ptr)
194 free(io_sigset_impl_from_sigset(ptr));
208 impl->dev_vptr = &io_sigset_impl_dev_vtbl;
209 impl->sigset_vptr = &io_sigset_impl_vtbl;
219 &io_sigset_impl_watch_func);
220 impl->fds[0] = impl->fds[1] = -1;
223 impl->
exec, &io_sigset_impl_read_task_func);
225 impl->
exec, &io_sigset_impl_wait_task_func);
228 if ((errsv = pthread_mutex_init(&impl->mtx, NULL)))
233 impl->read_posted = 0;
234 impl->wait_posted = 0;
239 for (
int i = 1; i < LELY_NSIG; i++)
243 if (io_sigset_impl_open(impl) == -1) {
255 pthread_mutex_destroy(&impl->mtx);
269 io_sigset_impl_svc_shutdown(&impl->svc);
272 io_sigset_impl_clear(sigset);
276 pthread_mutex_lock(&impl->mtx);
279 while (impl->read_posted || impl->wait_posted) {
280 if (io_sigset_impl_do_abort_tasks(impl))
282 pthread_mutex_unlock(&impl->mtx);
286 "io_sigset_fini() invoked with pending operations");
289 pthread_mutex_lock(&impl->mtx);
291 pthread_mutex_unlock(&impl->mtx);
295 io_sigset_impl_close(impl);
298 pthread_mutex_destroy(&impl->mtx);
313 io_sigset_t *tmp = io_sigset_init(sigset, poll, exec);
323 io_sigset_free((
void *)sigset);
333 io_sigset_fini(sigset);
334 io_sigset_free((
void *)sigset);
339io_sigset_handler(
int signo)
341 io_sigset_shared.sig[signo - 1].pending = 1;
342 io_sigset_shared.pending = 1;
344 io_sigset_kill(signo);
348io_sigset_kill(
int signo)
354 result = write(io_sigset_shared.sig[signo - 1].fd - 1,
"", 1);
355 }
while (result == -1 && errno == EINTR);
360io_sigset_process_all(
void)
366 pthread_mutex_lock(&io_sigset_shared.mtx);
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);
378 pthread_mutex_unlock(&io_sigset_shared.mtx);
389io_sigset_process_sig(
int signo,
struct sllist *queue)
391 for (
struct io_sigset_node *node = io_sigset_shared.sig[signo - 1].list;
392 node; node = node->
next) {
396 pthread_mutex_lock(&impl->mtx);
398 assert(node->watched);
399 if (!node->pending) {
402 if (!impl->wait_posted) {
403 impl->wait_posted = 1;
408 pthread_mutex_unlock(&impl->mtx);
414io_sigset_impl_dev_get_ctx(
const io_dev_t *dev)
422io_sigset_impl_dev_get_exec(
const io_dev_t *dev)
437 io_sigset_impl_pop(impl, &queue, task);
439 return io_sigset_wait_queue_post(&queue, 0);
450 io_sigset_impl_pop(impl, &queue, task);
458 const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
460 return &impl->dev_vptr;
470 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
478 for (
int i = 1; i < LELY_NSIG; i++) {
479 if (io_sigset_impl_do_remove(impl, i) == -1)
484 pthread_mutex_unlock(&io_sigset_shared.mtx);
491io_sigset_impl_insert(
io_sigset_t *sigset,
int signo)
495 if (signo <= 0 || signo >= LELY_NSIG) {
502 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
509 int result = io_sigset_impl_do_insert(impl, signo);
512 pthread_mutex_unlock(&io_sigset_shared.mtx);
519io_sigset_impl_remove(
io_sigset_t *sigset,
int signo)
523 if (signo <= 0 || signo >= LELY_NSIG) {
530 int errsv = pthread_mutex_lock(&io_sigset_shared.mtx);
537 int result = io_sigset_impl_do_remove(impl, signo);
540 pthread_mutex_unlock(&io_sigset_shared.mtx);
554 task->
exec = impl->exec;
558 pthread_mutex_lock(&impl->mtx);
560 if (impl->shutdown) {
562 pthread_mutex_unlock(&impl->mtx);
564 io_sigset_wait_post(wait, 0);
567 int post_wait = !impl->wait_posted && impl->pending;
569 impl->wait_posted = 1;
571 pthread_mutex_unlock(&impl->mtx);
589 if (io_sigset_impl_close(impl) == -1 && !result) {
594 if (io_sigset_impl_open(impl) == -1 && !result) {
604io_sigset_impl_svc_shutdown(
struct io_svc *svc)
610 pthread_mutex_lock(&impl->mtx);
612 int shutdown = !impl->shutdown;
619 io_sigset_impl_do_abort_tasks(impl);
622 pthread_mutex_unlock(&impl->mtx);
627 io_sigset_impl_dev_cancel(dev, NULL);
631io_sigset_impl_watch_func(
struct io_poll_watch *watch,
int events)
639 pthread_mutex_lock(&impl->mtx);
641 int post_read = !impl->read_posted;
642 impl->read_posted = 1;
644 pthread_mutex_unlock(&impl->mtx);
652io_sigset_impl_read_task_func(
struct ev_task *task)
666 result = read(impl->fds[0], buf,
sizeof(buf));
669 }
while (result > 0 || (result == -1 && errno == EINTR));
670 if (result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
674 io_sigset_process_all();
677 pthread_mutex_lock(&impl->mtx);
679 if (events && !impl->shutdown)
680 io_poll_watch(impl->poll, impl->fds[0], events, &impl->watch);
681 impl->read_posted = 0;
683 pthread_mutex_unlock(&impl->mtx);
690io_sigset_impl_wait_task_func(
struct ev_task *task)
697 int signo = LELY_NSIG;
700 pthread_mutex_lock(&impl->mtx);
715 impl->pending = signo != LELY_NSIG;
716 int post_wait = impl->wait_posted = impl->pending
719 pthread_mutex_unlock(&impl->mtx);
723 io_sigset_wait_post(wait, signo);
730io_sigset_impl_from_dev(
const io_dev_t *dev)
738io_sigset_impl_from_sigset(
const io_sigset_t *sigset)
746io_sigset_impl_from_svc(
const struct io_svc *svc)
761 pthread_mutex_lock(&impl->mtx);
768 pthread_mutex_unlock(&impl->mtx);
779 if (io_sigset_impl_close(impl) == -1) {
785 if (pipe2(impl->fds, O_CLOEXEC | O_NONBLOCK) == -1) {
787 if (pipe(impl->fds) == -1) {
795 if (impl->fds[1] - 1 > SIG_ATOMIC_MAX) {
797 goto error_sig_atomic;
827 goto error_poll_watch;
840 impl->fds[0] = impl->fds[1] = -1;
852 int fds[2] = { impl->fds[0], impl->fds[1] };
855 impl->fds[0] = impl->fds[1] = -1;
868 if (close(fds[1]) == -1 && !result) {
873 if (close(fds[0]) == -1 && !result) {
887 assert(signo < LELY_NSIG);
890 assert(node->signo == signo);
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;
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;
905 if (sigaction(signo, &act, &io_sigset_action[signo - 1])
907 io_sigset_shared.sig[signo - 1].fd = 0;
912 node->next = io_sigset_shared.sig[signo - 1].list;
913 io_sigset_shared.sig[signo - 1].list = node;
916 assert(!node->pending);
926 assert(signo < LELY_NSIG);
929 assert(node->signo == signo);
936 while (*
pnode != node)
938 assert(*
pnode == node);
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],
953 io_sigset_shared.sig[signo - 1].fd = 0;
958 io_sigset_shared.sig[signo - 1].fd = impl->fds[1] + 1;
959 io_sigset_kill(signo);
978 impl->read_posted = 0;
987 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.
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.
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...
#define IO_POLL_WATCH_INIT(func)
The static initializer for io_poll_watch.
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.
io_sigset_t * io_sigset_create(io_poll_t *poll, ev_exec_t *exec)
Creates a new system signal handler.
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a system signal handler.
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.
ptrdiff_t ssize_t
Used for a count of bytes or an error indication.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....