summaryrefslogtreecommitdiff
path: root/accel-pppd/triton
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/triton')
-rw-r--r--accel-pppd/triton/CMakeLists.txt40
-rw-r--r--accel-pppd/triton/conf_file.c248
-rw-r--r--accel-pppd/triton/event.c105
-rw-r--r--accel-pppd/triton/list.h249
-rw-r--r--accel-pppd/triton/loader.c62
-rw-r--r--accel-pppd/triton/log.c73
-rw-r--r--accel-pppd/triton/md.c216
-rw-r--r--accel-pppd/triton/mempool.c338
-rw-r--r--accel-pppd/triton/mempool.h26
-rw-r--r--accel-pppd/triton/options.c48
-rw-r--r--accel-pppd/triton/spinlock.h42
-rw-r--r--accel-pppd/triton/timer.c222
-rw-r--r--accel-pppd/triton/timerfd.c19
-rw-r--r--accel-pppd/triton/timerfd.h60
-rw-r--r--accel-pppd/triton/triton.c610
-rw-r--r--accel-pppd/triton/triton.h138
-rw-r--r--accel-pppd/triton/triton_p.h103
17 files changed, 2599 insertions, 0 deletions
diff --git a/accel-pppd/triton/CMakeLists.txt b/accel-pppd/triton/CMakeLists.txt
new file mode 100644
index 00000000..105b62a6
--- /dev/null
+++ b/accel-pppd/triton/CMakeLists.txt
@@ -0,0 +1,40 @@
+SET(sources_c
+ md.c
+ timer.c
+ triton.c
+ conf_file.c
+ loader.c
+ log.c
+ mempool.c
+ event.c
+)
+
+INCLUDE(CheckFunctionExists)
+CHECK_FUNCTION_EXISTS(timerfd_create HAVE_TIMERFD)
+
+IF (HAVE_TIMERFD)
+ ADD_DEFINITIONS(-DHAVE_TIMERFD)
+ELSE (HAVE_TIMERFD)
+ INCLUDE (CheckCSourceCompiles)
+ CHECK_C_SOURCE_COMPILES("
+ #include <sys/syscall.h>
+ int main()
+ {
+ syscall(SYS_timerfd_create);
+ }" HAVE_SYSCALL)
+ IF (NOT HAVE_SYSCALL)
+ MESSAGE(FATAL_ERROR "Your system is too old and is not supported by accel-ppp, sorry...")
+ ENDIF (NOT HAVE_SYSCALL)
+ SET(sources_c ${sources_c} timerfd.c)
+ENDIF (HAVE_TIMERFD)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_DEFINITIONS(-DMODULE_PATH="${CMAKE_INSTALL_PREFIX}/lib/accel-ppp")
+
+ADD_LIBRARY(triton SHARED ${sources_c})
+TARGET_LINK_LIBRARIES(triton dl)
+
+INSTALL(TARGETS triton
+ LIBRARY DESTINATION lib/accel-ppp
+)
diff --git a/accel-pppd/triton/conf_file.c b/accel-pppd/triton/conf_file.c
new file mode 100644
index 00000000..ce8549c9
--- /dev/null
+++ b/accel-pppd/triton/conf_file.c
@@ -0,0 +1,248 @@
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+struct sect_t
+{
+ struct list_head entry;
+
+ struct conf_sect_t *sect;
+};
+
+static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
+static LIST_HEAD(sections);
+static char *conf_fname;
+
+static char* skip_space(char *str);
+static char* skip_word(char *str);
+
+static struct conf_sect_t *find_sect(const char *name);
+static struct conf_sect_t *create_sect(const char *name);
+static void sect_add_item(struct conf_sect_t *sect, const char *name, const char *val);
+static struct conf_option_t *find_item(struct conf_sect_t *, const char *name);
+
+static char *buf;
+
+int __conf_load(const char *fname, struct conf_sect_t *cur_sect)
+{
+ char *str,*str2;
+ int cur_line = 0;
+
+ FILE *f = fopen(fname, "r");
+ if (!f) {
+ perror("conf_file:open");
+ return -1;
+ }
+
+ while(!feof(f)) {
+ if (!fgets(buf, 1024, f))
+ break;
+ ++cur_line;
+ if (buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = 0;
+
+ str = skip_space(buf);
+ if (*str == '#' || *str == 0)
+ continue;
+ if (strncmp(str, "$include", 8) == 0) {
+ str = skip_word(str);
+ str = skip_space(str);
+ if (__conf_load(str, cur_sect));
+ break;
+ continue;
+ }
+ if (*str == '[') {
+ for (str2 = ++str; *str2 && *str2 != ']'; str2++);
+ if (*str2 != ']') {
+ fprintf(stderr, "conf_file:%s:%i: sintax error\n", fname, cur_line);
+ return -1;
+ }
+ *str2 = 0;
+ cur_sect = find_sect(str);
+ if (!cur_sect)
+ cur_sect = create_sect(str);
+ continue;
+ }
+ if (!cur_sect) {
+ fprintf(stderr, "conf_file:%s:%i: no section opened\n", fname, cur_line);
+ return -1;
+ }
+ str2 = skip_word(str);
+ if (*str2 == ' ') {
+ *str2 = 0;
+ ++str2;
+ }
+ str2 = skip_space(str2);
+ if (*str2 == '=' || *str2 == ',') {
+ *str2 = 0;
+ str2 = skip_space(str2 + 1);
+ if (*str2 && *(str2 + 1) && *str2 == '$' && *(str2 + 1) == '{') {
+ char *s;
+ struct conf_option_t *opt;
+ for (s = str2+2; *s && *s != '}'; s++);
+ if (*s == '}') {
+ *s = 0;
+ str2 += 2;
+ }
+ opt = find_item(cur_sect, str2);
+ if (!opt) {
+ fprintf(stderr, "conf_file:%s:%i: parent option not found\n", fname, cur_line);
+ return -1;
+ }
+ str2 = opt->val;
+ }
+ } else
+ str2 = NULL;
+ sect_add_item(cur_sect, str, str2);
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+int conf_load(const char *fname)
+{
+ int r;
+
+ if (fname) {
+ if (conf_fname)
+ _free(conf_fname);
+ conf_fname = _strdup(fname);
+ } else
+ fname = conf_fname;
+
+ buf = _malloc(1024);
+
+ r = __conf_load(fname, NULL);
+
+ _free(buf);
+
+ return r;
+}
+
+int conf_reload(const char *fname)
+{
+ struct sect_t *sect;
+ struct conf_option_t *opt;
+ int r;
+ LIST_HEAD(sections_bak);
+
+ pthread_mutex_lock(&conf_lock);
+
+ while (!list_empty(&sections)) {
+ sect = list_entry(sections.next, typeof(*sect), entry);
+ list_del(&sect->entry);
+ list_add_tail(&sect->entry, &sections_bak);
+ }
+
+ r = conf_load(fname);
+
+ if (r) {
+ while (!list_empty(&sections_bak)) {
+ sect = list_entry(sections_bak.next, typeof(*sect), entry);
+ list_del(&sect->entry);
+ list_add_tail(&sect->entry, &sections);
+ }
+ pthread_mutex_unlock(&conf_lock);
+ } else {
+ pthread_mutex_unlock(&conf_lock);
+ while (!list_empty(&sections_bak)) {
+ sect = list_entry(sections_bak.next, typeof(*sect), entry);
+ list_del(&sect->entry);
+ while (!list_empty(&sect->sect->items)) {
+ opt = list_entry(sect->sect->items.next, typeof(*opt), entry);
+ list_del(&opt->entry);
+ if (opt->val)
+ _free(opt->val);
+ _free(opt->name);
+ _free(opt);
+ }
+ _free((char *)sect->sect->name);
+ _free(sect->sect);
+ _free(sect);
+ }
+ }
+
+ return r;
+}
+
+static char* skip_space(char *str)
+{
+ for (; *str && *str == ' '; str++);
+ return str;
+}
+static char* skip_word(char *str)
+{
+ for (; *str && (*str != ' ' && *str != '='); str++);
+ return str;
+}
+
+static struct conf_sect_t *find_sect(const char *name)
+{
+ struct sect_t *s;
+ list_for_each_entry(s, &sections, entry)
+ if (strcmp(s->sect->name, name) == 0) return s->sect;
+ return NULL;
+}
+
+static struct conf_sect_t *create_sect(const char *name)
+{
+ struct sect_t *s = _malloc(sizeof(struct sect_t));
+
+ s->sect = _malloc(sizeof(struct conf_sect_t));
+ s->sect->name = (char*)_strdup(name);
+ INIT_LIST_HEAD(&s->sect->items);
+
+ list_add_tail(&s->entry, &sections);
+
+ return s->sect;
+}
+
+static void sect_add_item(struct conf_sect_t *sect, const char *name, const char *val)
+{
+ struct conf_option_t *opt = _malloc(sizeof(struct conf_option_t));
+
+ opt->name = _strdup(name);
+ opt->val = val ? _strdup(val) : NULL;
+
+ list_add_tail(&opt->entry, &sect->items);
+}
+
+static struct conf_option_t *find_item(struct conf_sect_t *sect, const char *name)
+{
+ struct conf_option_t *opt;
+ list_for_each_entry(opt, &sect->items, entry) {
+ if (strcmp(opt->name, name) == 0)
+ return opt;
+ }
+
+ return NULL;
+}
+
+__export struct conf_sect_t * conf_get_section(const char *name)
+{
+ return find_sect(name);
+}
+
+__export char * conf_get_opt(const char *sect, const char *name)
+{
+ struct conf_option_t *opt;
+ struct conf_sect_t *s = conf_get_section(sect);
+
+ if (!s)
+ return NULL;
+
+ opt = find_item(s, name);
+ if (!opt)
+ return NULL;
+
+ return opt->val;
+}
+
diff --git a/accel-pppd/triton/event.c b/accel-pppd/triton/event.c
new file mode 100644
index 00000000..d45eca01
--- /dev/null
+++ b/accel-pppd/triton/event.c
@@ -0,0 +1,105 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+static int max_events = 1024;
+static struct _triton_event_t **events;
+
+struct event_handler_t
+{
+ struct list_head entry;
+ triton_event_func func;
+};
+
+int event_init(void)
+{
+ events = malloc(max_events * sizeof(void *));
+ if (!events) {
+ fprintf(stderr,"event:cann't allocate memory\n");
+ return -1;
+ }
+
+ memset(events, 0, max_events * sizeof(void *));
+
+ return 0;
+}
+
+int __export triton_event_register_handler(int ev_id, triton_event_func func)
+{
+ struct _triton_event_t *ev;
+ struct event_handler_t *h;
+
+ if (ev_id >= max_events)
+ return -1;
+
+ ev = events[ev_id];
+ if (!ev) {
+ ev = malloc(sizeof(*ev));
+ if (!ev) {
+ triton_log_error("event: out of memory\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&ev->handlers);
+ events[ev_id] = ev;
+ }
+
+ h = malloc(sizeof(*h));
+ if (!h) {
+ triton_log_error("event: out of memory\n");
+ return -1;
+ }
+
+ h->func = func;
+ list_add_tail(&h->entry, &ev->handlers);
+
+ return 0;
+}
+
+/*int triton_event_unregister_handler(int ev_id, triton_event_func func)
+{
+ struct _triton_event_t *ev;
+ struct event_handler_t *h;
+
+ if (ev_id >= max_events)
+ return -1;
+
+ ev = events[ev_id];
+ if (!ev) {
+ return -1;
+ }
+
+ list_for_each_entry(h, &ev->handlers, entry) {
+ if (h->func == func) {
+ if (ev->in_progress)
+ h->func = NULL;
+ else {
+ list_del(&h->entry);
+ _free(h);
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}*/
+
+void __export triton_event_fire(int ev_id, void *arg)
+{
+ struct _triton_event_t *ev;
+ struct event_handler_t *h;
+
+ if (ev_id >= max_events)
+ return;
+
+ ev = events[ev_id];
+ if (!ev)
+ return;
+
+ list_for_each_entry(h, &ev->handlers, entry)
+ h->func(arg);
+}
+
diff --git a/accel-pppd/triton/list.h b/accel-pppd/triton/list.h
new file mode 100644
index 00000000..d95dd714
--- /dev/null
+++ b/accel-pppd/triton/list.h
@@ -0,0 +1,249 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE)
+
+//#include <linux/prefetch.h>
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+typedef struct list_head {
+ struct list_head *next, *prev;
+} list_t;
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+
+static void inline prefetch(void *p){}
+
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = (void *) 0;
+ entry->prev = (void *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+//#endif /* __KERNEL__ || _LVM_H_INCLUDE */
+
+#endif
diff --git a/accel-pppd/triton/loader.c b/accel-pppd/triton/loader.c
new file mode 100644
index 00000000..2a2a2e2f
--- /dev/null
+++ b/accel-pppd/triton/loader.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+int load_modules(const char *name)
+{
+ struct conf_sect_t *sect;
+ struct conf_option_t *opt;
+ char *fname;
+ char *path = MODULE_PATH;
+
+ sect = conf_get_section(name);
+ if (!sect) {
+ fprintf(stderr, "loader: section '%s' not found\n", name);
+ return -1;
+ }
+
+ fname = _malloc(PATH_MAX);
+
+ list_for_each_entry(opt, &sect->items, entry) {
+ if (!strcmp(opt->name,"path") && opt->val) {
+ path = opt->val;
+ continue;
+ }
+
+ strcpy(fname, path);
+ strcat(fname, "/");
+ strcat(fname, opt->name);
+ if (access(fname, F_OK)) {
+ strcpy(fname, path);
+ strcat(fname, "/lib");
+ strcat(fname, opt->name);
+ strcat(fname, ".so");
+ if (access(fname, F_OK)) {
+ strcpy(fname, opt->name);
+ if (access(opt->name, F_OK)) {
+ triton_log_error("loader: '%s' not found\n", opt->name);
+ continue;
+ }
+ }
+ }
+
+ if (!dlopen(fname, RTLD_LAZY | RTLD_GLOBAL)) {
+ triton_log_error("loader: failed to load '%s': %s\n", opt->name, dlerror());
+ _free(fname);
+ return -1;
+ }
+ }
+
+ _free(fname);
+
+ return 0;
+}
+
diff --git a/accel-pppd/triton/log.c b/accel-pppd/triton/log.c
new file mode 100644
index 00000000..c7e6b7fe
--- /dev/null
+++ b/accel-pppd/triton/log.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+static FILE *f_error;
+static FILE *f_debug;
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+int log_init(void)
+{
+ char *log_error = conf_get_opt("core","log-error");
+ char *log_debug = conf_get_opt("core","log-debug");
+
+ if (log_error) {
+ f_error = fopen(log_error, "a");
+ if (!f_error) {
+ perror("log:log_error:open");
+ return -1;
+ }
+ }
+ if (log_debug) {
+ f_debug = fopen(log_debug, "a");
+ if (!f_debug) {
+ perror("log:log_debug:open");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void do_log(FILE *f, const char *fmt, va_list ap)
+{
+ struct timeval tv;
+ struct tm tm;
+ char date[64];
+
+ gettimeofday(&tv, NULL);
+ localtime_r(&tv.tv_sec, &tm);
+ strftime(date, sizeof(date), "%F %H:%M:%S", &tm);
+
+ pthread_mutex_lock(&lock);
+ fprintf(f, "[%s.%i]", date, (int)tv.tv_usec / 1000);
+ vfprintf(f, fmt,ap);
+ pthread_mutex_unlock(&lock);
+
+ fflush(f);
+}
+void triton_log_error(const char *fmt,...)
+{
+ va_list ap;
+
+ if (!f_error)
+ return;
+
+ va_start(ap, fmt);
+ do_log(f_error, fmt, ap);
+}
+
+void triton_log_debug(const char *fmt,...)
+{
+ va_list ap;
+
+ if (!f_debug)
+ return;
+
+ va_start(ap, fmt);
+ do_log(f_debug, fmt, ap);
+}
+
diff --git a/accel-pppd/triton/md.c b/accel-pppd/triton/md.c
new file mode 100644
index 00000000..84073d05
--- /dev/null
+++ b/accel-pppd/triton/md.c
@@ -0,0 +1,216 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+extern int max_events;
+
+static int epoll_fd;
+static struct epoll_event *epoll_events;
+
+static pthread_t md_thr;
+static void *md_thread(void *arg);
+
+static mempool_t *md_pool;
+
+static pthread_mutex_t freed_list_lock = PTHREAD_MUTEX_INITIALIZER;
+static LIST_HEAD(freed_list);
+static LIST_HEAD(freed_list2);
+
+int md_init(void)
+{
+ epoll_fd = epoll_create(1);
+ if (epoll_fd < 0) {
+ perror("md:epoll_create");
+ return -1;
+ }
+
+ epoll_events = _malloc(max_events * sizeof(struct epoll_event));
+ if (!epoll_events) {
+ fprintf(stderr,"md:cann't allocate memory\n");
+ return -1;
+ }
+
+ md_pool = mempool_create(sizeof(struct _triton_md_handler_t));
+
+ return 0;
+}
+void md_run(void)
+{
+ if (pthread_create(&md_thr, NULL, md_thread, NULL)) {
+ triton_log_error("md:pthread_create: %s", strerror(errno));
+ _exit(-1);
+ }
+}
+
+void md_terminate(void)
+{
+ pthread_cancel(md_thr);
+ pthread_join(md_thr, NULL);
+}
+
+static void *md_thread(void *arg)
+{
+ int i,n,r;
+ struct _triton_md_handler_t *h;
+ 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("md:epoll_wait: %s\n", strerror(errno));
+ _exit(-1);
+ }
+
+ for(i = 0; i < n; i++) {
+ h = (struct _triton_md_handler_t *)epoll_events[i].data.ptr;
+ if (!h->ud)
+ continue;
+ spin_lock(&h->ctx->lock);
+ if (h->ud) {
+ h->trig_epoll_events |= epoll_events[i].events;
+ if (!h->pending) {
+ list_add_tail(&h->entry2, &h->ctx->pending_handlers);
+ h->pending = 1;
+ __sync_add_and_fetch(&triton_stat.md_handler_pending, 1);
+ r = triton_queue_ctx(h->ctx);
+ } else
+ r = 0;
+ } else
+ r = 0;
+ spin_unlock(&h->ctx->lock);
+ if (r)
+ triton_thread_wakeup(h->ctx->thread);
+ }
+
+ while (!list_empty(&freed_list2)) {
+ h = list_entry(freed_list2.next, typeof(*h), entry);
+ list_del(&h->entry);
+ mempool_free(h);
+ }
+
+ pthread_mutex_lock(&freed_list_lock);
+ while (!list_empty(&freed_list)) {
+ h = list_entry(freed_list.next, typeof(*h), entry);
+ list_del(&h->entry);
+ list_add(&h->entry, &freed_list2);
+ }
+ pthread_mutex_unlock(&freed_list_lock);
+ }
+
+ return NULL;
+}
+
+void __export triton_md_register_handler(struct triton_context_t *ctx, struct triton_md_handler_t *ud)
+{
+ struct _triton_md_handler_t *h = mempool_alloc(md_pool);
+ memset(h, 0, sizeof(*h));
+ h->ud = ud;
+ h->epoll_event.data.ptr = h;
+ if (ctx)
+ h->ctx = (struct _triton_context_t *)ctx->tpd;
+ else
+ h->ctx = (struct _triton_context_t *)default_ctx.tpd;
+ ud->tpd = h;
+ spin_lock(&h->ctx->lock);
+ list_add_tail(&h->entry, &h->ctx->handlers);
+ spin_unlock(&h->ctx->lock);
+
+ triton_stat.md_handler_count++;
+}
+void __export triton_md_unregister_handler(struct triton_md_handler_t *ud)
+{
+ struct _triton_md_handler_t *h = (struct _triton_md_handler_t *)ud->tpd;
+ triton_md_disable_handler(ud, MD_MODE_READ | MD_MODE_WRITE);
+
+ spin_lock(&h->ctx->lock);
+ h->ud = NULL;
+ list_del(&h->entry);
+ if (h->pending) {
+ list_del(&h->entry2);
+ __sync_sub_and_fetch(&triton_stat.md_handler_pending, 1);
+ }
+ spin_unlock(&h->ctx->lock);
+
+ sched_yield();
+
+ pthread_mutex_lock(&freed_list_lock);
+ list_add_tail(&h->entry, &freed_list);
+ pthread_mutex_unlock(&freed_list_lock);
+
+ triton_stat.md_handler_count--;
+}
+int __export triton_md_enable_handler(struct triton_md_handler_t *ud, int mode)
+{
+ struct _triton_md_handler_t *h = (struct _triton_md_handler_t *)ud->tpd;
+ int r;
+ int events = h->epoll_event.events;
+
+ if (mode & MD_MODE_READ)
+ h->epoll_event.events |= EPOLLIN;
+ if (mode & MD_MODE_WRITE)
+ h->epoll_event.events |= EPOLLOUT;
+
+ if (!h->trig_level)
+ h->epoll_event.events |= EPOLLET;
+
+ if (events)
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, h->ud->fd, &h->epoll_event);
+ else
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, h->ud->fd, &h->epoll_event);
+
+ if (r) {
+ triton_log_error("md:epoll_ctl: %s\n",strerror(errno));
+ abort();
+ }
+
+ return r;
+}
+int __export triton_md_disable_handler(struct triton_md_handler_t *ud,int mode)
+{
+ struct _triton_md_handler_t *h = (struct _triton_md_handler_t *)ud->tpd;
+ int r=0;
+
+ if (!h->epoll_event.events)
+ return -1;
+
+ if (mode & MD_MODE_READ)
+ h->epoll_event.events &= ~EPOLLIN;
+ if (mode & MD_MODE_WRITE)
+ h->epoll_event.events &= ~EPOLLOUT;
+
+ if (h->epoll_event.events & (EPOLLIN | EPOLLOUT))
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, h->ud->fd, &h->epoll_event);
+ else {
+ h->epoll_event.events = 0;
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, h->ud->fd, NULL);
+ }
+
+ if (r) {
+ triton_log_error("md:epoll_ctl: %s\n",strerror(errno));
+ abort();
+ }
+
+ return r;
+}
+
+void __export triton_md_set_trig(struct triton_md_handler_t *ud, int mode)
+{
+ struct _triton_md_handler_t *h = (struct _triton_md_handler_t *)ud->tpd;
+ h->trig_level = mode;
+}
+
diff --git a/accel-pppd/triton/mempool.c b/accel-pppd/triton/mempool.c
new file mode 100644
index 00000000..855e22e8
--- /dev/null
+++ b/accel-pppd/triton/mempool.c
@@ -0,0 +1,338 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/mman.h>
+
+#include "triton_p.h"
+
+#include "memdebug.h"
+
+#ifdef VALGRIND
+#include <valgrind/memcheck.h>
+#define DELAY 5
+#endif
+
+//#define MEMPOOL_DISABLE
+
+#define MAGIC1 0x2233445566778899llu
+
+struct _mempool_t
+{
+ struct list_head entry;
+ int size;
+ struct list_head items;
+#ifdef MEMDEBUG
+ struct list_head ditems;
+#endif
+ spinlock_t lock;
+ uint64_t magic;
+ int mmap:1;
+};
+
+struct _item_t
+{
+ struct list_head entry;
+#ifdef VALGRIND
+ time_t timestamp;
+#endif
+ struct _mempool_t *owner;
+#ifdef MEMDEBUG
+ const char *fname;
+ int line;
+#endif
+ uint64_t magic2;
+ uint64_t magic1;
+ char ptr[0];
+};
+
+static LIST_HEAD(pools);
+static spinlock_t pools_lock = SPINLOCK_INITIALIZER;
+
+mempool_t __export *mempool_create(int size)
+{
+ struct _mempool_t *p = _malloc(sizeof(*p));
+
+ memset(p, 0, sizeof(*p));
+ INIT_LIST_HEAD(&p->items);
+#ifdef MEMDEBUG
+ INIT_LIST_HEAD(&p->ditems);
+#endif
+ spinlock_init(&p->lock);
+ p->size = size;
+ p->magic = (uint64_t)random() * (uint64_t)random();
+
+ spin_lock(&pools_lock);
+ list_add_tail(&p->entry, &pools);
+ spin_unlock(&pools_lock);
+
+ return (mempool_t *)p;
+}
+
+mempool_t __export *mempool_create2(int size)
+{
+ struct _mempool_t *p = (struct _mempool_t *)mempool_create(size);
+
+ p->mmap = 1;
+
+ return (mempool_t *)p;
+}
+
+#ifndef MEMDEBUG
+void __export *mempool_alloc(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+
+ spin_lock(&p->lock);
+ if (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+ list_del(&it->entry);
+ spin_unlock(&p->lock);
+
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+
+ it->magic1 = MAGIC1;
+
+ return it->ptr;
+ }
+ spin_unlock(&p->lock);
+
+ if (p->mmap)
+ it = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
+ else
+ it = _malloc(size);
+
+ if (!it) {
+ triton_log_error("mempool: out of memory\n");
+ return NULL;
+ }
+ it->owner = p;
+ it->magic1 = MAGIC1;
+ it->magic2 = p->magic;
+ *(uint64_t*)(it->data + p->size) = it->magic2;
+
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size);
+
+ return it->ptr;
+}
+#endif
+
+void __export *mempool_alloc_md(mempool_t *pool, const char *fname, int line)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+ int i, n;
+
+ spin_lock(&p->lock);
+ if (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+ VALGRIND_MAKE_MEM_UNDEFINED(it->ptr, p->size);
+#endif
+ list_del(&it->entry);
+ list_add(&it->entry, &p->ditems);
+ spin_unlock(&p->lock);
+
+ it->fname = fname;
+ it->line = line;
+
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+
+ it->magic1 = MAGIC1;
+
+ return it->ptr;
+#ifdef VALGRIND
+ }
+#endif
+ }
+ spin_unlock(&p->lock);
+
+ if (p->mmap) {
+ n = (sysconf(_SC_PAGE_SIZE) - 1) / size + 1;
+ it = mmap(NULL, n * size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size * (n - 1));
+ __sync_add_and_fetch(&triton_stat.mempool_available, size * (n - 1));
+ spin_lock(&p->lock);
+ for (i = 0; i < n - 1; i++, it) {
+ it->owner = p;
+ it->magic2 = p->magic;
+ it->magic1 = MAGIC1;
+ *(uint64_t*)(it->ptr + p->size) = it->magic2;
+ list_add_tail(&it->entry,&p->items);
+#ifdef VALGRIND
+ it->timestamp = 0;
+ VALGRIND_MAKE_MEM_NOACCESS(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ it = (struct _item_t *)((char *)it + size);
+ }
+ spin_unlock(&p->lock);
+#ifdef VALGRIND
+ VALGRIND_MAKE_MEM_UNDEFINED(it, size);
+#endif
+ } else
+ it = md_malloc(size, fname, line);
+
+ if (!it) {
+ triton_log_error("mempool: out of memory\n");
+ return NULL;
+ }
+ it->owner = p;
+ it->magic2 = p->magic;
+ it->magic1 = MAGIC1;
+ it->fname = fname;
+ it->line = line;
+ *(uint64_t*)(it->ptr + p->size) = it->magic2;
+
+ spin_lock(&p->lock);
+ list_add(&it->entry, &p->ditems);
+ spin_unlock(&p->lock);
+
+ __sync_add_and_fetch(&triton_stat.mempool_allocated, size);
+
+ return it->ptr;
+}
+
+
+void __export mempool_free(void *ptr)
+{
+ struct _item_t *it = container_of(ptr, typeof(*it), ptr);
+ struct _mempool_t *p = it->owner;
+ uint32_t size = sizeof(*it) + it->owner->size + 8;
+
+#ifdef MEMDEBUG
+ if (it->magic1 != MAGIC1) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ if (it->magic2 != it->owner->magic) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ if (it->magic2 != *(uint64_t*)(it->ptr + it->owner->size)) {
+ triton_log_error("mempool: memory corruption detected");
+ abort();
+ }
+
+ it->magic1 = 0;
+#endif
+
+ spin_lock(&p->lock);
+#ifdef MEMDEBUG
+ list_del(&it->entry);
+#endif
+#ifndef MEMPOOL_DISABLE
+ list_add_tail(&it->entry,&it->owner->items);
+#endif
+#ifdef VALGRIND
+ time(&it->timestamp);
+ VALGRIND_MAKE_MEM_NOACCESS(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ spin_unlock(&p->lock);
+
+#ifdef MEMPOOL_DISABLE
+ if (it->owner->mmap)
+ munmap(it, size);
+ else
+ _free(it);
+#endif
+
+ __sync_add_and_fetch(&triton_stat.mempool_available, size);
+}
+
+void __export mempool_clean(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+ uint32_t size = sizeof(*it) + p->size + 8;
+
+ spin_lock(&p->lock);
+ while (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ list_del(&it->entry);
+ if (p->mmap)
+ munmap(it, size);
+ else
+ _free(it);
+ __sync_sub_and_fetch(&triton_stat.mempool_allocated, size);
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+#ifdef VALGRIND
+ } else
+ break;
+#endif
+ }
+ spin_unlock(&p->lock);
+}
+
+#ifdef MEMDEBUG
+void __export mempool_show(mempool_t *pool)
+{
+ struct _mempool_t *p = (struct _mempool_t *)pool;
+ struct _item_t *it;
+
+ spin_lock(&p->lock);
+ list_for_each_entry(it, &p->ditems, entry)
+ triton_log_error("%s:%i %p\n", it->fname, it->line, it->ptr);
+ spin_unlock(&p->lock);
+}
+#endif
+
+void sigclean(int num)
+{
+ struct _mempool_t *p;
+ struct _item_t *it;
+ uint32_t size;
+
+ triton_log_error("mempool: clean\n");
+
+ spin_lock(&pools_lock);
+ list_for_each_entry(p, &pools, entry) {
+ if (p->mmap)
+ continue;
+ size = sizeof(*it) + p->size + 8;
+ spin_lock(&p->lock);
+ while (!list_empty(&p->items)) {
+ it = list_entry(p->items.next, typeof(*it), entry);
+#ifdef VALGRIND
+ if (it->timestamp + DELAY < time(NULL)) {
+ VALGRIND_MAKE_MEM_DEFINED(&it->owner, size - sizeof(it->entry) - sizeof(it->timestamp));
+#endif
+ list_del(&it->entry);
+ _free(it);
+ __sync_sub_and_fetch(&triton_stat.mempool_allocated, size);
+ __sync_sub_and_fetch(&triton_stat.mempool_available, size);
+#ifdef VALGRIND
+ } else
+ break;
+#endif
+ }
+ spin_unlock(&p->lock);
+ }
+ spin_unlock(&pools_lock);
+}
+
+static void __init init(void)
+{
+ sigset_t set;
+ sigfillset(&set);
+
+ struct sigaction sa = {
+ .sa_handler = sigclean,
+ .sa_mask = set,
+ };
+
+ sigaction(35, &sa, NULL);
+}
+
diff --git a/accel-pppd/triton/mempool.h b/accel-pppd/triton/mempool.h
new file mode 100644
index 00000000..bdb3e712
--- /dev/null
+++ b/accel-pppd/triton/mempool.h
@@ -0,0 +1,26 @@
+#ifndef __TRITON_MEMPOOL_H
+#define __TRITON_MEMPOOL_H
+
+#include <stdint.h>
+
+struct mempool_stat_t
+{
+ uint32_t allocated;
+ uint32_t available;
+};
+
+typedef void * mempool_t;
+mempool_t *mempool_create(int size);
+mempool_t *mempool_create2(int size);
+void mempool_free(void*);
+struct mempool_stat_t mempool_get_stat(void);
+
+#ifdef MEMDEBUG
+void *mempool_alloc_md(mempool_t*, const char *fname, int line);
+#define mempool_alloc(pool) mempool_alloc_md(pool, __FILE__, __LINE__)
+#else
+void *mempool_alloc(mempool_t*);
+#endif
+
+#endif
+
diff --git a/accel-pppd/triton/options.c b/accel-pppd/triton/options.c
new file mode 100644
index 00000000..a5214e21
--- /dev/null
+++ b/accel-pppd/triton/options.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "triton_p.h"
+#include "conf_file.h"
+
+#include "memdebug.h"
+
+static struct conf_file_sect_t *sect=NULL;
+
+static const char* find_option(const char *name)
+{
+ struct option_t *opt;
+
+ if (!sect)
+ {
+ sect=conf_file_get_section("options");
+ if (!sect) return 0;
+ }
+
+ list_for_each_entry(opt,&sect->items,entry)
+ {
+ if (strcmp(opt->name,name)==0)
+ return opt->val;
+ }
+
+ return NULL;
+}
+int triton_get_int_option(const char *str)
+{
+ const char *val=find_option(str);
+ if (!val) return 0;
+
+ return atoi(val);
+}
+const char* triton_get_str_option(const char *str)
+{
+ const char *val=find_option(str);
+
+ return val;
+}
+double triton_get_double_option(const char *str)
+{
+ const char *val=find_option(str);
+ if (!val) return 0;
+
+ return atof(val);
+}
diff --git a/accel-pppd/triton/spinlock.h b/accel-pppd/triton/spinlock.h
new file mode 100644
index 00000000..bb8dcf44
--- /dev/null
+++ b/accel-pppd/triton/spinlock.h
@@ -0,0 +1,42 @@
+#ifndef __TRITON_SPINLOCK_H
+#define __TRITON_SPINLOCK_H
+
+#if defined(FUTEX_SPINLOCK)
+
+/*#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/futex.h>
+typedef volatile int __attribute__((aligned)) spinlock_t;
+static inline void _spin_lock(spinlock_t *l)
+{
+ syscall(SYS_futex, l, FUTEX_WAIT, r, NULL, NULL, 0);
+}
+static inline void _spin_unlock(spinlock_t *l)
+{
+ syscall(SYS_futex, l, FUTEX_WAKE, 2, NULL, NULL, 0);
+}
+#define spin_lock(l) _spin_lock(l)
+#define spin_unlock(l) _spin_unlock(l)
+#define SPINLOCK_INITIALIZER 1
+#define spinlock_init(l) {*(l)=1;}*/
+
+#elif defined(GCC_SPINLOCK)
+
+typedef volatile int __attribute__((aligned)) spinlock_t;
+#define spin_lock(l) {while(__sync_lock_test_and_set(l,1));}
+#define spin_unlock(l) __sync_lock_release(l)
+#define SPINLOCK_INITIALIZER 0
+#define spinlock_init(l) {*(l)=0;}
+
+#else
+
+#include <pthread.h>
+typedef pthread_mutex_t spinlock_t;
+#define spin_lock(l) pthread_mutex_lock(l)
+#define spin_unlock(l) pthread_mutex_unlock(l)
+#define SPINLOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define spinlock_init(l) pthread_mutex_init(l,NULL)
+#endif
+
+#endif
+
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--;
+}
+
diff --git a/accel-pppd/triton/timerfd.c b/accel-pppd/triton/timerfd.c
new file mode 100644
index 00000000..b026258f
--- /dev/null
+++ b/accel-pppd/triton/timerfd.c
@@ -0,0 +1,19 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "timerfd.h"
+
+int timerfd_create (clockid_t __clock_id, int __flags)
+{
+ return syscall(SYS_timerfd_create, __clock_id, __flags);
+}
+
+
+int timerfd_settime (int __ufd, int __flags,
+ __const struct itimerspec *__utmr,
+ struct itimerspec *__otmr)
+{
+ return syscall(SYS_timerfd_settime, __ufd, __flags, __utmr, __otmr);
+}
+
diff --git a/accel-pppd/triton/timerfd.h b/accel-pppd/triton/timerfd.h
new file mode 100644
index 00000000..c1bb06f5
--- /dev/null
+++ b/accel-pppd/triton/timerfd.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_TIMERFD_H
+#define _SYS_TIMERFD_H 1
+
+#include <time.h>
+
+
+/* Bits to be set in the FLAGS parameter of `timerfd_create'. */
+enum
+ {
+ TFD_CLOEXEC = 02000000,
+#define TFD_CLOEXEC TFD_CLOEXEC
+ TFD_NONBLOCK = 04000
+#define TFD_NONBLOCK TFD_NONBLOCK
+ };
+
+
+/* Bits to be set in the FLAGS parameter of `timerfd_settime'. */
+enum
+ {
+ TFD_TIMER_ABSTIME = 1 << 0
+#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME
+ };
+
+
+__BEGIN_DECLS
+
+/* Return file descriptor for new interval timer source. */
+extern int timerfd_create (clockid_t __clock_id, int __flags) __THROW;
+
+/* Set next expiration time of interval timer source UFD to UTMR. If
+ FLAGS has the TFD_TIMER_ABSTIME flag set the timeout value is
+ absolute. Optionally return the old expiration time in OTMR. */
+extern int timerfd_settime (int __ufd, int __flags,
+ __const struct itimerspec *__utmr,
+ struct itimerspec *__otmr) __THROW;
+
+/* Return the next expiration time of UFD. */
+extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW;
+
+__END_DECLS
+
+#endif /* sys/timerfd.h */
diff --git a/accel-pppd/triton/triton.c b/accel-pppd/triton/triton.c
new file mode 100644
index 00000000..00dfcf6e
--- /dev/null
+++ b/accel-pppd/triton/triton.c
@@ -0,0 +1,610 @@
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include "triton_p.h"
+#include "memdebug.h"
+
+int thread_count = 2;
+int max_events = 64;
+
+static spinlock_t threads_lock = SPINLOCK_INITIALIZER;
+static LIST_HEAD(threads);
+static LIST_HEAD(sleep_threads);
+
+static LIST_HEAD(ctx_queue);
+
+static spinlock_t ctx_list_lock = SPINLOCK_INITIALIZER;
+static LIST_HEAD(ctx_list);
+
+static int terminate;
+static int need_terminate;
+
+static int need_config_reload;
+static void (*config_reload_notify)(int);
+
+static mempool_t *ctx_pool;
+static mempool_t *call_pool;
+
+struct triton_stat_t __export triton_stat;
+
+static struct timeval ru_utime;
+static struct timeval ru_stime;
+static struct timespec ru_timestamp;
+static int ru_refs;
+static void ru_update(struct triton_timer_t *);
+static struct triton_timer_t ru_timer = {
+ .period = 1000,
+ .expire = ru_update,
+};
+struct triton_context_t default_ctx;
+
+static struct triton_context_t __thread *this_ctx;
+
+#define log_debug2(fmt, ...)
+
+void triton_thread_wakeup(struct _triton_thread_t *thread)
+{
+ log_debug2("wake up thread %p\n", thread);
+ pthread_kill(thread->thread, SIGUSR1);
+}
+
+static void __config_reload(void (*notify)(int))
+{
+ struct _triton_thread_t *t;
+ int r;
+
+ log_debug2("config_reload: enter\n");
+ r = conf_reload(NULL);
+ notify(r);
+
+ spin_lock(&threads_lock);
+ need_config_reload = 0;
+ list_for_each_entry(t, &threads, entry)
+ triton_thread_wakeup(t);
+ spin_unlock(&threads_lock);
+ log_debug2("config_reload: exit\n");
+}
+
+static void ctx_thread(struct _triton_context_t *ctx);
+static void* triton_thread(struct _triton_thread_t *thread)
+{
+ sigset_t set;
+ int sig;
+
+ sigfillset(&set);
+ sigdelset(&set, SIGKILL);
+ sigdelset(&set, SIGSTOP);
+ pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ sigaddset(&set, SIGQUIT);
+
+ pthread_mutex_lock(&thread->sleep_lock);
+ pthread_mutex_unlock(&thread->sleep_lock);
+
+ while (1) {
+ spin_lock(&threads_lock);
+ if (!list_empty(&ctx_queue) && !need_config_reload) {
+ thread->ctx = list_entry(ctx_queue.next, typeof(*thread->ctx), entry2);
+ log_debug2("thread: %p: dequeued ctx %p\n", thread, thread->ctx);
+ list_del(&thread->ctx->entry2);
+ spin_unlock(&threads_lock);
+ spin_lock(&thread->ctx->lock);
+ thread->ctx->thread = thread;
+ thread->ctx->queued = 0;
+ spin_unlock(&thread->ctx->lock);
+ __sync_sub_and_fetch(&triton_stat.context_pending, 1);
+ } else {
+ if (triton_stat.thread_count > thread_count + triton_stat.context_sleeping) {
+ __sync_sub_and_fetch(&triton_stat.thread_active, 1);
+ __sync_sub_and_fetch(&triton_stat.thread_count, 1);
+ list_del(&thread->entry);
+ spin_unlock(&threads_lock);
+ pthread_detach(pthread_self());
+ log_debug2("thread: %p: exit\n", thread);
+ _free(thread);
+ return NULL;
+ }
+ log_debug2("thread: %p: sleeping\n", thread);
+ if (!terminate)
+ list_add(&thread->entry2, &sleep_threads);
+
+ if (__sync_sub_and_fetch(&triton_stat.thread_active, 1) == 0 && need_config_reload) {
+ spin_unlock(&threads_lock);
+ __config_reload(config_reload_notify);
+ } else
+ spin_unlock(&threads_lock);
+
+ if (terminate)
+ return NULL;
+
+ //printf("thread %p: enter sigwait\n", thread);
+ sigwait(&set, &sig);
+ //printf("thread %p: exit sigwait\n", thread);
+
+ spin_lock(&threads_lock);
+ __sync_add_and_fetch(&triton_stat.thread_active, 1);
+ if (!thread->ctx) {
+ list_del(&thread->entry2);
+ spin_unlock(&threads_lock);
+ continue;
+ }
+ spin_unlock(&threads_lock);
+ }
+
+cont:
+ log_debug2("thread %p: ctx=%p %p\n", thread, thread->ctx, thread->ctx ? thread->ctx->thread : NULL);
+ this_ctx = thread->ctx->ud;
+ if (thread->ctx->ud->before_switch)
+ thread->ctx->ud->before_switch(thread->ctx->ud, thread->ctx->bf_arg);
+
+ log_debug2("thread %p: switch to %p\n", thread, thread->ctx);
+ ctx_thread(thread->ctx);
+ log_debug2("thread %p: switch from %p %p\n", thread, thread->ctx, thread->ctx->thread);
+
+ spin_lock(&thread->ctx->lock);
+ if (thread->ctx->pending) {
+ spin_unlock(&thread->ctx->lock);
+ goto cont;
+ }
+ thread->ctx->thread = NULL;
+ spin_unlock(&thread->ctx->lock);
+
+ if (thread->ctx->need_free) {
+ log_debug2("- context %p removed\n", thread->ctx);
+ mempool_free(thread->ctx);
+ }
+
+ thread->ctx = NULL;
+ }
+}
+
+static void ctx_thread(struct _triton_context_t *ctx)
+{
+ struct _triton_md_handler_t *h;
+ struct _triton_timer_t *t;
+ struct _triton_ctx_call_t *call;
+ uint64_t tt;
+
+ log_debug2("ctx %p %p: enter\n", ctx, ctx->thread);
+ if (ctx->need_close) {
+ if (ctx->ud->close)
+ ctx->ud->close(ctx->ud);
+ ctx->need_close = 0;
+ }
+
+ while (1) {
+ spin_lock(&ctx->lock);
+ if (!list_empty(&ctx->pending_timers)) {
+ t = list_entry(ctx->pending_timers.next, typeof(*t), entry2);
+ list_del(&t->entry2);
+ t->pending = 0;
+ spin_unlock(&ctx->lock);
+ __sync_sub_and_fetch(&triton_stat.timer_pending, 1);
+ read(t->fd, &tt, sizeof(tt));
+ t->ud->expire(t->ud);
+ continue;
+ }
+ if (!list_empty(&ctx->pending_handlers)) {
+ h = list_entry(ctx->pending_handlers.next, typeof(*h), entry2);
+ list_del(&h->entry2);
+ h->pending = 0;
+ spin_unlock(&ctx->lock);
+ __sync_sub_and_fetch(&triton_stat.md_handler_pending, 1);
+ if (h->trig_epoll_events & (EPOLLIN | EPOLLERR | EPOLLHUP))
+ if (h->ud && h->ud->read)
+ if (h->ud->read(h->ud))
+ continue;
+ if (h->trig_epoll_events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
+ if (h->ud && h->ud->write)
+ if (h->ud->write(h->ud))
+ continue;
+ h->trig_epoll_events = 0;
+ continue;
+ }
+ if (!list_empty(&ctx->pending_calls)) {
+ call = list_entry(ctx->pending_calls.next, typeof(*call), entry);
+ list_del(&call->entry);
+ spin_unlock(&ctx->lock);
+ call->func(call->arg);
+ mempool_free(call);
+ continue;
+ }
+ ctx->pending = 0;
+ spin_unlock(&ctx->lock);
+ break;
+ }
+
+ log_debug2("ctx %p %p: exit\n", ctx, ctx->thread);
+}
+
+struct _triton_thread_t *create_thread()
+{
+ struct _triton_thread_t *thread = _malloc(sizeof(*thread));
+ if (!thread)
+ return NULL;
+
+ memset(thread, 0, sizeof(*thread));
+ pthread_mutex_init(&thread->sleep_lock, NULL);
+ pthread_cond_init(&thread->sleep_cond, NULL);
+ pthread_mutex_lock(&thread->sleep_lock);
+ if (pthread_create(&thread->thread, NULL, (void*(*)(void*))triton_thread, thread)) {
+ triton_log_error("pthread_create: %s", strerror(errno));
+ return NULL;
+ }
+
+ __sync_add_and_fetch(&triton_stat.thread_count, 1);
+ __sync_add_and_fetch(&triton_stat.thread_active, 1);
+
+ return thread;
+}
+
+int triton_queue_ctx(struct _triton_context_t *ctx)
+{
+ ctx->pending = 1;
+ if (ctx->thread || ctx->queued || ctx->init)
+ return 0;
+
+ spin_lock(&threads_lock);
+ if (list_empty(&sleep_threads) || need_config_reload) {
+ if (ctx->priority)
+ list_add(&ctx->entry2, &ctx_queue);
+ else
+ list_add_tail(&ctx->entry2, &ctx_queue);
+ spin_unlock(&threads_lock);
+ ctx->queued = 1;
+ log_debug2("ctx %p: queued\n", ctx);
+ __sync_add_and_fetch(&triton_stat.context_pending, 1);
+ return 0;
+ }
+
+ ctx->thread = list_entry(sleep_threads.next, typeof(*ctx->thread), entry2);
+ ctx->thread->ctx = ctx;
+ log_debug2("ctx %p: assigned to thread %p\n", ctx, ctx->thread);
+ list_del(&ctx->thread->entry2);
+ spin_unlock(&threads_lock);
+
+ return 1;
+}
+
+int __export triton_context_register(struct triton_context_t *ud, void *bf_arg)
+{
+ struct _triton_context_t *ctx = mempool_alloc(ctx_pool);
+
+ log_debug2("ctx %p: register\n", ctx);
+ if (!ctx)
+ return -1;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->ud = ud;
+ ctx->bf_arg = bf_arg;
+ ctx->init = 1;
+ spinlock_init(&ctx->lock);
+ INIT_LIST_HEAD(&ctx->handlers);
+ INIT_LIST_HEAD(&ctx->timers);
+ INIT_LIST_HEAD(&ctx->pending_handlers);
+ INIT_LIST_HEAD(&ctx->pending_timers);
+ INIT_LIST_HEAD(&ctx->pending_calls);
+
+ ud->tpd = ctx;
+
+ spin_lock(&ctx_list_lock);
+ list_add_tail(&ctx->entry, &ctx_list);
+ spin_unlock(&ctx_list_lock);
+
+ __sync_add_and_fetch(&triton_stat.context_sleeping, 1);
+ __sync_add_and_fetch(&triton_stat.context_count, 1);
+
+ return 0;
+}
+
+void __export triton_context_unregister(struct triton_context_t *ud)
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd;
+ struct _triton_ctx_call_t *call;
+ struct _triton_thread_t *t;
+
+ log_debug2("ctx %p: unregister\n", ctx);
+
+ while (!list_empty(&ctx->pending_calls)) {
+ call = list_entry(ctx->pending_calls.next, typeof(*call), entry);
+ list_del(&call->entry);
+ mempool_free(call);
+ }
+
+ if (!list_empty(&ctx->handlers)) {
+ triton_log_error("BUG:ctx:triton_unregister_ctx: handlers is not empty");
+ {
+ struct _triton_md_handler_t *h;
+ list_for_each_entry(h, &ctx->handlers, entry)
+ if (h->ud)
+ printf("%p\n", h->ud);
+ }
+ abort();
+ }
+ if (!list_empty(&ctx->pending_handlers)) {
+ triton_log_error("BUG:ctx:triton_unregister_ctx: pending_handlers is not empty");
+ abort();
+ }
+ if (!list_empty(&ctx->timers)) {
+ triton_log_error("BUG:ctx:triton_unregister_ctx: timers is not empty");
+ abort();
+ }
+ if (!list_empty(&ctx->pending_timers)) {
+ triton_log_error("BUG:ctx:triton_unregister_ctx: pending_timers is not empty");
+ abort();
+ }
+
+ ctx->need_free = 1;
+ spin_lock(&ctx_list_lock);
+ list_del(&ctx->entry);
+ if (__sync_sub_and_fetch(&triton_stat.context_count, 1) == 1) {
+ if (need_terminate)
+ terminate = 1;
+ }
+ spin_unlock(&ctx_list_lock);
+
+ if (terminate) {
+ list_for_each_entry(t, &threads, entry)
+ triton_thread_wakeup(t);
+ }
+}
+
+void __export triton_context_set_priority(struct triton_context_t *ud, int prio)
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd;
+
+ ctx->priority = prio > 0;
+}
+
+void __export triton_context_schedule()
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)this_ctx->tpd;
+ struct _triton_thread_t *t = NULL;
+
+ log_debug2("ctx %p: enter schedule\n", ctx);
+ __sync_add_and_fetch(&triton_stat.context_sleeping, 1);
+ __sync_sub_and_fetch(&triton_stat.thread_active, 1);
+ pthread_mutex_lock(&ctx->thread->sleep_lock);
+ while (1) {
+ if (ctx->wakeup) {
+ ctx->wakeup = 0;
+ break;
+ } else {
+ if (!t && triton_stat.thread_count <= thread_count + triton_stat.context_sleeping) {
+ t = create_thread();
+ spin_lock(&threads_lock);
+ list_add_tail(&t->entry, &threads);
+ spin_unlock(&threads_lock);
+ pthread_mutex_unlock(&t->sleep_lock);
+ }
+ pthread_cond_wait(&ctx->thread->sleep_cond, &ctx->thread->sleep_lock);
+ }
+ }
+ pthread_mutex_unlock(&ctx->thread->sleep_lock);
+ __sync_sub_and_fetch(&triton_stat.context_sleeping, 1);
+ __sync_add_and_fetch(&triton_stat.thread_active, 1);
+ log_debug2("ctx %p: exit schedule\n", ctx);
+}
+
+struct triton_context_t __export *triton_context_self(void)
+{
+ return this_ctx;
+}
+
+void triton_context_print(void)
+{
+ struct _triton_context_t *ctx;
+
+ list_for_each_entry(ctx, &ctx_list, entry)
+ printf("%p\n", ctx);
+}
+
+void __export triton_context_wakeup(struct triton_context_t *ud)
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd;
+ int r = 0;
+
+ log_debug2("ctx %p: wakeup\n", ctx);
+
+ if (ctx->init) {
+ __sync_sub_and_fetch(&triton_stat.context_sleeping, 1);
+ spin_lock(&ctx->lock);
+ ctx->init = 0;
+ if (ctx->pending)
+ r = triton_queue_ctx(ctx);
+ spin_unlock(&ctx->lock);
+ if (r)
+ triton_thread_wakeup(ctx->thread);
+ return;
+ }
+
+ pthread_mutex_lock(&ctx->thread->sleep_lock);
+ ctx->wakeup = 1;
+ pthread_cond_signal(&ctx->thread->sleep_cond);
+ pthread_mutex_unlock(&ctx->thread->sleep_lock);
+}
+
+int __export triton_context_call(struct triton_context_t *ud, void (*func)(void *), void *arg)
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd;
+ struct _triton_ctx_call_t *call = mempool_alloc(call_pool);
+ int r;
+
+ if (!call)
+ return -1;
+
+ call->func = func;
+ call->arg = arg;
+
+ spin_lock(&ctx->lock);
+ list_add_tail(&call->entry, &ctx->pending_calls);
+ r = triton_queue_ctx(ctx);
+ spin_unlock(&ctx->lock);
+
+ if (r)
+ triton_thread_wakeup(ctx->thread);
+
+ return 0;
+}
+
+void __export triton_cancel_call(struct triton_context_t *ud, void (*func)(void *))
+{
+ struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd;
+ struct list_head *pos, *n;
+ struct _triton_ctx_call_t *call;
+
+ list_for_each_safe(pos, n, &ctx->pending_calls) {
+ call = list_entry(pos, typeof(*call), entry);
+ if (call->func != func)
+ continue;
+ list_del(&call->entry);
+ mempool_free(call);
+ }
+}
+
+void __export triton_collect_cpu_usage(void)
+{
+ struct rusage rusage;
+
+ if (__sync_fetch_and_add(&ru_refs, 1) == 0) {
+ triton_timer_add(NULL, &ru_timer, 0);
+ getrusage(RUSAGE_SELF, &rusage);
+ clock_gettime(CLOCK_MONOTONIC, &ru_timestamp);
+ ru_utime = rusage.ru_utime;
+ ru_stime = rusage.ru_stime;
+ triton_stat.cpu = 0;
+ }
+}
+
+void __export triton_stop_collect_cpu_usage(void)
+{
+ if (__sync_sub_and_fetch(&ru_refs, 1) == 0)
+ triton_timer_del(&ru_timer);
+}
+
+static void ru_update(struct triton_timer_t *t)
+{
+ struct timespec ts;
+ struct rusage rusage;
+ unsigned int dt;
+ unsigned int val;
+
+ getrusage(RUSAGE_SELF, &rusage);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ dt = (ts.tv_sec - ru_timestamp.tv_sec) * 1000000 + (ts.tv_nsec - ru_timestamp.tv_nsec) / 1000000;
+ val = (double)((rusage.ru_utime.tv_sec - ru_utime.tv_sec) * 1000000 + (rusage.ru_utime.tv_usec - ru_utime.tv_usec) +
+ (rusage.ru_stime.tv_sec - ru_stime.tv_sec) * 1000000 + (rusage.ru_stime.tv_usec - ru_stime.tv_usec)) / dt * 100;
+
+ if (val <= 100)
+ triton_stat.cpu = val;
+
+ ru_timestamp = ts;
+ ru_utime = rusage.ru_utime;
+ ru_stime = rusage.ru_stime;
+}
+
+int __export triton_init(const char *conf_file)
+{
+ ctx_pool = mempool_create2(sizeof(struct _triton_context_t));
+ call_pool = mempool_create(sizeof(struct _triton_ctx_call_t));
+
+ if (conf_load(conf_file))
+ return -1;
+
+ if (log_init())
+ return -1;
+
+ if (md_init())
+ return -1;
+
+ if (timer_init())
+ return -1;
+
+ if (event_init())
+ return -1;
+
+ return 0;
+}
+
+int __export triton_load_modules(const char *mod_sect)
+{
+ if (load_modules(mod_sect))
+ return -1;
+
+ return 0;
+}
+
+void __export triton_conf_reload(void (*notify)(int))
+{
+ spin_lock(&threads_lock);
+ need_config_reload = 1;
+ config_reload_notify = notify;
+ if (triton_stat.thread_active == 0) {
+ spin_unlock(&threads_lock);
+ __config_reload(notify);
+ } else
+ spin_unlock(&threads_lock);
+}
+
+void __export triton_run()
+{
+ struct _triton_thread_t *t;
+ int i;
+ char *opt;
+
+ opt = conf_get_opt("core", "thread-count");
+ if (opt && atoi(opt) > 0)
+ thread_count = atoi(opt);
+
+ for(i = 0; i < thread_count; i++) {
+ t = create_thread();
+ if (!t)
+ _exit(-1);
+
+ list_add_tail(&t->entry, &threads);
+ pthread_mutex_unlock(&t->sleep_lock);
+ }
+
+ time(&triton_stat.start_time);
+
+ md_run();
+ timer_run();
+
+ triton_context_register(&default_ctx, NULL);
+ triton_context_wakeup(&default_ctx);
+}
+
+void __export triton_terminate()
+{
+ struct _triton_context_t *ctx;
+ struct _triton_thread_t *t;
+ int r;
+
+ need_terminate = 1;
+
+ spin_lock(&ctx_list_lock);
+ list_for_each_entry(ctx, &ctx_list, entry) {
+ spin_lock(&ctx->lock);
+ ctx->need_close = 1;
+ r = triton_queue_ctx(ctx);
+ if (r)
+ triton_thread_wakeup(ctx->thread);
+ spin_unlock(&ctx->lock);
+ }
+ spin_unlock(&ctx_list_lock);
+
+ list_for_each_entry(t, &threads, entry)
+ pthread_join(t->thread, NULL);
+
+ md_terminate();
+ timer_terminate();
+}
+
diff --git a/accel-pppd/triton/triton.h b/accel-pppd/triton/triton.h
new file mode 100644
index 00000000..6866d523
--- /dev/null
+++ b/accel-pppd/triton/triton.h
@@ -0,0 +1,138 @@
+#ifndef TRITON_H
+#define TRITON_H
+
+#include <sys/time.h>
+#include <stdint.h>
+
+#include "list.h"
+
+struct triton_context_t
+{
+ const void *tpd; // triton private data, don't touch
+ void (*close)(struct triton_context_t*);
+ void (*free)(struct triton_context_t*);
+ void (*before_switch)(struct triton_context_t *ctx, void *arg);
+};
+
+struct triton_md_handler_t
+{
+ const void *tpd; // triton private data, don't touch!
+ int fd;
+ int (*read)(struct triton_md_handler_t *);
+ int (*write)(struct triton_md_handler_t *);
+};
+
+struct triton_timer_t
+{
+ const void *tpd; // triton private data, don't touch!
+ struct timeval expire_tv;
+ int period;
+ void (*expire)(struct triton_timer_t *);
+};
+
+struct triton_sigchld_handler_t
+{
+ void *tpd;
+ int pid;
+ void (*handler)(struct triton_sigchld_handler_t *h, int status);
+};
+
+struct conf_option_t
+{
+ struct list_head entry;
+ char *name;
+ char *val;
+};
+
+struct conf_sect_t
+{
+ const char *name;
+ struct list_head items;
+};
+
+struct triton_stat_t
+{
+ unsigned int mempool_allocated;
+ unsigned int mempool_available;
+ unsigned int thread_count;
+ unsigned int thread_active;
+ unsigned int context_count;
+ unsigned int context_sleeping;
+ unsigned int context_pending;
+ unsigned int md_handler_count;
+ unsigned int md_handler_pending;
+ unsigned int timer_count;
+ unsigned int timer_pending;
+ time_t start_time;
+ unsigned int cpu;
+};
+
+extern struct triton_stat_t triton_stat;
+int triton_context_register(struct triton_context_t *, void *arg);
+void triton_context_unregister(struct triton_context_t *);
+void triton_context_set_priority(struct triton_context_t *, int);
+void triton_context_schedule(void);
+void triton_context_wakeup(struct triton_context_t *);
+int triton_context_call(struct triton_context_t *, void (*func)(void *), void *arg);
+void triton_cancel_call(struct triton_context_t *, void (*func)(void *));
+struct triton_context_t *triton_context_self(void);
+
+#define MD_MODE_READ 1
+#define MD_MODE_WRITE 2
+
+#define MD_TRIG_EDGE 0
+#define MD_TRIG_LEVEL 1
+
+void triton_md_register_handler(struct triton_context_t *, struct triton_md_handler_t *);
+void triton_md_unregister_handler(struct triton_md_handler_t *h);
+int triton_md_enable_handler(struct triton_md_handler_t *h, int mode);
+int triton_md_disable_handler(struct triton_md_handler_t *h,int mode);
+void triton_md_set_trig(struct triton_md_handler_t *h, int mode);
+
+int triton_timer_add(struct triton_context_t *ctx, struct triton_timer_t*,int abs_time);
+int triton_timer_mod(struct triton_timer_t *,int abs_time);
+void triton_timer_del(struct triton_timer_t *);
+
+typedef void (*triton_event_func)(void *);
+int triton_event_register_handler(int ev_id, triton_event_func func);
+void triton_event_fire(int ev_id, void *arg);
+
+struct conf_sect_t *conf_get_section(const char *name);
+char *conf_get_opt(const char *sect, const char *name);
+void triton_conf_reload(void (*notify)(int));
+
+void triton_collect_cpu_usage(void);
+void triton_stop_collect_cpu_usage(void);
+
+
+#define TRITON_OK 0
+#define TRITON_ERR_NOCOMP -1
+#define TRITON_ERR_NOSUPP -2
+#define TRITON_ERR_NOINTF -3
+#define TRITON_ERR_EXISTS -4
+#define TRITON_ERR_NOCHAN -5
+#define TRITON_ERR_NOMSG -6
+#define TRITON_ERR_BUSY -5
+
+int triton_init(const char *conf_file);
+int triton_load_modules(const char *md_sect);
+void triton_run(void);
+void triton_terminate(void);
+
+
+#define __init __attribute__((constructor))
+#define __exit __attribute__((destructor))
+#define __export __attribute__((visibility("default")))
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif
diff --git a/accel-pppd/triton/triton_p.h b/accel-pppd/triton/triton_p.h
new file mode 100644
index 00000000..235eb701
--- /dev/null
+++ b/accel-pppd/triton/triton_p.h
@@ -0,0 +1,103 @@
+#ifndef TRITON_P_H
+#define TRITON_P_H
+
+#include <pthread.h>
+#include <sys/epoll.h>
+
+#include "triton.h"
+#include "list.h"
+#include "spinlock.h"
+#include "mempool.h"
+
+struct _triton_thread_t
+{
+ struct list_head entry;
+ struct list_head entry2;
+ pthread_t thread;
+ int terminate;
+ struct _triton_context_t *ctx;
+ pthread_mutex_t sleep_lock;
+ pthread_cond_t sleep_cond;
+};
+
+struct _triton_context_t
+{
+ struct list_head entry;
+ struct list_head entry2;
+
+ spinlock_t lock;
+ struct _triton_thread_t *thread;
+
+ struct list_head handlers;
+ struct list_head timers;
+ struct list_head pending_handlers;
+ struct list_head pending_timers;
+ struct list_head pending_calls;
+
+ int init;
+ int queued;
+ int wakeup;
+ int need_close;
+ int need_free;
+ int pending;
+ int priority;
+
+ struct triton_context_t *ud;
+ void *bf_arg;
+};
+
+struct _triton_md_handler_t
+{
+ struct list_head entry;
+ struct list_head entry2;
+ struct _triton_context_t *ctx;
+ struct epoll_event epoll_event;
+ uint32_t trig_epoll_events;
+ int pending:1;
+ int trig_level:1;
+ struct triton_md_handler_t *ud;
+};
+
+struct _triton_timer_t
+{
+ struct list_head entry;
+ struct list_head entry2;
+ struct epoll_event epoll_event;
+ struct _triton_context_t *ctx;
+ int fd;
+ int pending:1;
+ struct triton_timer_t *ud;
+};
+
+struct _triton_event_t
+{
+ struct list_head handlers;
+};
+
+struct _triton_ctx_call_t
+{
+ struct list_head entry;
+
+ void *arg;
+ void (*func)(void *);
+};
+
+int log_init(void);
+int md_init();
+int timer_init();
+int event_init();
+
+void md_run();
+void md_terminate();
+void timer_run();
+void timer_terminate();
+extern struct triton_context_t default_ctx;
+int triton_queue_ctx(struct _triton_context_t*);
+void triton_thread_wakeup(struct _triton_thread_t*);
+int conf_load(const char *fname);
+int conf_reload(const char *fname);
+void triton_log_error(const char *fmt,...);
+void triton_log_debug(const char *fmt,...);
+int load_modules(const char *name);
+
+#endif