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 
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  // 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 
340 static io_ctx_t *
341 io_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 
348 static ev_exec_t *
349 io_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 
356 static size_t
357 io_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 
369 static size_t
370 io_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 
382 static io_dev_t *
383 io_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 
390 static int
391 io_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 
403 static int
404 io_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 
420 static int
421 io_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 
437 static void
438 io_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;
446  ev_exec_on_task_init(task->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 
470 static void
471 io_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 
497 static void
498 io_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 
526 static void
527 io_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 
568 static inline struct io_sigset_impl *
569 io_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 
576 static inline struct io_sigset_impl *
577 io_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 
584 static inline struct io_sigset_impl *
585 io_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 
592 static void
593 io_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 
611 static void
612 io_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 
630 static void
631 io_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.
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a system signal handler.
Definition: sigset.c:330
io_sigset_t * io_sigset_create(io_poll_t *poll, ev_exec_t *exec)
Creates a new system signal handler.
Definition: sigset.c:303
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