From f28cb1b0a926f1ea98700b7871537ad1793511fd Mon Sep 17 00:00:00 2001 From: Dmitry Kozlov Date: Wed, 5 Jan 2011 15:18:59 +0300 Subject: rename accel-pptp to accel-ppp --- accel-pppd/triton/CMakeLists.txt | 40 +++ accel-pppd/triton/conf_file.c | 248 ++++++++++++++++ accel-pppd/triton/event.c | 105 +++++++ accel-pppd/triton/list.h | 249 ++++++++++++++++ accel-pppd/triton/loader.c | 62 ++++ accel-pppd/triton/log.c | 73 +++++ accel-pppd/triton/md.c | 216 ++++++++++++++ accel-pppd/triton/mempool.c | 338 ++++++++++++++++++++++ accel-pppd/triton/mempool.h | 26 ++ accel-pppd/triton/options.c | 48 +++ accel-pppd/triton/spinlock.h | 42 +++ accel-pppd/triton/timer.c | 222 ++++++++++++++ accel-pppd/triton/timerfd.c | 19 ++ accel-pppd/triton/timerfd.h | 60 ++++ accel-pppd/triton/triton.c | 610 +++++++++++++++++++++++++++++++++++++++ accel-pppd/triton/triton.h | 138 +++++++++ accel-pppd/triton/triton_p.h | 103 +++++++ 17 files changed, 2599 insertions(+) create mode 100644 accel-pppd/triton/CMakeLists.txt create mode 100644 accel-pppd/triton/conf_file.c create mode 100644 accel-pppd/triton/event.c create mode 100644 accel-pppd/triton/list.h create mode 100644 accel-pppd/triton/loader.c create mode 100644 accel-pppd/triton/log.c create mode 100644 accel-pppd/triton/md.c create mode 100644 accel-pppd/triton/mempool.c create mode 100644 accel-pppd/triton/mempool.h create mode 100644 accel-pppd/triton/options.c create mode 100644 accel-pppd/triton/spinlock.h create mode 100644 accel-pppd/triton/timer.c create mode 100644 accel-pppd/triton/timerfd.c create mode 100644 accel-pppd/triton/timerfd.h create mode 100644 accel-pppd/triton/triton.c create mode 100644 accel-pppd/triton/triton.h create mode 100644 accel-pppd/triton/triton_p.h (limited to 'accel-pppd/triton') 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 + 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 +#include +#include +#include +#include + +#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(§ions)) { + sect = list_entry(sections.next, typeof(*sect), entry); + list_del(§->entry); + list_add_tail(§->entry, §ions_bak); + } + + r = conf_load(fname); + + if (r) { + while (!list_empty(§ions_bak)) { + sect = list_entry(sections_bak.next, typeof(*sect), entry); + list_del(§->entry); + list_add_tail(§->entry, §ions); + } + pthread_mutex_unlock(&conf_lock); + } else { + pthread_mutex_unlock(&conf_lock); + while (!list_empty(§ions_bak)) { + sect = list_entry(sections_bak.next, typeof(*sect), entry); + list_del(§->entry); + while (!list_empty(§->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, §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-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 +#include +#include + +#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 + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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_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 +#include + +#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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#include "triton_p.h" + +#include "memdebug.h" + +#ifdef VALGRIND +#include +#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 + +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 +#include + +#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-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 +#include +#include +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 +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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_TIMERFD +#include +#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 +#include +#include + +#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 + + +/* 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 +#include +#include +#include +#include +#include +#include + +#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 +#include + +#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 +#include + +#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 -- cgit v1.2.3