26#if !LELY_NO_STDIO && defined(__linux__)
46#include <sys/timerfd.h>
50static size_t io_timer_impl_dev_cancel(
io_dev_t *dev,
struct ev_task *task);
51static size_t io_timer_impl_dev_abort(
io_dev_t *dev,
struct ev_task *task);
54static const struct io_dev_vtbl io_timer_impl_dev_vtbl = {
55 &io_timer_impl_dev_get_ctx,
56 &io_timer_impl_dev_get_exec,
57 &io_timer_impl_dev_cancel,
58 &io_timer_impl_dev_abort
64static int io_timer_impl_getoverrun(
const io_timer_t *timer);
65static int io_timer_impl_gettime(
66 const io_timer_t *timer,
struct itimerspec *value);
67static int io_timer_impl_settime(
io_timer_t *timer,
int flags,
68 const struct itimerspec *value,
struct itimerspec *ovalue);
69static void io_timer_impl_submit_wait(
74 &io_timer_impl_get_dev,
75 &io_timer_impl_get_clock,
76 &io_timer_impl_getoverrun,
77 &io_timer_impl_gettime,
78 &io_timer_impl_settime,
79 &io_timer_impl_submit_wait
83static int io_timer_impl_svc_notify_fork(
85static void io_timer_impl_svc_shutdown(
struct io_svc *svc);
88static const struct io_svc_vtbl io_timer_impl_svc_vtbl = {
89 &io_timer_impl_svc_notify_fork,
90 &io_timer_impl_svc_shutdown
108 unsigned shutdown : 1;
109 unsigned wait_posted : 1;
114static void io_timer_impl_watch_func(
struct io_poll_watch *watch,
int events);
115static void io_timer_impl_wait_task_func(
struct ev_task *task);
121 const struct io_svc *svc);
136 impl->timer_vptr = NULL;
138 return &impl->timer_vptr;
142io_timer_free(
void *ptr)
145 free(io_timer_impl_from_timer(ptr));
152 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
160 impl->dev_vptr = &io_timer_impl_dev_vtbl;
161 impl->timer_vptr = &io_timer_impl_vtbl;
170 impl->clockid = clockid;
173 &io_timer_impl_watch_func);
177 impl->
exec, &io_timer_impl_wait_task_func);
180 if ((errsv = pthread_mutex_init(&impl->mtx, NULL)))
185 impl->wait_posted = 0;
191 if (io_timer_impl_open(impl) == -1) {
203 pthread_mutex_destroy(&impl->mtx);
213 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
217 io_timer_impl_svc_shutdown(&impl->svc);
220 pthread_mutex_lock(&impl->mtx);
223 while (impl->wait_posted) {
227 pthread_mutex_unlock(&impl->mtx);
229 pthread_mutex_lock(&impl->mtx);
231 pthread_mutex_unlock(&impl->mtx);
235 io_timer_impl_close(impl);
238 pthread_mutex_destroy(&impl->mtx);
253 io_timer_t *tmp = io_timer_init(timer, poll, exec, clockid);
263 io_timer_free((
void *)timer);
273 io_timer_fini(timer);
274 io_timer_free((
void *)timer);
279io_timer_impl_dev_get_ctx(
const io_dev_t *dev)
281 const struct io_timer_impl *impl = io_timer_impl_from_dev(dev);
287io_timer_impl_dev_get_exec(
const io_dev_t *dev)
289 const struct io_timer_impl *impl = io_timer_impl_from_dev(dev);
302 io_timer_impl_pop(impl, &queue, task);
304 return io_timer_wait_queue_post(&queue, -1, ECANCELED);
315 io_timer_impl_pop(impl, &queue, task);
323 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
325 return &impl->dev_vptr;
329io_timer_impl_get_clock(
const io_timer_t *timer)
331 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
332 assert(impl->clockid == CLOCK_REALTIME
333 || impl->clockid == CLOCK_MONOTONIC);
335 switch (impl->clockid) {
338 default:
return NULL;
343io_timer_impl_getoverrun(
const io_timer_t *timer)
345 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
348 pthread_mutex_lock((pthread_mutex_t *)&impl->mtx);
350 int overrun = impl->overrun;
352 pthread_mutex_unlock((pthread_mutex_t *)&impl->mtx);
359io_timer_impl_gettime(
const io_timer_t *timer,
struct itimerspec *value)
361 const struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
363 return timerfd_gettime(impl->tfd, value);
367io_timer_impl_settime(
io_timer_t *timer,
int flags,
368 const struct itimerspec *value,
struct itimerspec *ovalue)
370 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
373 if (flags & TIMER_ABSTIME)
374 flags_ |= TFD_TIMER_ABSTIME;
376 return timerfd_settime(impl->tfd, flags_, value, ovalue);
382 struct io_timer_impl *impl = io_timer_impl_from_timer(timer);
387 task->
exec = impl->exec;
391 pthread_mutex_lock(&impl->mtx);
393 if (impl->shutdown) {
395 pthread_mutex_unlock(&impl->mtx);
397 io_timer_wait_post(wait, -1, ECANCELED);
401 pthread_mutex_unlock(&impl->mtx);
417 struct itimerspec value = { { 0, 0 }, { 0, 0 } };
418 if (timerfd_gettime(impl->tfd, &value) == -1) {
423 if (io_timer_impl_close(impl) == -1 && !result) {
428 if (io_timer_impl_open(impl) == -1 && !result) {
433 if (timerfd_settime(impl->tfd, 0, &value, NULL) == -1 && !result) {
443io_timer_impl_svc_shutdown(
struct io_svc *svc)
449 pthread_mutex_lock(&impl->mtx);
451 int shutdown = !impl->shutdown;
461 impl->wait_posted = 0;
464 pthread_mutex_unlock(&impl->mtx);
469 io_timer_impl_dev_cancel(dev, NULL);
473io_timer_impl_watch_func(
struct io_poll_watch *watch,
int events)
481 pthread_mutex_lock(&impl->mtx);
483 int post_wait = !impl->wait_posted && !impl->shutdown;
485 impl->wait_posted = 1;
487 pthread_mutex_unlock(&impl->mtx);
495io_timer_impl_wait_task_func(
struct ev_task *task)
510 result = read(impl->tfd, &value,
sizeof(value));
511 }
while (result == -1 && errno == EINTR);
512 if (result !=
sizeof(value))
515 if (value > (uintmax_t)INT_MAX + 1)
516 value = (uintmax_t)INT_MAX + 1;
517 if (overrun > (
int)(INT_MAX - value))
522 if (result == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
531 pthread_mutex_lock(&impl->mtx);
534 impl->overrun = overrun;
535 if (overrun >= 0 || errno)
538 if (events && !impl->shutdown)
540 impl->wait_posted = 0;
542 pthread_mutex_unlock(&impl->mtx);
545 io_timer_wait_queue_post(&queue, overrun, errno);
550io_timer_impl_from_dev(
const io_dev_t *dev)
558io_timer_impl_from_timer(
const io_timer_t *timer)
566io_timer_impl_from_svc(
const struct io_svc *svc)
581 pthread_mutex_lock(&impl->mtx);
588 pthread_mutex_unlock(&impl->mtx);
599 if (io_timer_impl_close(impl) == -1) {
604 impl->tfd = timerfd_create(impl->clockid, TFD_NONBLOCK | TFD_CLOEXEC);
605 if (impl->tfd == -1) {
607 goto error_timerfd_create;
613 goto error_poll_watch;
647 if (close(tfd) == -1 && !result) {
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.
io_fork_event
The type of event generated by an I/O context before and after a process fork.
@ IO_FORK_CHILD
The event generated after the fork in the child process.
#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.
@ IO_EVENT_IN
Data (other than priority data) MAY be read without blocking.
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.
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.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
This header file is part of the I/O library; it contains the I/O polling declarations for POSIX platf...
#define IO_POLL_WATCH_INIT(func)
The static initializer for io_poll_watch.
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.
int io_poll_watch(io_poll_t *poll, io_handle_t handle, struct io_event *event, int keep)
Registers an I/O device with an I/O polling interface and instructs it to watch for certain events.
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.
An object representing a file descriptor being monitored for I/O events.
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.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....