static inline int _mk_event_channel_create(struct mk_event_ctx *ctx, int *r_fd, int *w_fd, void *data) { int ret; int fd[2]; struct mk_event *event; ret = pipe(fd); if (ret < 0) { mk_libc_error("pipe"); return ret; } event = data; event->fd = fd[0]; event->type = MK_EVENT_NOTIFICATION; event->mask = MK_EVENT_EMPTY; ret = _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, event); if (ret != 0) { close(fd[0]); close(fd[1]); return ret; } *r_fd = fd[0]; *w_fd = fd[1]; return 0; }
/* Register a timeout file descriptor */ static inline int _mk_event_timeout_create(mk_event_ctx_t *ctx, int expire) { int ret; int timer_fd; struct itimerspec its; /* expiration interval */ its.it_interval.tv_sec = expire; its.it_interval.tv_nsec = 0; /* initial expiration */ its.it_value.tv_sec = time(NULL) + expire; its.it_value.tv_nsec = 0; timer_fd = timerfd_create(CLOCK_REALTIME, 0); if (timer_fd == -1) { mk_libc_error("timerfd"); return -1; } ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); if (ret < 0) { mk_libc_error("timerfd_settime"); return -1; } /* register the timer into the epoll queue */ ret = _mk_event_add(ctx, timer_fd, MK_EVENT_READ); if (ret != 0) { close(timer_fd); return ret; } return timer_fd; }
/* Register or modify an event */ int mk_event_add(struct mk_event_loop *loop, int fd, int type, uint32_t mask, void *data) { int ret; struct mk_event_ctx *ctx; mk_bug(!data); ctx = loop->data; ret = _mk_event_add(ctx, fd, type, mask, data); if (ret == -1) { return -1; } return 0; }
/* * This routine creates a timer, since this select(2) backend aims to be used * in very old systems to be compatible, we cannot trust timerfd_create(2) * will be available (e.g: Cygwin), so our workaround is to create a pipe(2) * and a thread, this thread writes a byte upon the expiration time is reached. */ static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx, time_t sec, long nsec, void *data) { int ret; int fd[2]; struct mk_event *event; struct fd_timer *timer; timer = mk_mem_alloc(sizeof(struct fd_timer)); if (!timer) { return -1; } ret = pipe(fd); if (ret < 0) { mk_mem_free(timer); mk_libc_error("pipe"); return ret; } event = (struct mk_event *) data; event->fd = fd[0]; event->type = MK_EVENT_NOTIFICATION; event->mask = MK_EVENT_EMPTY; _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data); event->mask = MK_EVENT_READ; /* Compose the timer context, this is released inside the worker thread */ timer->fd = fd[1]; timer->sec = sec; timer->nsec = nsec; timer->run = MK_TRUE; event->data = timer; /* Now the dirty workaround, create a thread */ ret = mk_utils_worker_spawn(_timeout_worker, timer, &timer->tid); if (ret < 0) { close(fd[0]); close(fd[1]); mk_mem_free(timer); return -1; } return fd[0]; }
/* Register a timeout file descriptor */ static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx, time_t sec, long nsec, void *data) { int ret; int timer_fd; struct itimerspec its; struct mk_event *event; mk_bug(!data); memset(&its, '\0', sizeof(struct itimerspec)); /* expiration interval */ its.it_interval.tv_sec = sec; its.it_interval.tv_nsec = nsec; /* initial expiration */ its.it_value.tv_sec = time(NULL) + sec; its.it_value.tv_nsec = 0; timer_fd = timerfd_create(CLOCK_REALTIME, 0); if (timer_fd == -1) { mk_libc_error("timerfd"); return -1; } ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); if (ret < 0) { mk_libc_error("timerfd_settime"); return -1; } event = data; event->fd = timer_fd; event->type = MK_EVENT_NOTIFICATION; event->mask = MK_EVENT_EMPTY; /* register the timer into the epoll queue */ ret = _mk_event_add(ctx, timer_fd, MK_EVENT_NOTIFICATION, MK_EVENT_READ, data); if (ret != 0) { close(timer_fd); return ret; } return timer_fd; }
/* Register or modify an event */ int mk_event_add(mk_event_loop_t *loop, int fd, int mask, void *data) { int ret; mk_event_ctx_t *ctx; struct mk_event_fd_state *fds; ctx = loop->data; ret = _mk_event_add(ctx, fd, mask); if (ret == -1) { return -1; } fds = mk_event_get_state(fd); fds->mask = mask; fds->data = data; return 0; }
static inline int _mk_event_channel_create(mk_event_ctx_t *ctx, int *r_fd, int *w_fd) { int fd; int ret; fd = eventfd(0, EFD_CLOEXEC); if (fd == -1) { mk_libc_error("eventfd"); return -1; } ret = _mk_event_add(ctx, fd, MK_EVENT_READ); if (ret != 0) { close(fd); return ret; } *w_fd = *r_fd = fd; return 0; }
/* * This routine creates a timer, since this select(2) backend aims to be used * in very old systems to be compatible, we cannot trust timerfd_create(2) * will be available (e.g: Cygwin), so our workaround is to create a pipe(2) * and a thread, this thread writes a byte upon the expiration time is reached. */ static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx, int expire, void *data) { int ret; int fd[2]; pid_t tid; struct mk_event *event; struct fd_timer *timer; timer = mk_mem_malloc(sizeof(struct fd_timer)); if (!timer) { return -1; } ret = pipe(fd); if (ret < 0) { mk_mem_free(timer); mk_libc_error("pipe"); return ret; } event = (struct mk_event *) data; event->fd = fd[0]; event->type = MK_EVENT_NOTIFICATION; event->mask = MK_EVENT_EMPTY; _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data); event->mask = MK_EVENT_READ; /* Compose the timer context, this is released inside the worker thread */ timer->fd = fd[1]; timer->expiration = expire; /* Now the dirty workaround, create a thread */ mk_utils_worker_spawn(_timeout_worker, timer); return fd[0]; }