26#if !LELY_NO_STDIO && _WIN32
38#include <processthreadsapi.h>
44#define LELY_NSIG (SIGABRT + 1)
55#define IO_SIGSET_NODE_INIT(signo) \
61 CRITICAL_SECTION CriticalSection;
63} io_sigset_shared = { .list = { NULL } };
65static BOOL WINAPI io_sigset_handler_routine(DWORD dwCtrlType);
66static BOOL io_sigset_handler(
int signo);
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);
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
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(
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
99static void io_sigset_impl_svc_shutdown(
struct io_svc *svc);
102static const struct io_svc_vtbl io_sigset_impl_svc_vtbl = {
104 &io_sigset_impl_svc_shutdown
115 struct io_cp signal_cp;
121 CRITICAL_SECTION CriticalSection;
123 unsigned shutdown : 1;
124 unsigned signal_posted : 1;
125 unsigned wait_posted : 1;
126 unsigned pending : 1;
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);
140 const struct io_svc *svc);
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);
149io_win32_sigset_init(
void)
151 InitializeCriticalSection(&io_sigset_shared.CriticalSection);
152 if (!SetConsoleCtrlHandler(&io_sigset_handler_routine, TRUE)) {
153 DeleteCriticalSection(&io_sigset_shared.CriticalSection);
160io_win32_sigset_fini(
void)
162 SetConsoleCtrlHandler(&io_sigset_handler_routine, FALSE);
163 DeleteCriticalSection(&io_sigset_shared.CriticalSection);
174 return &impl->sigset_vptr;
178io_sigset_free(
void *ptr)
181 free(io_sigset_impl_from_sigset(ptr));
193 impl->dev_vptr = &io_sigset_impl_dev_vtbl;
194 impl->sigset_vptr = &io_sigset_impl_vtbl;
204 &io_sigset_impl_signal_cp_func);
206 impl->
exec, &io_sigset_impl_wait_task_func);
209 InitializeCriticalSection(&impl->CriticalSection);
213 impl->signal_posted = 0;
214 impl->wait_posted = 0;
219 for (
int i = 1; i < LELY_NSIG; i++)
235 io_sigset_impl_svc_shutdown(&impl->svc);
241 EnterCriticalSection(&impl->CriticalSection);
244 while (impl->wait_posted) {
248 LeaveCriticalSection(&impl->CriticalSection);
250 EnterCriticalSection(&impl->CriticalSection);
252 LeaveCriticalSection(&impl->CriticalSection);
254 DeleteCriticalSection(&impl->CriticalSection);
265 dwErrCode = GetLastError();
269 io_sigset_t *tmp = io_sigset_init(sigset, poll, exec);
271 dwErrCode = GetLastError();
279 io_sigset_free((
void *)sigset);
281 SetLastError(dwErrCode);
289 io_sigset_fini(sigset);
290 io_sigset_free((
void *)sigset);
295io_sigset_handler_routine(DWORD dwCtrlType)
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)) {
309 case CTRL_LOGOFF_EVENT:
310 case CTRL_SHUTDOWN_EVENT:
311 default:
return FALSE;
316io_sigset_handler(
int signo)
319 assert(signo < LELY_NSIG);
321 EnterCriticalSection(&io_sigset_shared.CriticalSection);
323 for (
struct io_sigset_node *node = list; node; node = node->next) {
327 assert(node->watched);
328 if (!node->pending) {
330 if (!impl->signal_posted) {
331 impl->signal_posted = 1;
336 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
341io_sigset_impl_dev_get_ctx(
const io_dev_t *dev)
349io_sigset_impl_dev_get_exec(
const io_dev_t *dev)
364 io_sigset_impl_pop(impl, &queue, task);
366 return io_sigset_wait_queue_post(&queue, 0);
377 io_sigset_impl_pop(impl, &queue, task);
385 const struct io_sigset_impl *impl = io_sigset_impl_from_sigset(sigset);
387 return &impl->dev_vptr;
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);
404io_sigset_impl_insert(
io_sigset_t *sigset,
int signo)
408 if (signo <= 0 || signo >= LELY_NSIG) {
409 SetLastError(ERROR_INVALID_PARAMETER);
413 EnterCriticalSection(&io_sigset_shared.CriticalSection);
414 io_sigset_impl_do_insert(impl, signo);
415 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
421io_sigset_impl_remove(
io_sigset_t *sigset,
int signo)
425 if (signo <= 0 || signo >= LELY_NSIG) {
426 SetLastError(ERROR_INVALID_PARAMETER);
430 EnterCriticalSection(&io_sigset_shared.CriticalSection);
431 io_sigset_impl_do_remove(impl, signo);
432 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
445 task->
exec = impl->exec;
449 EnterCriticalSection(&impl->CriticalSection);
451 if (impl->shutdown) {
453 LeaveCriticalSection(&impl->CriticalSection);
455 io_sigset_wait_post(wait, 0);
458 int post_wait = !impl->wait_posted && impl->pending;
460 impl->wait_posted = 1;
462 LeaveCriticalSection(&impl->CriticalSection);
471io_sigset_impl_svc_shutdown(
struct io_svc *svc)
477 EnterCriticalSection(&impl->CriticalSection);
479 int shutdown = !impl->shutdown;
483 if (shutdown && impl->wait_posted
487 impl->wait_posted = 0;
489 LeaveCriticalSection(&impl->CriticalSection);
494 io_sigset_impl_dev_cancel(dev, NULL);
498io_sigset_impl_signal_cp_func(
struct io_cp *cp,
size_t nbytes,
int errc)
507 EnterCriticalSection(&impl->CriticalSection);
510 int post_wait = !impl->wait_posted && !
sllist_empty(&impl->queue)
513 impl->wait_posted = 1;
515 LeaveCriticalSection(&impl->CriticalSection);
518 EnterCriticalSection(&io_sigset_shared.CriticalSection);
519 impl->signal_posted = 0;
520 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
527io_sigset_impl_wait_task_func(
struct ev_task *task)
534 int signo = LELY_NSIG;
537 EnterCriticalSection(&impl->CriticalSection);
540 EnterCriticalSection(&io_sigset_shared.CriticalSection);
551 LeaveCriticalSection(&io_sigset_shared.CriticalSection);
554 impl->pending = signo != LELY_NSIG;
555 int post_wait = impl->wait_posted = impl->pending
558 LeaveCriticalSection(&impl->CriticalSection);
562 io_sigset_wait_post(wait, signo);
569io_sigset_impl_from_dev(
const io_dev_t *dev)
577io_sigset_impl_from_sigset(
const io_sigset_t *sigset)
585io_sigset_impl_from_svc(
const struct io_svc *svc)
600 EnterCriticalSection(&impl->CriticalSection);
607 LeaveCriticalSection(&impl->CriticalSection);
616 assert(signo < LELY_NSIG);
619 assert(node->signo == signo);
624 assert(!node->pending);
626 node->next = io_sigset_shared.list[signo - 1];
627 io_sigset_shared.list[signo - 1] = node;
635 assert(signo < LELY_NSIG);
638 assert(node->signo == signo);
647 while (*
pnode != node)
649 assert(*
pnode == node);
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.
#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 native and platform-independent er...
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
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.
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.
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.
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.
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.
void io_sigset_destroy(io_sigset_t *sigset)
Destroys a 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....
An I/O polling interface.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
An I/O completion packet.
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.
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.