42 static size_t io_timer_impl_dev_cancel(
io_dev_t *dev,
struct ev_task *task);
43 static size_t io_timer_impl_dev_abort(
io_dev_t *dev,
struct ev_task *task);
46 static const struct io_dev_vtbl io_timer_impl_dev_vtbl = {
47 &io_timer_impl_dev_get_ctx,
48 &io_timer_impl_dev_get_exec,
49 &io_timer_impl_dev_cancel,
50 &io_timer_impl_dev_abort
56 static int io_timer_impl_getoverrun(
const io_timer_t *timer);
57 static int io_timer_impl_gettime(
58 const io_timer_t *timer,
struct itimerspec *value);
59 static int io_timer_impl_settime(
io_timer_t *timer,
int flags,
60 const struct itimerspec *value,
struct itimerspec *ovalue);
61 static void io_timer_impl_submit_wait(
66 &io_timer_impl_get_dev,
67 &io_timer_impl_get_clock,
68 &io_timer_impl_getoverrun,
69 &io_timer_impl_gettime,
70 &io_timer_impl_settime,
71 &io_timer_impl_submit_wait
75 static void io_timer_impl_svc_shutdown(
struct io_svc *svc);
78 static const struct io_svc_vtbl io_timer_impl_svc_vtbl = {
80 &io_timer_impl_svc_shutdown
92 CRITICAL_SECTION CriticalSection1;
97 CRITICAL_SECTION CriticalSection2;
99 struct itimerspec value;
102 CRITICAL_SECTION CriticalSection3;
107 static void CALLBACK io_timer_impl_func(
108 PVOID lpParameter, BOOLEAN TimerOrWaitFired);
111 static inline struct io_timer_impl *io_timer_impl_from_timer(
114 const struct io_svc *svc);
127 return &impl->timer_vptr;
131 io_timer_free(
void *ptr)
134 free(io_timer_impl_from_timer(ptr));
141 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
147 impl->dev_vptr = &io_timer_impl_dev_vtbl;
148 impl->timer_vptr = &io_timer_impl_vtbl;
155 impl->clockid = clockid;
158 InitializeCriticalSection(&impl->CriticalSection1);
164 InitializeCriticalSection(&impl->CriticalSection2);
166 impl->value = (
struct itimerspec){ { 0, 0 }, { 0, 0 } };
170 InitializeCriticalSection(&impl->CriticalSection3);
182 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
186 io_timer_impl_svc_shutdown(&impl->svc);
189 DeleteTimerQueueTimer(NULL, impl->Timer, INVALID_HANDLE_VALUE);
192 DeleteCriticalSection(&impl->CriticalSection3);
193 DeleteCriticalSection(&impl->CriticalSection2);
194 DeleteCriticalSection(&impl->CriticalSection1);
205 dwErrCode = GetLastError();
209 io_timer_t *tmp = io_timer_init(timer, poll, exec, clockid);
211 dwErrCode = GetLastError();
219 io_timer_free((
void *)timer);
221 SetLastError(dwErrCode);
229 io_timer_fini(timer);
230 io_timer_free((
void *)timer);
235 io_timer_impl_dev_get_ctx(
const io_dev_t *dev)
237 const struct io_timer_impl *impl = io_timer_impl_from_dev(dev);
243 io_timer_impl_dev_get_exec(
const io_dev_t *dev)
245 const struct io_timer_impl *impl = io_timer_impl_from_dev(dev);
258 io_timer_impl_pop(impl, &queue, task);
260 return io_timer_wait_queue_post(&queue, -1, ERROR_OPERATION_ABORTED);
271 io_timer_impl_pop(impl, &queue, task);
277 io_timer_impl_get_dev(
const io_timer_t *timer)
279 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
281 return &impl->dev_vptr;
285 io_timer_impl_get_clock(
const io_timer_t *timer)
287 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
288 assert(impl->clockid == CLOCK_REALTIME
289 || impl->clockid == CLOCK_MONOTONIC);
291 switch (impl->clockid) {
294 default:
return NULL;
299 io_timer_impl_getoverrun(
const io_timer_t *timer)
301 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
304 EnterCriticalSection((LPCRITICAL_SECTION)&impl->CriticalSection2);
306 int overrun = impl->overrun;
308 LeaveCriticalSection((LPCRITICAL_SECTION)&impl->CriticalSection2);
315 io_timer_impl_gettime(
const io_timer_t *timer,
struct itimerspec *value)
317 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
321 EnterCriticalSection((LPCRITICAL_SECTION)&impl->CriticalSection2);
323 struct itimerspec value_ = impl->value;
325 LeaveCriticalSection((LPCRITICAL_SECTION)&impl->CriticalSection2);
328 if (value_.it_value.tv_sec || value_.it_value.tv_nsec) {
329 struct timespec now = { 0, 0 };
330 if (clock_gettime(impl->clockid, &now) == -1) {
344 io_timer_impl_settime(
io_timer_t *timer,
int flags,
345 const struct itimerspec *value,
struct itimerspec *ovalue)
347 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
350 struct timespec now = { 0, 0 };
351 if (clock_gettime(impl->clockid, &now) == -1) {
356 ULONGLONG DueTime = 0;
357 ULONGLONG Period = 0;
359 struct timespec period = value->it_interval;
360 struct timespec expiry = value->it_value;
361 int arm = expiry.tv_sec || expiry.tv_nsec;
363 if (period.tv_nsec < 0 || period.tv_nsec >= 1000000000l) {
364 SetLastError(ERROR_INVALID_PARAMETER);
367 if (period.tv_sec < 0)
368 period = (
struct timespec){ 0, 0 };
369 Period = (ULONGLONG)period.tv_sec * 1000
370 + (period.tv_nsec + 999999l) / 1000000l;
371 period.tv_nsec = (Period % 1000) * 1000000l;
372 if (Period > ULONG_MAX) {
373 SetLastError(ERROR_INVALID_PARAMETER);
377 if (expiry.tv_nsec < 0 || expiry.tv_nsec >= 1000000000l) {
378 SetLastError(ERROR_INVALID_PARAMETER);
381 if (flags & TIMER_ABSTIME)
383 if (expiry.tv_sec < 0)
384 expiry = (
struct timespec){ 0, 0 };
385 DueTime = (ULONGLONG)expiry.tv_sec * 1000
386 + (expiry.tv_nsec + 999999l) / 1000000l;
387 if (DueTime > ULONG_MAX) {
388 SetLastError(ERROR_INVALID_PARAMETER);
394 period = (
struct timespec){ 0, 0 };
398 DWORD dwErrCode = GetLastError();
401 EnterCriticalSection(&impl->CriticalSection3);
405 DeleteTimerQueueTimer(NULL, impl->Timer, INVALID_HANDLE_VALUE);
410 EnterCriticalSection(&impl->CriticalSection2);
413 struct itimerspec ovalue_ = impl->value;
414 if (ovalue_.it_value.tv_sec || ovalue_.it_value.tv_nsec)
416 impl->value = (
struct itimerspec){ period, expiry };
420 ULONG Flags = WT_EXECUTEDEFAULT;
422 Flags |= WT_EXECUTEONLYONCE;
425 if (arm && !CreateTimerQueueTimer(&impl->Timer, NULL,
426 &io_timer_impl_func, impl, DueTime, Period, Flags)) {
429 dwErrCode = GetLastError();
431 impl->value = (
struct itimerspec){ { 0, 0 }, { 0, 0 } };
435 LeaveCriticalSection(&impl->CriticalSection2);
436 LeaveCriticalSection(&impl->CriticalSection3);
442 SetLastError(dwErrCode);
449 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
454 task->
exec = impl->exec;
458 EnterCriticalSection(&impl->CriticalSection1);
460 if (impl->shutdown) {
462 LeaveCriticalSection(&impl->CriticalSection1);
464 io_timer_wait_post(wait, -1, ERROR_OPERATION_ABORTED);
468 LeaveCriticalSection(&impl->CriticalSection1);
474 io_timer_impl_svc_shutdown(
struct io_svc *svc)
480 EnterCriticalSection(&impl->CriticalSection1);
482 int shutdown = !impl->shutdown;
485 LeaveCriticalSection(&impl->CriticalSection1);
489 io_timer_impl_dev_cancel(dev, NULL);
493 io_timer_impl_func(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
497 (void)TimerOrWaitFired;
503 struct timespec now = { 0, 0 };
504 if (clock_gettime(impl->clockid, &now) == -1) {
513 EnterCriticalSection(&impl->CriticalSection2);
517 struct timespec *period = &impl->value.it_interval;
518 struct timespec *expiry = &impl->value.it_value;
519 if (period->tv_sec || period->tv_nsec) {
520 assert(!(period->tv_nsec % 1000000l));
521 ULONG Period = period->tv_sec * 1000
522 + period->tv_nsec / 1000000l;
526 impl->overrun =
MIN(
MAX(overrun, INT_MIN), INT_MAX);
528 *expiry = (
struct timespec){ 0, 0 };
531 overrun = impl->overrun;
534 if (overrun >= 0 || errc)
538 LeaveCriticalSection(&impl->CriticalSection2);
541 io_timer_wait_queue_post(&queue, overrun, errc);
546 io_timer_impl_from_dev(
const io_dev_t *dev)
554 io_timer_impl_from_timer(
const io_timer_t *timer)
562 io_timer_impl_from_svc(
const struct io_svc *svc)
577 EnterCriticalSection(&impl->CriticalSection1);
584 LeaveCriticalSection(&impl->CriticalSection1);
const struct io_clock_vtbl *const io_clock_t
An abstract clock.
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.
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.
This header file is part of the I/O library; it contains the I/O system timer declarations.
const struct io_timer_vtbl *const io_timer_t
An abstract timer.
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.
#define MIN(a, b)
Returns the minimum of a and b.
#define MAX(a, b)
Returns the maximum of a and b.
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.
io_timer_t * io_timer_create(io_poll_t *poll, ev_exec_t *exec, clockid_t clockid)
Creates a new I/O system timer.
void io_timer_destroy(io_timer_t *timer)
Destroys an I/O system timer.
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.
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.
The virtual table of an I/O service.
A wait operation suitable for use with an I/O timer.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the wait operation.
This header file is part of the I/O library; it contains the standard system clock definitions.
#define IO_CLOCK_REALTIME
The io_clock_t pointer representing the POSIX realtime clock.
#define IO_CLOCK_MONOTONIC
The io_clock_t pointer representing the POSIX monotonic clock.
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.
This header file is part of the utilities library; it contains the time function declarations.
void timespec_add(struct timespec *tp, const struct timespec *inc)
Adds the time interval *inc to the time at tp.
void timespec_sub(struct timespec *tp, const struct timespec *dec)
Subtracts the time interval *dec from the time at tp.
void timespec_add_msec(struct timespec *tp, uint_least64_t msec)
Adds msec milliseconds to the time at tp.
int_least64_t timespec_diff_msec(const struct timespec *t1, const struct timespec *t2)
Returns the time difference (in milliseconds) between *t1 and *t2.