diff options
author | Kozlov Dmitry <dima@server> | 2010-10-06 16:55:05 +0400 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-10-06 16:55:05 +0400 |
commit | 45b3c9c5bdd896f51f47e29069e3c030ddb17d51 (patch) | |
tree | cbec5824ffb2eee20b98ad9892a357304384ff01 /accel-pptpd/triton | |
parent | ba3db9f17477ea4b49c266c5cb50f63f3b074db2 (diff) | |
parent | 01ccd98495c9da1e79f7867bf52416b23f20200d (diff) | |
download | accel-ppp-45b3c9c5bdd896f51f47e29069e3c030ddb17d51.tar.gz accel-ppp-45b3c9c5bdd896f51f47e29069e3c030ddb17d51.zip |
merged branch accel-pptpd
Diffstat (limited to 'accel-pptpd/triton')
-rw-r--r-- | accel-pptpd/triton/CMakeLists.txt | 20 | ||||
-rw-r--r-- | accel-pptpd/triton/conf_file.c | 187 | ||||
-rw-r--r-- | accel-pptpd/triton/event.c | 105 | ||||
-rw-r--r-- | accel-pptpd/triton/list.h | 249 | ||||
-rw-r--r-- | accel-pptpd/triton/loader.c | 62 | ||||
-rw-r--r-- | accel-pptpd/triton/log.c | 73 | ||||
-rw-r--r-- | accel-pptpd/triton/md.c | 188 | ||||
-rw-r--r-- | accel-pptpd/triton/mempool.c | 179 | ||||
-rw-r--r-- | accel-pptpd/triton/mempool.h | 25 | ||||
-rw-r--r-- | accel-pptpd/triton/options.c | 48 | ||||
-rw-r--r-- | accel-pptpd/triton/spinlock.h | 20 | ||||
-rw-r--r-- | accel-pptpd/triton/timer.c | 181 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.c | 472 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.h | 127 | ||||
-rw-r--r-- | accel-pptpd/triton/triton_p.h | 105 |
15 files changed, 2041 insertions, 0 deletions
diff --git a/accel-pptpd/triton/CMakeLists.txt b/accel-pptpd/triton/CMakeLists.txt new file mode 100644 index 00000000..3e5e068a --- /dev/null +++ b/accel-pptpd/triton/CMakeLists.txt @@ -0,0 +1,20 @@ +SET(sources_c + md.c + timer.c + triton.c + conf_file.c + loader.c + log.c + mempool.c + event.c +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_DEFINITIONS(-DMODULE_PATH="${CMAKE_INSTALL_PREFIX}/usr/lib/accel-pptp") + +ADD_LIBRARY(triton SHARED ${sources_c}) + +INSTALL(TARGETS triton + LIBRARY DESTINATION usr/lib/accel-pptp +) diff --git a/accel-pptpd/triton/conf_file.c b/accel-pptpd/triton/conf_file.c new file mode 100644 index 00000000..6eb2e7a8 --- /dev/null +++ b/accel-pptpd/triton/conf_file.c @@ -0,0 +1,187 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include "triton_p.h" + +#include "memdebug.h" + +struct sect_t +{ + struct list_head entry; + + struct conf_sect_t *sect; +}; + +static LIST_HEAD(sections); + +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); + +int conf_load(const char *fname) +{ + char *buf,*str,*str2; + char *path0,*path; + int cur_line = 0; + static struct conf_sect_t *cur_sect = NULL; + + FILE *f = fopen(fname, "r"); + if (!f) { + perror("conf_file:open"); + return -1; + } + + buf = _malloc(1024); + path0 = _malloc(4096); + path = _malloc(4096); + + getcwd(path0, 1024); + + 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); + conf_load(str); + 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); + } + + _free(buf); + _free(path); + _free(path0); + fclose(f); + + return 0; +} + +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, §ions, 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, §ions); + + 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, §->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, §->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-pptpd/triton/event.c b/accel-pptpd/triton/event.c new file mode 100644 index 00000000..d45eca01 --- /dev/null +++ b/accel-pptpd/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-pptpd/triton/list.h b/accel-pptpd/triton/list.h new file mode 100644 index 00000000..d95dd714 --- /dev/null +++ b/accel-pptpd/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-pptpd/triton/loader.c b/accel-pptpd/triton/loader.c new file mode 100644 index 00000000..b6c1914e --- /dev/null +++ b/accel-pptpd/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, §->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_NOW | 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-pptpd/triton/log.c b/accel-pptpd/triton/log.c new file mode 100644 index 00000000..c7e6b7fe --- /dev/null +++ b/accel-pptpd/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-pptpd/triton/md.c b/accel-pptpd/triton/md.c new file mode 100644 index 00000000..444aebf0 --- /dev/null +++ b/accel-pptpd/triton/md.c @@ -0,0 +1,188 @@ +#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; + +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; + 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; + 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); + } + } + + 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); + + __sync_fetch_and_add(&triton_stat.md_handler_count, 1); +} +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); + list_del(&h->entry); + if (h->pending) + list_del(&h->entry2); + h->ud = NULL; + spin_unlock(&h->ctx->lock); + sched_yield(); + mempool_free(h); + + __sync_fetch_and_sub(&triton_stat.md_handler_count, 1); +} +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-pptpd/triton/mempool.c b/accel-pptpd/triton/mempool.c new file mode 100644 index 00000000..c96c3ba2 --- /dev/null +++ b/accel-pptpd/triton/mempool.c @@ -0,0 +1,179 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> + +#include "triton_p.h" + +#include "memdebug.h" + +#define MAGIC1 0x2233445566778899llu + +struct _mempool_t +{ + struct list_head entry; + int size; + struct list_head items; + spinlock_t lock; + uint64_t magic; +}; + +struct _item_t +{ + struct _mempool_t *owner; + struct list_head entry; + uint64_t magic2; + uint64_t magic1; + char ptr[0]; +}; + +static LIST_HEAD(pools); +static spinlock_t pools_lock = SPINLOCK_INITIALIZER; + +__export mempool_t *mempool_create(int size) +{ + struct _mempool_t *p = _malloc(sizeof(*p)); + + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->items); + 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; +} + +#ifndef MEMDEBUG +__export void *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_fetch_and_sub(&triton_stat.mempool_available, size); + + it->magic1 = MAGIC1; + + return it->ptr; + } + spin_unlock(&p->lock); + + 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_fetch_and_add(&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; + + 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_fetch_and_sub(&triton_stat.mempool_available, size); + + it->magic1 = MAGIC1; + + return it->ptr; + } + spin_unlock(&p->lock); + + 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; + *(uint64_t*)(it->ptr + p->size) = it->magic2; + + __sync_fetch_and_add(&triton_stat.mempool_allocated, size); + + return it->ptr; +} + + +__export void mempool_free(void *ptr) +{ + struct _item_t *it = container_of(ptr, typeof(*it), ptr); + uint32_t size = sizeof(*it) + it->owner->size + 8; + + 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; + + spin_lock(&it->owner->lock); + list_add_tail(&it->entry,&it->owner->items); + spin_unlock(&it->owner->lock); + + __sync_fetch_and_add(&triton_stat.mempool_available, size); +} + +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) { + size = sizeof(*it) + p->size; + spin_lock(&p->lock); + while (!list_empty(&p->items)) { + it = list_entry(p->items.next, typeof(*it), entry); + list_del(&it->entry); + _free(it); + __sync_fetch_and_sub(&triton_stat.mempool_allocated, size); + __sync_fetch_and_sub(&triton_stat.mempool_available, size); + } + spin_unlock(&p->lock); + } + spin_unlock(&pools_lock); +} + +static void __init init(void) +{ + signal(35, sigclean); +} diff --git a/accel-pptpd/triton/mempool.h b/accel-pptpd/triton/mempool.h new file mode 100644 index 00000000..d3539215 --- /dev/null +++ b/accel-pptpd/triton/mempool.h @@ -0,0 +1,25 @@ +#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); +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-pptpd/triton/options.c b/accel-pptpd/triton/options.c new file mode 100644 index 00000000..a5214e21 --- /dev/null +++ b/accel-pptpd/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,§->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-pptpd/triton/spinlock.h b/accel-pptpd/triton/spinlock.h new file mode 100644 index 00000000..b13cde61 --- /dev/null +++ b/accel-pptpd/triton/spinlock.h @@ -0,0 +1,20 @@ +#ifndef __TRITON_SPINLOCK_H +#define __TRITON_SPINLOCK_H + +#ifdef GCC_SPINLOCK +typedef volatile unsigned char 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-pptpd/triton/timer.c b/accel-pptpd/triton/timer.c new file mode 100644 index 00000000..cbf2b13d --- /dev/null +++ b/accel-pptpd/triton/timer.c @@ -0,0 +1,181 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/epoll.h> +#include <sys/timerfd.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 timer_thr; +static void *timer_thread(void *arg); + +static mempool_t *timer_pool; + +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; + spin_lock(&t->ctx->lock); + if (t->ud) { + if (!t->pending) { + list_add_tail(&t->entry2, &t->ctx->pending_timers); + t->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); + } + } + + 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(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (t->fd < 0) { + triton_log_error("timer:timerfd_create: %s" ,strerror(errno)); + mempool_free(t); + return -1; + } + + ud->tpd = t; + + if (triton_timer_mod(ud, abs_time)) { + close(t->fd); + mempool_free(t); + return -1; + } + + 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); + close(t->fd); + mempool_free(t); + ud->tpd = NULL; + return -1; + } + + __sync_fetch_and_add(&triton_stat.timer_count, 1); + + return 0; +} +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); + list_del(&t->entry); + if (t->pending) + list_del(&t->entry2); + t->ud = NULL; + spin_unlock(&t->ctx->lock); + sched_yield(); + mempool_free(t); + ud->tpd = NULL; + + __sync_fetch_and_sub(&triton_stat.timer_count, 1); +} + diff --git a/accel-pptpd/triton/triton.c b/accel-pptpd/triton/triton.c new file mode 100644 index 00000000..b2aaa7bb --- /dev/null +++ b/accel-pptpd/triton/triton.c @@ -0,0 +1,472 @@ +#include <signal.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.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 mempool_t *ctx_pool; +static mempool_t *call_pool; +static mempool_t *ctx_stack_pool; + +__export struct triton_stat_t triton_stat; + +void triton_thread_wakeup(struct _triton_thread_t *thread) +{ + //printf("wake up thread %p\n", thread); + pthread_kill(thread->thread, SIGUSR1); +} + +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); + + while (1) { + spin_lock(&threads_lock); + if (!list_empty(&ctx_queue)) { + thread->ctx = list_entry(ctx_queue.next, typeof(*thread->ctx), entry2); + //printf("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_fetch_and_sub(&triton_stat.context_pending, 1); + } else { + //printf("thread: %p: sleeping\n", thread); + if (!terminate) + list_add(&thread->entry2, &sleep_threads); + spin_unlock(&threads_lock); + if (terminate) + return NULL; + + __sync_fetch_and_sub(&triton_stat.thread_active, 1); + //printf("thread %p: enter sigwait\n", thread); + sigwait(&set, &sig); + //printf("thread %p: exit sigwait\n", thread); + __sync_fetch_and_add(&triton_stat.thread_active, 1); + + if (!thread->ctx) + continue; + } + +cont: + //printf("thread %p: ctx=%p %p\n", thread, thread->ctx, thread->ctx ? thread->ctx->thread : NULL); + if (thread->ctx->ud->before_switch) + thread->ctx->ud->before_switch(thread->ctx->ud, thread->ctx->bf_arg); + + //printf("thread %p: switch to %p\n", thread, thread->ctx); + while (1) { + if (swapcontext(&thread->uctx, &thread->ctx->uctx)) { + if (errno == EINTR) + continue; + triton_log_error("swapcontext: %s\n", strerror(errno)); + } else + break; + } + //printf("thread %p: switch from %p %p\n", thread, thread->ctx, thread->ctx->thread); + + if (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) { + //printf("- context %p removed\n", thread->ctx); + mempool_free(thread->ctx->uctx.uc_stack.ss_sp); + 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; + + while (1) { + //printf("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); + 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); + if (h->trig_epoll_events & (EPOLLIN | EPOLLERR | EPOLLHUP)) + if (h->ud && h->ud->read) + h->ud->read(h->ud); + if (h->trig_epoll_events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) + if (h->ud && h->ud->write) + h->ud->write(h->ud); + 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); + } + ctx->pending = 0; + spin_unlock(&ctx->lock); + break; + } + + //printf("ctx %p %p: exit\n", ctx, ctx->thread); + while (1) { + if (swapcontext(&ctx->uctx, &ctx->thread->uctx)) { + if (errno == EINTR) + continue; + triton_log_error("swapcontext: %s\n", strerror(errno)); + } else + break; + } + } +} + +struct _triton_thread_t *create_thread() +{ + struct _triton_thread_t *thread = malloc(sizeof(*thread)); + if (!thread) + return NULL; + + memset(thread, 0, sizeof(*thread)); + if (pthread_create(&thread->thread, NULL, (void*(*)(void*))triton_thread, thread)) { + triton_log_error("pthread_create: %s", strerror(errno)); + return NULL; + } + + triton_stat.thread_count++; + triton_stat.thread_active++; + + return thread; +} + +int triton_queue_ctx(struct _triton_context_t *ctx) +{ + ctx->pending = 1; + if (ctx->thread || ctx->queued || ctx->sleeping) + return 0; + + spin_lock(&threads_lock); + if (list_empty(&sleep_threads)) { + list_add_tail(&ctx->entry2, &ctx_queue); + spin_unlock(&threads_lock); + ctx->queued = 1; + //printf("ctx %p: queued\n", ctx); + __sync_fetch_and_add(&triton_stat.context_pending, 1); + return 0; + } + + ctx->thread = list_entry(sleep_threads.next, typeof(*ctx->thread), entry2); + ctx->thread->ctx = ctx; + //printf("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); + + if (!ctx) + return -1; + + memset(ctx, 0, sizeof(*ctx)); + ctx->ud = ud; + ctx->bf_arg = bf_arg; + ctx->sleeping = 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); + + if (getcontext(&ctx->uctx)) { + triton_log_error("getcontext: %s\n", strerror(errno)); + _free(ctx); + return -1; + } + + ctx->uctx.uc_stack.ss_size = CTX_STACK_SIZE; + ctx->uctx.uc_stack.ss_sp = mempool_alloc(ctx_stack_pool); + if (!ctx->uctx.uc_stack.ss_sp) { + triton_log_error("out of memory\n"); + _free(ctx); + return -1; + } + sigfillset(&ctx->uctx.uc_sigmask); + makecontext(&ctx->uctx, (void (*)())ctx_thread, 1, ctx); + + ud->tpd = ctx; + + spin_lock(&ctx_list_lock); + list_add_tail(&ctx->entry, &ctx_list); + spin_unlock(&ctx_list_lock); + + __sync_fetch_and_add(&triton_stat.context_sleeping, 1); + __sync_fetch_and_add(&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; + + 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 (need_terminate && list_empty(&ctx_list)) + terminate = 1; + spin_unlock(&ctx_list_lock); + + __sync_fetch_and_sub(&triton_stat.context_count, 1); + + if (terminate) { + list_for_each_entry(t, &threads, entry) + triton_thread_wakeup(t); + } +} +void __export triton_context_schedule(struct triton_context_t *ud) +{ + struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd; + ucontext_t *uctx = &ctx->thread->uctx; + + spin_lock(&ctx->lock); + if (ctx->wakeup) { + ctx->wakeup = 0; + spin_unlock(&ctx->lock); + return; + } + ctx->sleeping = 1; + ctx->thread = NULL; + spin_unlock(&ctx->lock); + + while (1) { + if (swapcontext(&ctx->uctx, uctx)) { + if (errno == EINTR) + continue; + triton_log_error("swaswpntext: %s\n", strerror(errno)); + } else + break; + } + + __sync_fetch_and_add(&triton_stat.context_sleeping, 1); +} + +int __export triton_context_wakeup(struct triton_context_t *ud) +{ + struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd; + int r; + + spin_lock(&ctx->lock); + if (!ctx->sleeping) { + ctx->wakeup = 1; + spin_unlock(&ctx->lock); + return -1; + } + ctx->sleeping = 0; + r = triton_queue_ctx(ctx); + spin_unlock(&ctx->lock); + + if (r) + triton_thread_wakeup(ctx->thread); + + __sync_fetch_and_sub(&triton_stat.context_sleeping, 1); + + return 0; +} + +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; +} + +int __export triton_init(const char *conf_file) +{ + ctx_pool = mempool_create(sizeof(struct _triton_context_t)); + call_pool = mempool_create(sizeof(struct _triton_ctx_call_t)); + ctx_stack_pool = mempool_create(CTX_STACK_SIZE); + + 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_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); + } + + md_run(); + timer_run(); +} + +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-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h new file mode 100644 index 00000000..4b4d9c41 --- /dev/null +++ b/accel-pptpd/triton/triton.h @@ -0,0 +1,127 @@ +#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 +{ + uint32_t mempool_allocated; + uint32_t mempool_available; + uint32_t thread_count; + uint32_t thread_active; + uint32_t context_count; + uint32_t context_sleeping; + uint32_t context_pending; + uint32_t md_handler_count; + uint32_t md_handler_pending; + uint32_t timer_count; + uint32_t timer_pending; +}; + +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_schedule(struct triton_context_t *); +int triton_context_wakeup(struct triton_context_t *); +int triton_context_call(struct triton_context_t *, void (*func)(void *), void *arg); + +#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); + +#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 __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-pptpd/triton/triton_p.h b/accel-pptpd/triton/triton_p.h new file mode 100644 index 00000000..c685051a --- /dev/null +++ b/accel-pptpd/triton/triton_p.h @@ -0,0 +1,105 @@ +#ifndef TRITON_P_H +#define TRITON_P_H + +#include <pthread.h> +#include <sys/epoll.h> +#include <ucontext.h> + +#include "triton.h" +#include "list.h" +#include "spinlock.h" +#include "mempool.h" + +#define CTX_STACK_SIZE 8196 + +struct _triton_thread_t +{ + struct list_head entry; + struct list_head entry2; + pthread_t thread; + int terminate:1; + struct _triton_context_t *ctx; + ucontext_t uctx; +}; + +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; + + ucontext_t uctx; + + int queued:1; + int sleeping:1; + int wakeup:1; + int need_close:1; + int need_free:1; + int pending:1; + + 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(); +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); +void triton_log_error(const char *fmt,...); +void triton_log_debug(const char *fmt,...); +int load_modules(const char *name); + +#endif |