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 && _WIN32
27
28#include "../sigset.h"
29#include <lely/io2/ctx.h>
30#include <lely/io2/sys/sigset.h>
31#include <lely/io2/win32/poll.h>
32#include <lely/util/errnum.h>
33#include <lely/util/util.h>
34
35#include <assert.h>
36#include <stdlib.h>
37
38#include <processthreadsapi.h>
39
40#ifndef LELY_NSIG
41#ifdef NSIG
42#define LELY_NSIG NSIG
43#else
44#define LELY_NSIG (SIGABRT + 1)
45#endif
46#endif
47
48struct io_sigset_node {
49 struct io_sigset_node *next;
50 unsigned signo : 30;
51 unsigned watched : 1;
52 unsigned pending : 1;
53};
54
55#define IO_SIGSET_NODE_INIT(signo) \
56 { \
57 NULL, (signo), 0, 0 \
58 }
59
60static struct {
61 CRITICAL_SECTION CriticalSection;
62 struct io_sigset_node *list[LELY_NSIG - 1];
63} io_sigset_shared = { .list = { NULL } };
64
65static BOOL WINAPI io_sigset_handler_routine(DWORD dwCtrlType);
66static BOOL io_sigset_handler(int signo);
67
68static io_ctx_t *io_sigset_impl_dev_get_ctx(const io_dev_t *dev);
69static ev_exec_t *io_sigset_impl_dev_get_exec(const io_dev_t *dev);
70static size_t io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task);
71static size_t io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task);
72
73// clang-format off
74static const struct io_dev_vtbl io_sigset_impl_dev_vtbl = {
75 &io_sigset_impl_dev_get_ctx,
76 &io_sigset_impl_dev_get_exec,
77 &io_sigset_impl_dev_cancel,
78 &io_sigset_impl_dev_abort
79};
80// clang-format on
81
82static io_dev_t *io_sigset_impl_get_dev(const io_sigset_t *sigset);
83static int io_sigset_impl_clear(io_sigset_t *sigset);
84static int io_sigset_impl_insert(io_sigset_t *sigset, int signo);
85static int io_sigset_impl_remove(io_sigset_t *sigset, int signo);
86static void io_sigset_impl_submit_wait(
87 io_sigset_t *sigset, struct io_sigset_wait *wait);
88
89// clang-format off
90static const struct io_sigset_vtbl io_sigset_impl_vtbl = {
91 &io_sigset_impl_get_dev,
92 &io_sigset_impl_clear,
93 &io_sigset_impl_insert,
94 &io_sigset_impl_remove,
95 &io_sigset_impl_submit_wait
96};
97// clang-format on
98
99static void io_sigset_impl_svc_shutdown(struct io_svc *svc);
100
101// clang-format off
102static const struct io_svc_vtbl io_sigset_impl_svc_vtbl = {
103 NULL,
104 &io_sigset_impl_svc_shutdown
105};
106// clang-format on
107
108struct io_sigset_impl {
109 const struct io_dev_vtbl *dev_vptr;
110 const struct io_sigset_vtbl *sigset_vptr;
111 io_poll_t *poll;
112 struct io_svc svc;
113 io_ctx_t *ctx;
114 ev_exec_t *exec;
115 struct io_cp signal_cp;
116 struct ev_task wait_task;
117#if !LELY_NO_THREADS
118 // The critical section protecting shutdown, wait_posted, pending and
119 // queue. signal_posted and nodes are protected by the critical section
120 // in io_sigset_shared.
121 CRITICAL_SECTION CriticalSection;
122#endif
123 unsigned shutdown : 1;
124 unsigned signal_posted : 1;
125 unsigned wait_posted : 1;
126 unsigned pending : 1;
127 struct sllist queue;
128 struct io_sigset_node nodes[LELY_NSIG - 1];
129};
130
131static void io_sigset_impl_signal_cp_func(
132 struct io_cp *cp, size_t nbytes, int errc);
133static void io_sigset_impl_wait_task_func(struct ev_task *task);
134
135static inline struct io_sigset_impl *io_sigset_impl_from_dev(
136 const io_dev_t *dev);
137static inline struct io_sigset_impl *io_sigset_impl_from_sigset(
138 const io_sigset_t *sigset);
139static inline struct io_sigset_impl *io_sigset_impl_from_svc(
140 const struct io_svc *svc);
141
142static void io_sigset_impl_pop(struct io_sigset_impl *impl,
143 struct sllist *queue, struct ev_task *task);
144
145static void io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo);
146static void io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo);
147
148int
149io_win32_sigset_init(void)
150{
151 InitializeCriticalSection(&io_sigset_shared.CriticalSection);
152 if (!SetConsoleCtrlHandler(&io_sigset_handler_routine, TRUE)) {
153 DeleteCriticalSection(&io_sigset_shared.CriticalSection);
154 return -1;
155 }
156 return 0;
157}
158
159void
160io_win32_sigset_fini(void)
161{
162 SetConsoleCtrlHandler(&io_sigset_handler_routine, FALSE);
163 DeleteCriticalSection(&io_sigset_shared.CriticalSection);
164}
165
166void *
167io_sigset_alloc(void)
168{
169 struct io_sigset_impl *impl = malloc(sizeof(*impl));
170 if (!impl) {
171 set_errc(errno2c(errno));
172 return NULL;
173 }
174 return &impl->sigset_vptr;
175}
176
177void
178io_sigset_free(void *ptr)
179{
180 if (ptr)
181 free(io_sigset_impl_from_sigset(ptr));
182}
183
185io_sigset_init(io_sigset_t *sigset, io_poll_t *poll, ev_exec_t *exec)
186{
187 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
188 assert(poll);
189 assert(exec);
190 io_ctx_t *ctx = io_poll_get_ctx(poll);
191 assert(ctx);
192
193 impl->dev_vptr = &io_sigset_impl_dev_vtbl;
194 impl->sigset_vptr = &io_sigset_impl_vtbl;
195
196 impl->svc = (struct io_svc)IO_SVC_INIT(&io_sigset_impl_svc_vtbl);
197 impl->ctx = ctx;
198
199 impl->poll = poll;
200
201 impl->exec = exec;
202
203 impl->signal_cp = (struct io_cp)IO_CP_INIT(
204 &io_sigset_impl_signal_cp_func);
205 impl->wait_task = (struct ev_task)EV_TASK_INIT(
206 impl->exec, &io_sigset_impl_wait_task_func);
207
208#if !LELY_NO_THREADS
209 InitializeCriticalSection(&impl->CriticalSection);
210#endif
211
212 impl->shutdown = 0;
213 impl->signal_posted = 0;
214 impl->wait_posted = 0;
215 impl->pending = 0;
216
217 sllist_init(&impl->queue);
218
219 for (int i = 1; i < LELY_NSIG; i++)
220 impl->nodes[i - 1] =
221 (struct io_sigset_node)IO_SIGSET_NODE_INIT(i);
222
223 io_ctx_insert(impl->ctx, &impl->svc);
224
225 return sigset;
226}
227
228void
229io_sigset_fini(io_sigset_t *sigset)
230{
231 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
232
233 io_ctx_remove(impl->ctx, &impl->svc);
234 // Cancel all pending tasks.
235 io_sigset_impl_svc_shutdown(&impl->svc);
236
237 // TODO: Find a reliable way to wait for io_sigset_impl_signal_cp_func()
238 // to complete.
239
240#if !LELY_NO_THREADS
241 EnterCriticalSection(&impl->CriticalSection);
242 // If necessary, busy-wait until io_sigset_impl_wait_task_func()
243 // completes.
244 while (impl->wait_posted) {
245 // Try to abort io_sigset_impl_wait_task_func().
246 if (ev_exec_abort(impl->wait_task.exec, &impl->wait_task))
247 break;
248 LeaveCriticalSection(&impl->CriticalSection);
249 SwitchToThread();
250 EnterCriticalSection(&impl->CriticalSection);
251 }
252 LeaveCriticalSection(&impl->CriticalSection);
253
254 DeleteCriticalSection(&impl->CriticalSection);
255#endif
256}
257
260{
261 DWORD dwErrCode = 0;
262
263 io_sigset_t *sigset = io_sigset_alloc();
264 if (!sigset) {
265 dwErrCode = GetLastError();
266 goto error_alloc;
267 }
268
269 io_sigset_t *tmp = io_sigset_init(sigset, poll, exec);
270 if (!tmp) {
271 dwErrCode = GetLastError();
272 goto error_init;
273 }
274 sigset = tmp;
275
276 return sigset;
277
278error_init:
279 io_sigset_free((void *)sigset);
280error_alloc:
281 SetLastError(dwErrCode);
282 return NULL;
283}
284
285void
287{
288 if (sigset) {
289 io_sigset_fini(sigset);
290 io_sigset_free((void *)sigset);
291 }
292}
293
294static BOOL WINAPI
295io_sigset_handler_routine(DWORD dwCtrlType)
296{
297 switch (dwCtrlType) {
298 case CTRL_C_EVENT: return io_sigset_handler(SIGINT);
299 case CTRL_BREAK_EVENT: return io_sigset_handler(SIGBREAK);
300 case CTRL_CLOSE_EVENT:
301 if (io_sigset_handler(SIGHUP)) {
302 // Windows will terminate the process after the handler
303 // returns, so we wait to allow an event loop to process
304 // the signal.
305 Sleep(INFINITE);
306 return TRUE;
307 }
308 return FALSE;
309 case CTRL_LOGOFF_EVENT:
310 case CTRL_SHUTDOWN_EVENT:
311 default: return FALSE;
312 }
313}
314
315static BOOL
316io_sigset_handler(int signo)
317{
318 assert(signo > 0);
319 assert(signo < LELY_NSIG);
320
321 EnterCriticalSection(&io_sigset_shared.CriticalSection);
322 struct io_sigset_node *list = io_sigset_shared.list[signo - 1];
323 for (struct io_sigset_node *node = list; node; node = node->next) {
324 // cppcheck-suppress nullPointer
325 struct io_sigset_impl *impl = structof(
326 node, struct io_sigset_impl, nodes[signo - 1]);
327 assert(node->watched);
328 if (!node->pending) {
329 node->pending = 1;
330 if (!impl->signal_posted) {
331 impl->signal_posted = 1;
332 io_poll_post(impl->poll, 0, &impl->signal_cp);
333 }
334 }
335 }
336 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
337 return list != NULL;
338}
339
340static io_ctx_t *
341io_sigset_impl_dev_get_ctx(const io_dev_t *dev)
342{
343 const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
344
345 return impl->ctx;
346}
347
348static ev_exec_t *
349io_sigset_impl_dev_get_exec(const io_dev_t *dev)
350{
351 const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
352
353 return impl->exec;
354}
355
356static size_t
357io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task)
358{
359 struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
360
361 struct sllist queue;
362 sllist_init(&queue);
363
364 io_sigset_impl_pop(impl, &queue, task);
365
366 return io_sigset_wait_queue_post(&queue, 0);
367}
368
369static size_t
370io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task)
371{
372 struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
373
374 struct sllist queue;
375 sllist_init(&queue);
376
377 io_sigset_impl_pop(impl, &queue, task);
378
379 return ev_task_queue_abort(&queue);
380}
381
382static io_dev_t *
383io_sigset_impl_get_dev(const io_sigset_t *sigset)
384{
385 const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
386
387 return &impl->dev_vptr;
388}
389
390static int
391io_sigset_impl_clear(io_sigset_t *sigset)
392{
393 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
394
395 EnterCriticalSection(&io_sigset_shared.CriticalSection);
396 for (int i = 1; i < LELY_NSIG; i++)
397 io_sigset_impl_do_remove(impl, i);
398 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
399
400 return 0;
401}
402
403static int
404io_sigset_impl_insert(io_sigset_t *sigset, int signo)
405{
406 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
407
408 if (signo <= 0 || signo >= LELY_NSIG) {
409 SetLastError(ERROR_INVALID_PARAMETER);
410 return -1;
411 }
412
413 EnterCriticalSection(&io_sigset_shared.CriticalSection);
414 io_sigset_impl_do_insert(impl, signo);
415 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
416
417 return 0;
418}
419
420static int
421io_sigset_impl_remove(io_sigset_t *sigset, int signo)
422{
423 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
424
425 if (signo <= 0 || signo >= LELY_NSIG) {
426 SetLastError(ERROR_INVALID_PARAMETER);
427 return -1;
428 }
429
430 EnterCriticalSection(&io_sigset_shared.CriticalSection);
431 io_sigset_impl_do_remove(impl, signo);
432 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
433
434 return 0;
435}
436
437static void
438io_sigset_impl_submit_wait(io_sigset_t *sigset, struct io_sigset_wait *wait)
439{
440 struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
441 assert(wait);
442 struct ev_task *task = &wait->task;
443
444 if (!task->exec)
445 task->exec = impl->exec;
447
448#if !LELY_NO_THREADS
449 EnterCriticalSection(&impl->CriticalSection);
450#endif
451 if (impl->shutdown) {
452#if !LELY_NO_THREADS
453 LeaveCriticalSection(&impl->CriticalSection);
454#endif
455 io_sigset_wait_post(wait, 0);
456 } else {
457 sllist_push_back(&impl->queue, &task->_node);
458 int post_wait = !impl->wait_posted && impl->pending;
459 if (post_wait)
460 impl->wait_posted = 1;
461#if !LELY_NO_THREADS
462 LeaveCriticalSection(&impl->CriticalSection);
463#endif
464 // cppcheck-suppress duplicateCondition
465 if (post_wait)
466 ev_exec_post(impl->wait_task.exec, &impl->wait_task);
467 }
468}
469
470static void
471io_sigset_impl_svc_shutdown(struct io_svc *svc)
472{
473 struct io_sigset_impl *impl = io_sigset_impl_from_svc(svc);
474 io_dev_t *dev = &impl->dev_vptr;
475
476#if !LELY_NO_THREADS
477 EnterCriticalSection(&impl->CriticalSection);
478#endif
479 int shutdown = !impl->shutdown;
480 impl->shutdown = 1;
481 // Try to abort io_sigset_impl_wait_task_func().
482 // clang-format off
483 if (shutdown && impl->wait_posted
484 && ev_exec_abort(impl->wait_task.exec,
485 &impl->wait_task))
486 // clang-format on
487 impl->wait_posted = 0;
488#if !LELY_NO_THREADS
489 LeaveCriticalSection(&impl->CriticalSection);
490#endif
491
492 if (shutdown)
493 // Cancel all pending operations.
494 io_sigset_impl_dev_cancel(dev, NULL);
495}
496
497static void
498io_sigset_impl_signal_cp_func(struct io_cp *cp, size_t nbytes, int errc)
499{
500 assert(cp);
501 struct io_sigset_impl *impl =
502 structof(cp, struct io_sigset_impl, signal_cp);
503 (void)nbytes;
504 (void)errc;
505
506#if !LELY_NO_THREADS
507 EnterCriticalSection(&impl->CriticalSection);
508#endif
509 impl->pending = 1;
510 int post_wait = !impl->wait_posted && !sllist_empty(&impl->queue)
511 && !impl->shutdown;
512 if (post_wait)
513 impl->wait_posted = 1;
514#if !LELY_NO_THREADS
515 LeaveCriticalSection(&impl->CriticalSection);
516#endif
517
518 EnterCriticalSection(&io_sigset_shared.CriticalSection);
519 impl->signal_posted = 0;
520 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
521
522 if (post_wait)
523 ev_exec_post(impl->wait_task.exec, &impl->wait_task);
524}
525
526static void
527io_sigset_impl_wait_task_func(struct ev_task *task)
528{
529 assert(task);
530 struct io_sigset_impl *impl =
531 structof(task, struct io_sigset_impl, wait_task);
532
533 struct io_sigset_wait *wait = NULL;
534 int signo = LELY_NSIG;
535
536#if !LELY_NO_THREADS
537 EnterCriticalSection(&impl->CriticalSection);
538#endif
539 if (!sllist_empty(&impl->queue)) {
540 EnterCriticalSection(&io_sigset_shared.CriticalSection);
541 for (signo = 1; signo < LELY_NSIG; signo++) {
542 struct io_sigset_node *node = &impl->nodes[signo - 1];
543 if (node->pending) {
544 node->pending = 0;
545 task = ev_task_from_node(
546 sllist_pop_front(&impl->queue));
547 wait = io_sigset_wait_from_task(task);
548 break;
549 }
550 }
551 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
552 }
553
554 impl->pending = signo != LELY_NSIG;
555 int post_wait = impl->wait_posted = impl->pending
556 && !sllist_empty(&impl->queue) && !impl->shutdown;
557#if !LELY_NO_THREADS
558 LeaveCriticalSection(&impl->CriticalSection);
559#endif
560
561 if (wait)
562 io_sigset_wait_post(wait, signo);
563
564 if (post_wait)
565 ev_exec_post(impl->wait_task.exec, &impl->wait_task);
566}
567
568static inline struct io_sigset_impl *
569io_sigset_impl_from_dev(const io_dev_t *dev)
570{
571 assert(dev);
572
573 return structof(dev, struct io_sigset_impl, dev_vptr);
574}
575
576static inline struct io_sigset_impl *
577io_sigset_impl_from_sigset(const io_sigset_t *sigset)
578{
579 assert(sigset);
580
581 return structof(sigset, struct io_sigset_impl, sigset_vptr);
582}
583
584static inline struct io_sigset_impl *
585io_sigset_impl_from_svc(const struct io_svc *svc)
586{
587 assert(svc);
588
589 return structof(svc, struct io_sigset_impl, svc);
590}
591
592static void
593io_sigset_impl_pop(struct io_sigset_impl *impl, struct sllist *queue,
594 struct ev_task *task)
595{
596 assert(impl);
597 assert(queue);
598
599#if !LELY_NO_THREADS
600 EnterCriticalSection(&impl->CriticalSection);
601#endif
602 if (!task)
603 sllist_append(queue, &impl->queue);
604 else if (sllist_remove(&impl->queue, &task->_node))
605 sllist_push_back(queue, &task->_node);
606#if !LELY_NO_THREADS
607 LeaveCriticalSection(&impl->CriticalSection);
608#endif
609}
610
611static void
612io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo)
613{
614 assert(impl);
615 assert(signo > 0);
616 assert(signo < LELY_NSIG);
617
618 struct io_sigset_node *node = &impl->nodes[signo - 1];
619 assert(node->signo == signo);
620
621 if (node->watched)
622 return;
623 node->watched = 1;
624 assert(!node->pending);
625
626 node->next = io_sigset_shared.list[signo - 1];
627 io_sigset_shared.list[signo - 1] = node;
628}
629
630static void
631io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo)
632{
633 assert(impl);
634 assert(signo > 0);
635 assert(signo < LELY_NSIG);
636
637 struct io_sigset_node *node = &impl->nodes[signo - 1];
638 assert(node->signo == signo);
639
640 if (!node->watched)
641 return;
642 node->watched = 0;
643 node->pending = 0;
644
645 struct io_sigset_node **pnode = &io_sigset_shared.list[signo - 1];
646 assert(*pnode);
647 while (*pnode != node)
648 pnode = &(*pnode)->next;
649 assert(*pnode == node);
650 *pnode = node->next;
651 node->next = NULL;
652}
653
654#endif // !LELY_NO_STDIO && _WIN32
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
#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 native and platform-independent er...
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
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
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
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
This header file is part of the I/O library; it contains the I/O polling declarations for Windows.
#define IO_CP_INIT(func)
The static initializer for io_cp.
Definition: poll.h:67
int io_poll_post(io_poll_t *poll, size_t nbytes, struct io_cp *cp)
Posts a completion packet to the I/O completion port of an I/O polling instance.
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
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
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....
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
An I/O completion packet.
Definition: poll.h:54
Definition: ctx.c:38
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
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