summaryrefslogtreecommitdiff
path: root/accel-pppd/triton/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/triton/timer.c')
-rw-r--r--accel-pppd/triton/timer.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/accel-pppd/triton/timer.c b/accel-pppd/triton/timer.c
new file mode 100644
index 00000000..e419e938
--- /dev/null
+++ b/accel-pppd/triton/timer.c
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#ifdef HAVE_TIMERFD
+#include <sys/timerfd.h>
+#else
+#include "timerfd.h"
+#endif
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+extern int max_events;
+static int epoll_fd;
+static struct epoll_event *epoll_events;
+
+static pthread_t timer_thr;
+static void *timer_thread(void *arg);
+
+static mempool_t *timer_pool;
+
+static pthread_mutex_t freed_list_lock = PTHREAD_MUTEX_INITIALIZER;
+static LIST_HEAD(freed_list);
+static LIST_HEAD(freed_list2);
+
+int timer_init(void)
+{
+ epoll_fd = epoll_create(1);
+ if (epoll_fd < 0) {
+ perror("timer:epoll_create");
+ return -1;
+ }
+
+ epoll_events = _malloc(max_events * sizeof(struct epoll_event));
+ if (!epoll_events) {
+ fprintf(stderr,"timer:cann't allocate memory\n");
+ return -1;
+ }
+
+ timer_pool = mempool_create(sizeof(struct _triton_timer_t));
+
+ return 0;
+}
+
+void timer_run(void)
+{
+ if (pthread_create(&timer_thr, NULL, timer_thread, NULL)) {
+ triton_log_error("timer:pthread_create: %s",strerror(errno));
+ _exit(-1);
+ }
+}
+
+void timer_terminate(void)
+{
+ pthread_cancel(timer_thr);
+ pthread_join(timer_thr, NULL);
+}
+
+void *timer_thread(void *arg)
+{
+ int i,n,r;
+ struct _triton_timer_t *t;
+ sigset_t set;
+
+ sigfillset(&set);
+ sigdelset(&set, SIGKILL);
+ sigdelset(&set, SIGSTOP);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ while(1) {
+ n = epoll_wait(epoll_fd, epoll_events, max_events, -1);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ triton_log_error("timer:epoll_wait: %s", strerror(errno));
+ _exit(-1);
+ }
+
+ for(i = 0; i < n; i++) {
+ t = (struct _triton_timer_t *)epoll_events[i].data.ptr;
+ if (!t->ud)
+ continue;
+ spin_lock(&t->ctx->lock);
+ if (t->ud) {
+ if (!t->pending) {
+ list_add_tail(&t->entry2, &t->ctx->pending_timers);
+ t->pending = 1;
+ __sync_add_and_fetch(&triton_stat.timer_pending, 1);
+ r = triton_queue_ctx(t->ctx);
+ } else
+ r = 0;
+ } else
+ r = 0;
+ spin_unlock(&t->ctx->lock);
+ if (r)
+ triton_thread_wakeup(t->ctx->thread);
+ }
+
+ while (!list_empty(&freed_list2)) {
+ t = list_entry(freed_list2.next, typeof(*t), entry);
+ list_del(&t->entry);
+ mempool_free(t);
+ }
+
+ pthread_mutex_lock(&freed_list_lock);
+ while (!list_empty(&freed_list)) {
+ t = list_entry(freed_list.next, typeof(*t), entry);
+ list_del(&t->entry);
+ list_add(&t->entry, &freed_list2);
+ }
+ pthread_mutex_unlock(&freed_list_lock);
+ }
+
+ return NULL;
+}
+
+
+int __export triton_timer_add(struct triton_context_t *ctx, struct triton_timer_t *ud, int abs_time)
+{
+ struct _triton_timer_t *t = mempool_alloc(timer_pool);
+
+ memset(t, 0, sizeof(*t));
+ t->ud = ud;
+ t->epoll_event.data.ptr = t;
+ t->epoll_event.events = EPOLLIN | EPOLLET;
+ if (ctx)
+ t->ctx = (struct _triton_context_t *)ctx->tpd;
+ else
+ t->ctx = (struct _triton_context_t *)default_ctx.tpd;
+ t->fd = timerfd_create(abs_time ? CLOCK_REALTIME : CLOCK_MONOTONIC, 0);
+ if (t->fd < 0) {
+ triton_log_error("timer:timerfd_create: %s", strerror(errno));
+ mempool_free(t);
+ return -1;
+ }
+
+ if (fcntl(t->fd, F_SETFL, O_NONBLOCK)) {
+ triton_log_error("timer: failed to set nonblocking mode: %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ ud->tpd = t;
+
+ if (triton_timer_mod(ud, abs_time))
+ goto out_err;
+
+ spin_lock(&t->ctx->lock);
+ list_add_tail(&t->entry, &t->ctx->timers);
+ spin_unlock(&t->ctx->lock);
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, t->fd, &t->epoll_event)) {
+ triton_log_error("timer:epoll_ctl: %s", strerror(errno));
+ spin_lock(&t->ctx->lock);
+ t->ud = NULL;
+ list_del(&t->entry);
+ spin_unlock(&t->ctx->lock);
+ goto out_err;
+ }
+
+ triton_stat.timer_count++;
+
+ return 0;
+
+out_err:
+ ud->tpd = NULL;
+ close(t->fd);
+ mempool_free(t);
+ return -1;
+}
+int __export triton_timer_mod(struct triton_timer_t *ud,int abs_time)
+{
+ struct _triton_timer_t *t = (struct _triton_timer_t *)ud->tpd;
+ struct itimerspec ts = {
+ .it_value.tv_sec = ud->expire_tv.tv_sec,
+ .it_value.tv_nsec = ud->expire_tv.tv_usec * 1000,
+ .it_interval.tv_sec = ud->period / 1000,
+ .it_interval.tv_nsec = (ud->period % 1000) * 1000,
+ };
+
+ if (ud->expire_tv.tv_sec == 0 && ud->expire_tv.tv_usec == 0)
+ ts.it_value = ts.it_interval;
+
+ if (timerfd_settime(t->fd, abs_time ? TFD_TIMER_ABSTIME : 0, &ts, NULL)) {
+ triton_log_error("timer:timerfd_settime: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+void __export triton_timer_del(struct triton_timer_t *ud)
+{
+ struct _triton_timer_t *t = (struct _triton_timer_t *)ud->tpd;
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, t->fd, &t->epoll_event);
+ close(t->fd);
+ spin_lock(&t->ctx->lock);
+ t->ud = NULL;
+ list_del(&t->entry);
+ if (t->pending) {
+ list_del(&t->entry2);
+ __sync_sub_and_fetch(&triton_stat.timer_pending, 1);
+ }
+ spin_unlock(&t->ctx->lock);
+
+ sched_yield();
+
+ pthread_mutex_lock(&freed_list_lock);
+ list_add_tail(&t->entry, &freed_list);
+ pthread_mutex_unlock(&freed_list_lock);
+
+ ud->tpd = NULL;
+
+ triton_stat.timer_count--;
+}
+