Lely core libraries  2.2.5
sigset.c
Go to the documentation of this file.
1 
24 #include "io.h"
25 
26 #if _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 
48 struct 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 
60 static struct {
61  CRITICAL_SECTION CriticalSection;
62  struct io_sigset_node *list[LELY_NSIG - 1];
63 } io_sigset_shared = { .list = { NULL } };
64 
65 static BOOL WINAPI io_sigset_handler_routine(DWORD dwCtrlType);
66 static BOOL io_sigset_handler(int signo);
67 
68 static io_ctx_t *io_sigset_impl_dev_get_ctx(const io_dev_t *dev);
69 static ev_exec_t *io_sigset_impl_dev_get_exec(const io_dev_t *dev);
70 static size_t io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task);
71 static size_t io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task);
72 
73 // clang-format off
74 static 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 
82 static io_dev_t *io_sigset_impl_get_dev(const io_sigset_t *sigset);
83 static int io_sigset_impl_clear(io_sigset_t *sigset);
84 static int io_sigset_impl_insert(io_sigset_t *sigset, int signo);
85 static int io_sigset_impl_remove(io_sigset_t *sigset, int signo);
86 static void io_sigset_impl_submit_wait(
87  io_sigset_t *sigset, struct io_sigset_wait *wait);
88 
89 // clang-format off
90 static 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 
99 static void io_sigset_impl_svc_shutdown(struct io_svc *svc);
100 
101 // clang-format off
102 static const struct io_svc_vtbl io_sigset_impl_svc_vtbl = {
103  NULL,
104  &io_sigset_impl_svc_shutdown
105 };
106 // clang-format on
107 
108 struct 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 
131 static void io_sigset_impl_signal_cp_func(
132  struct io_cp *cp, size_t nbytes, int errc);
133 static void io_sigset_impl_wait_task_func(struct ev_task *task);
134 
135 static inline struct io_sigset_impl *io_sigset_impl_from_dev(
136  const io_dev_t *dev);
137 static inline struct io_sigset_impl *io_sigset_impl_from_sigset(
138  const io_sigset_t *sigset);
139 static inline struct io_sigset_impl *io_sigset_impl_from_svc(
140  const struct io_svc *svc);
141 
142 static void io_sigset_impl_pop(struct io_sigset_impl *impl,
143  struct sllist *queue, struct ev_task *task);
144 
145 static void io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo);
146 static void io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo);
147 
148 int
149 io_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 
159 void
160 io_win32_sigset_fini(void)
161 {
162  SetConsoleCtrlHandler(&io_sigset_handler_routine, FALSE);
163  DeleteCriticalSection(&io_sigset_shared.CriticalSection);
164 }
165 
166 void *
167 io_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 
177 void
178 io_sigset_free(void *ptr)
179 {
180  if (ptr)
181  free(io_sigset_impl_from_sigset(ptr));
182 }
183 
184 io_sigset_t *
185 io_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 
228 void
229 io_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 
258 io_sigset_t *
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 
278 error_init:
279  io_sigset_free((void *)sigset);
280 error_alloc:
281  SetLastError(dwErrCode);
282  return NULL;
283 }
284 
285 void
287 {
288  if (sigset) {
289  io_sigset_fini(sigset);
290  io_sigset_free((void *)sigset);
291  }
292 }
293 
294 static BOOL WINAPI
295 io_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 
315 static BOOL
316 io_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  struct io_sigset_impl *impl = structof(
325  node, struct io_sigset_impl, nodes[signo - 1]);
326  assert(node->watched);
327  if (!node->pending) {
328  node->pending = 1;
329  if (!impl->signal_posted) {
330  impl->signal_posted = 1;
331  io_poll_post(impl->poll, 0, &impl->signal_cp);
332  }
333  }
334  }
335  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
336  return list != NULL;
337 }
338 
339 static io_ctx_t *
340 io_sigset_impl_dev_get_ctx(const io_dev_t *dev)
341 {
342  const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
343 
344  return impl->ctx;
345 }
346 
347 static ev_exec_t *
348 io_sigset_impl_dev_get_exec(const io_dev_t *dev)
349 {
350  const struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
351 
352  return impl->exec;
353 }
354 
355 static size_t
356 io_sigset_impl_dev_cancel(io_dev_t *dev, struct ev_task *task)
357 {
358  struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
359 
360  struct sllist queue;
361  sllist_init(&queue);
362 
363  io_sigset_impl_pop(impl, &queue, task);
364 
365  return io_sigset_wait_queue_post(&queue, 0);
366 }
367 
368 static size_t
369 io_sigset_impl_dev_abort(io_dev_t *dev, struct ev_task *task)
370 {
371  struct io_sigset_impl *impl = io_sigset_impl_from_dev(dev);
372 
373  struct sllist queue;
374  sllist_init(&queue);
375 
376  io_sigset_impl_pop(impl, &queue, task);
377 
378  return ev_task_queue_abort(&queue);
379 }
380 
381 static io_dev_t *
382 io_sigset_impl_get_dev(const io_sigset_t *sigset)
383 {
384  const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
385 
386  return &impl->dev_vptr;
387 }
388 
389 static int
390 io_sigset_impl_clear(io_sigset_t *sigset)
391 {
392  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
393 
394  EnterCriticalSection(&io_sigset_shared.CriticalSection);
395  for (int i = 1; i < LELY_NSIG; i++)
396  io_sigset_impl_do_remove(impl, i);
397  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
398 
399  return 0;
400 }
401 
402 static int
403 io_sigset_impl_insert(io_sigset_t *sigset, int signo)
404 {
405  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
406 
407  if (signo <= 0 || signo >= LELY_NSIG) {
408  SetLastError(ERROR_INVALID_PARAMETER);
409  return -1;
410  }
411 
412  EnterCriticalSection(&io_sigset_shared.CriticalSection);
413  io_sigset_impl_do_insert(impl, signo);
414  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
415 
416  return 0;
417 }
418 
419 static int
420 io_sigset_impl_remove(io_sigset_t *sigset, int signo)
421 {
422  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
423 
424  if (signo <= 0 || signo >= LELY_NSIG) {
425  SetLastError(ERROR_INVALID_PARAMETER);
426  return -1;
427  }
428 
429  EnterCriticalSection(&io_sigset_shared.CriticalSection);
430  io_sigset_impl_do_remove(impl, signo);
431  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
432 
433  return 0;
434 }
435 
436 static void
437 io_sigset_impl_submit_wait(io_sigset_t *sigset, struct io_sigset_wait *wait)
438 {
439  struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
440  assert(wait);
441  struct ev_task *task = &wait->task;
442 
443  if (!task->exec)
444  task->exec = impl->exec;
445  ev_exec_on_task_init(task->exec);
446 
447 #if !LELY_NO_THREADS
448  EnterCriticalSection(&impl->CriticalSection);
449 #endif
450  if (impl->shutdown) {
451 #if !LELY_NO_THREADS
452  LeaveCriticalSection(&impl->CriticalSection);
453 #endif
454  io_sigset_wait_post(wait, 0);
455  } else {
456  sllist_push_back(&impl->queue, &task->_node);
457  int post_wait = !impl->wait_posted && impl->pending;
458  if (post_wait)
459  impl->wait_posted = 1;
460 #if !LELY_NO_THREADS
461  LeaveCriticalSection(&impl->CriticalSection);
462 #endif
463  if (post_wait)
464  ev_exec_post(impl->wait_task.exec, &impl->wait_task);
465  }
466 }
467 
468 static void
469 io_sigset_impl_svc_shutdown(struct io_svc *svc)
470 {
471  struct io_sigset_impl *impl = io_sigset_impl_from_svc(svc);
472  io_dev_t *dev = &impl->dev_vptr;
473 
474 #if !LELY_NO_THREADS
475  EnterCriticalSection(&impl->CriticalSection);
476 #endif
477  int shutdown = !impl->shutdown;
478  impl->shutdown = 1;
479  // Try to abort io_sigset_impl_wait_task_func().
480  // clang-format off
481  if (shutdown && impl->wait_posted
482  && ev_exec_abort(impl->wait_task.exec,
483  &impl->wait_task))
484  // clang-format on
485  impl->wait_posted = 0;
486 #if !LELY_NO_THREADS
487  LeaveCriticalSection(&impl->CriticalSection);
488 #endif
489 
490  if (shutdown)
491  // Cancel all pending operations.
492  io_sigset_impl_dev_cancel(dev, NULL);
493 }
494 
495 static void
496 io_sigset_impl_signal_cp_func(struct io_cp *cp, size_t nbytes, int errc)
497 {
498  assert(cp);
499  struct io_sigset_impl *impl =
500  structof(cp, struct io_sigset_impl, signal_cp);
501  (void)nbytes;
502  (void)errc;
503 
504 #if !LELY_NO_THREADS
505  EnterCriticalSection(&impl->CriticalSection);
506 #endif
507  impl->pending = 1;
508  int post_wait = !impl->wait_posted && !sllist_empty(&impl->queue)
509  && !impl->shutdown;
510  if (post_wait)
511  impl->wait_posted = 1;
512 #if !LELY_NO_THREADS
513  LeaveCriticalSection(&impl->CriticalSection);
514 #endif
515 
516  EnterCriticalSection(&io_sigset_shared.CriticalSection);
517  impl->signal_posted = 0;
518  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
519 
520  if (post_wait)
521  ev_exec_post(impl->wait_task.exec, &impl->wait_task);
522 }
523 
524 static void
525 io_sigset_impl_wait_task_func(struct ev_task *task)
526 {
527  assert(task);
528  struct io_sigset_impl *impl =
529  structof(task, struct io_sigset_impl, wait_task);
530 
531  struct io_sigset_wait *wait = NULL;
532  int signo = LELY_NSIG;
533 
534 #if !LELY_NO_THREADS
535  EnterCriticalSection(&impl->CriticalSection);
536 #endif
537  if (!sllist_empty(&impl->queue)) {
538  EnterCriticalSection(&io_sigset_shared.CriticalSection);
539  for (signo = 1; signo < LELY_NSIG; signo++) {
540  struct io_sigset_node *node = &impl->nodes[signo - 1];
541  if (node->pending) {
542  node->pending = 0;
543  task = ev_task_from_node(
544  sllist_pop_front(&impl->queue));
545  wait = io_sigset_wait_from_task(task);
546  break;
547  }
548  }
549  LeaveCriticalSection(&io_sigset_shared.CriticalSection);
550  }
551 
552  impl->pending = signo != LELY_NSIG;
553  int post_wait = impl->wait_posted = impl->pending
554  && !sllist_empty(&impl->queue) && !impl->shutdown;
555 #if !LELY_NO_THREADS
556  LeaveCriticalSection(&impl->CriticalSection);
557 #endif
558 
559  if (wait)
560  io_sigset_wait_post(wait, signo);
561 
562  if (post_wait)
563  ev_exec_post(impl->wait_task.exec, &impl->wait_task);
564 }
565 
566 static inline struct io_sigset_impl *
567 io_sigset_impl_from_dev(const io_dev_t *dev)
568 {
569  assert(dev);
570 
571  return structof(dev, struct io_sigset_impl, dev_vptr);
572 }
573 
574 static inline struct io_sigset_impl *
575 io_sigset_impl_from_sigset(const io_sigset_t *sigset)
576 {
577  assert(sigset);
578 
579  return structof(sigset, struct io_sigset_impl, sigset_vptr);
580 }
581 
582 static inline struct io_sigset_impl *
583 io_sigset_impl_from_svc(const struct io_svc *svc)
584 {
585  assert(svc);
586 
587  return structof(svc, struct io_sigset_impl, svc);
588 }
589 
590 static void
591 io_sigset_impl_pop(struct io_sigset_impl *impl, struct sllist *queue,
592  struct ev_task *task)
593 {
594  assert(impl);
595  assert(queue);
596 
597 #if !LELY_NO_THREADS
598  EnterCriticalSection(&impl->CriticalSection);
599 #endif
600  if (!task)
601  sllist_append(queue, &impl->queue);
602  else if (sllist_remove(&impl->queue, &task->_node))
603  sllist_push_back(queue, &task->_node);
604 #if !LELY_NO_THREADS
605  LeaveCriticalSection(&impl->CriticalSection);
606 #endif
607 }
608 
609 static void
610 io_sigset_impl_do_insert(struct io_sigset_impl *impl, int signo)
611 {
612  assert(impl);
613  assert(signo > 0);
614  assert(signo < LELY_NSIG);
615 
616  struct io_sigset_node *node = &impl->nodes[signo - 1];
617  assert(node->signo == signo);
618 
619  if (node->watched)
620  return;
621  node->watched = 1;
622  assert(!node->pending);
623 
624  node->next = io_sigset_shared.list[signo - 1];
625  io_sigset_shared.list[signo - 1] = node;
626 }
627 
628 static void
629 io_sigset_impl_do_remove(struct io_sigset_impl *impl, int signo)
630 {
631  assert(impl);
632  assert(signo > 0);
633  assert(signo < LELY_NSIG);
634 
635  struct io_sigset_node *node = &impl->nodes[signo - 1];
636  assert(node->signo == signo);
637 
638  if (!node->watched)
639  return;
640  node->watched = 0;
641  node->pending = 0;
642 
643  struct io_sigset_node **pnode = &io_sigset_shared.list[signo - 1];
644  assert(*pnode);
645  while (*pnode != node)
646  pnode = &(*pnode)->next;
647  assert(*pnode == node);
648  *pnode = node->next;
649  node->next = NULL;
650 }
651 
652 #endif // _WIN32
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
Definition: exec.h:126
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
Definition: sigset.h:48
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
This header file is part of the I/O library; it contains the I/O context and service declarations...
An I/O polling interface.
Definition: poll.c:48
const struct io_sigset_vtbl *const io_sigset_t
An abstract signal handler.
Definition: sigset.h:40
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
Definition: ctx.c:35
This header file is part of the I/O library; it contains the I/O polling declarations for Windows...
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 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
#define IO_CP_INIT(func)
The static initializer for io_cp.
Definition: poll.h:67
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
Definition: sllist.h:221
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
A wait operation suitable for use with a signal handler.
Definition: sigset.h:43
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
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
This header file is part of the utilities library; it contains the native and platform-independent er...
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
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.
An I/O service.
Definition: ctx.h:49
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
A singly-linked list.
Definition: sllist.h:51
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a system signal handler.
Definition: sigset.c:326
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
This is the internal header file of the Windows-specific I/O declarations.
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 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
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
An executable task.
Definition: task.h:41
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
Definition: sllist.h:190
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
The virtual table of an I/O service.
Definition: ctx.h:67
This header file is part of the I/O library; it contains the system signal handler declarations...
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
Definition: ctx.h:57
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
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
Definition: sllist.h:184
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
Definition: dev.h:35
This is the public header file of the utilities library.
io_sigset_t * io_sigset_create(io_poll_t *poll, ev_exec_t *exec)
Creates a new system signal handler.
Definition: sigset.c:299
A node in a pairing heap.
Definition: pheap.h:51