/tobikko/core/hub.c
C | 1224 lines | 989 code | 157 blank | 78 comment | 186 complexity | 5bb206c9a96b2240e197662c3ad76c35 MD5 | raw file
- #include "hub.h"
- #include "timer.h"
- #include "heapq.h"
- #include "lookup.h"
- #include "buffer.h"
- #include "socket.h"
- #include "greensupport.h"
- #include <assert.h>
- typedef struct {
- TimerObject **q;
- uint32_t size;
- uint32_t max;
- } pending_queue_t;
- typedef struct {
- PyGreenlet *greenlet;
- PyObject *timeout_exc;
- } switch_arg_t;
- //loop start flag
- static volatile sig_atomic_t loop_done;
- static volatile sig_atomic_t catch_signal = 0;
- //force stop flag
- static uint8_t stopped = 0;
- static uint8_t debug = 0;
- static uint32_t activecnt = 0;
- static uint32_t ioactivecnt = 0;
- static heapq_t *g_timers;
- static pending_queue_t *g_pendings = NULL;
- //static HubObject *hub = NULL;
- static PyObject *watchdog = NULL;
- static PyGreenlet *suspend_thread = NULL;
- static PyObject *system_errors;
- static PyObject *sleep_callback = NULL;
- //special switch value
- static int internal_init_hub_thread(HubObject *self);
- static inline PyObject* internal_hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet);
- static inline HubObject* internal_get_hub(void);
- static void
- sigint_cb(int signum)
- {
- DEBUG("call SIGINT");
- loop_done = 0;
- RDEBUG("loop_done = 0");
- if(!catch_signal){
- catch_signal = 1;
- }
- //hub_abort();
- }
- static void
- sigpipe_cb(int signum)
- {
- }
- static int
- init_pendings(void)
- {
- pending_queue_t *pendings = NULL;
- pendings = PyMem_Malloc(sizeof(pending_queue_t));
- if(pendings == NULL){
- return -1;
- }
- pendings->size = 0;
- pendings->max= 1024;
- pendings->q = (TimerObject**)malloc(sizeof(TimerObject*) * pendings->max);
- if(pendings->q == NULL){
- PyMem_Free(pendings);
- return -1;
- }
- g_pendings = pendings;
- return 1;
- }
- static int
- realloc_pendings(void)
- {
- TimerObject **new_heap;
- uint32_t max;
- pending_queue_t *pendings = g_pendings;
- if(pendings->size >= pendings->max){
- //realloc
- max = pendings->max * 2;
- new_heap = (TimerObject**)realloc(pendings->q, sizeof(TimerObject*) * max);
- if(new_heap == NULL){
- PyErr_SetString(PyExc_Exception, "size over timer queue");
- return -1;
- }
- pendings->max = max;
- pendings->q = new_heap;
- RDEBUG("realloc max:%d", pendings->max);
- }
- return 1;
- }
- static void
- destroy_pendings(void)
- {
- if(g_pendings == NULL){
- return;
- }
-
- /*
- int i = pendings->start;
- int len = pendings->size - i;
- TimerObject *timer = NULL;
- TimerObject **t = pendings->q;
- t += i;
- while(len--){
- timer = *t;
- Py_DECREF(timer);
- pendings->start++;
- t++;
- }*/
- free(g_pendings->q);
- PyMem_Free(g_pendings);
- g_pendings = NULL;
- }
- void
- reset_all(void)
- {
- //Py_XDECREF(hub);
- //hub = NULL;
- //TODO error check
- destroy_queue(g_timers);
- g_timers = init_queue();
- destroy_pendings();
- init_pendings();
- (void)reset_channel();
- //set sig again
- PyOS_setsig(SIGPIPE, sigpipe_cb);
- PyOS_setsig(SIGINT, sigint_cb);
- PyOS_setsig(SIGTERM, sigint_cb);
- reset_main_loop();
- }
- static inline int
- fire_pendings(void)
- {
- PyObject *res;
- TimerObject *timer = NULL;
- pending_queue_t *pendings = g_pendings;
- while(pendings->size && loop_done){
- timer = *(pendings->q + --pendings->size);
- DEBUG("start timer:%p activecnt:%d", timer, activecnt);
- if(!timer->called){
- timer->called = 1;
- res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
- Py_XDECREF(res);
- DEBUG("call pending %p", timer);
- }
- Py_DECREF(timer);
- activecnt--;
- DEBUG("fin timer:%p activecnt:%d", timer, activecnt);
- if(PyErr_Occurred()){
- RDEBUG("pending call raise exception");
- if(debug){
- //TODO PyErr_Print or write log
- PyErr_Print();
- }else{
- return -1;
- }
- }
- }
- return 1;
- }
- static inline int
- fire_timer(void)
- {
- TimerObject *timer;
- int ret = 1;
- heapq_t *q = g_timers;
- time_t now = time(NULL);
- PyObject *res = NULL;
- while(q->size > 0 && loop_done){
- timer = q->heap[0];
- if(timer->seconds <= now){
- //call
- if(!timer->called){
- timer->called = 1;
- if(timer->greenlet){
- //local timer
- if(!greenlet_dead(timer->greenlet)){
- res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
- }
- } else{
- res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
- }
- Py_XDECREF(res);
- }
- timer = heappop(q);
- Py_DECREF(timer);
- activecnt--;
- if(PyErr_Occurred()){
- RDEBUG("scheduled call raise exception");
- if(debug){
- //TODO PyErr_Print or write log
- PyErr_Print();
- }else{
- ret = -1;
- break;
- }
- }
- }else{
- break;
- }
- }
- return ret;
- }
- static void
- init_main_loop(HubObject *self)
- {
- if(self && self->main_loop == NULL){
- //DEBUG("init_main_loop");
- //DEBUG("self %p" ,self);
- picoev_init(self->maxfd);
- self->main_loop = picoev_create_loop(60);
- self->main_loop->now = time(NULL);
- }
- }
- static void
- destroy_main_loop(HubObject *self)
- {
- if(self && self->main_loop != NULL){
- DEBUG("self %p" ,self);
- picoev_destroy_loop(self->main_loop);
- picoev_deinit();
- self->main_loop = NULL;
- }
- }
- void
- reset_main_loop(void)
- {
- HubObject *hub = internal_get_hub();
- if(hub != NULL){
- destroy_main_loop(hub);
- init_main_loop(hub);
- }
- }
- static int
- internal_loop(HubObject *self)
- {
- int ret = 1;
- heapq_t *q = g_timers;
- picoev_loop *loop = NULL;
- init_main_loop(self);
- if(suspend_thread){
- //reset_main_loop();
- DEBUG("switch to suspend_thread");
- PyObject *o = greenlet_switch(suspend_thread, NULL, NULL);
- Py_XDECREF(o);
- Py_DECREF(suspend_thread);
- suspend_thread = NULL;
- }
- loop_done = 1;
- DEBUG("loop start loop:%p activecnt:%d", self->main_loop, activecnt);
- loop = self->main_loop;
- while (likely(loop_done && activecnt > 0)) {
- if(unlikely(fire_pendings() == -1)){
- //error stop hub
- loop_done = 0;
- RDEBUG("loop_done = 0");
- ret = -1;
- continue;
- }
- if(q->size > 0){
- if(unlikely(fire_timer() == -1)){
- loop_done = 0;
- RDEBUG("loop_done = 0");
- ret = -1;
- continue;
- }
- }
- if(ioactivecnt > 0 || q->size > 0){
- picoev_loop_once(loop, 10);
- }
- //DEBUG("%d", main_loop->timeout.resolution);
- /*
- if(watchdog){
- //check
- watchdog_result = PyObject_CallFunction(watchdog, NULL);
- if(PyErr_Occurred()){
- PyErr_Print();
- //PyErr_Clear();
- }
- Py_XDECREF(watchdog_result);
- }*/
- //DEBUG("active event io:%d/total:%d", ioactivecnt, activecnt);
- }
- //abort ??
- if(PyErr_Occurred()){
- //if(stopped || PyErr_Occurred()){
- ret = -1;
- }
- //destroy_main_loop(self);
- //reset_main_loop();
- //TODO clear timer queure and pendings
- //activecnt -= ioactivecnt;
- //ioactivecnt = 0;
- RDEBUG("loop end ret:%d", ret);
- DEBUG("fin active event io:%d/total:%d", ioactivecnt, activecnt);
- stopped = 0;
- loop_done= 0;
- return ret;
- }
- static void
- switch_user_thread(picoev_loop* loop, int fd, PyGreenlet *greenlet)
- {
- PyObject *res = NULL;
- RDEBUG("del event fd:%d thread:%p", fd, greenlet);
- //clear event
- picoev_del(loop, fd);
- activecnt--;
- ioactivecnt--;
- if(!PyErr_Occurred()){
- res = greenlet_switch(greenlet, NULL, NULL);
- Py_XDECREF(res);
- }else{
- loop_done = 0;
- }
- }
- static inline HubObject*
- internal_get_hub(void)
- {
- HubObject *self;
- static HubObject *g_hub = NULL;
- if(g_hub != NULL){
- return g_hub;
- }
- self = PyObject_NEW(HubObject, &HubObjectType);
- if(self == NULL){
- return NULL;
- }
- self->main_loop = NULL;
- self->greenlet = NULL;
- self->maxfd = 1024;
- //DEBUG("self %p", self);
- if(internal_init_hub_thread(self) == -1){
- PyObject_DEL(self);
- return NULL;
- }
- g_hub = self;
- return g_hub;
- }
- PyObject *
- get_hub(void)
- {
- return (PyObject*)internal_get_hub();
- }
- static void
- HubObject_dealloc(HubObject *self)
- {
- DEBUG("self %p", self);
- Py_XDECREF(self->greenlet);
- PyObject_DEL(self);
- }
- static PyObject*
- HubObject_run(HubObject *self, PyObject *args)
- {
- PyObject *ret;
- DEBUG("self %p", self);
- while(1){
- if(loop_done == 1){
- DEBUG("already running");
- Py_RETURN_NONE;
- }
- if(internal_loop(self) < 0){
- return NULL;
- }
- if(catch_signal){
- //override
- PyErr_Clear();
- PyErr_SetNone(PyExc_KeyboardInterrupt);
- catch_signal = 0;
- return NULL;
- }
- RDEBUG("hub stopped loop_done:%d", loop_done);
- PyErr_SetString(HubAbortException, "loop block forever");
- ret = greenlet_throw_err(PyGreenlet_GET_PARENT(self->greenlet));
- Py_XDECREF(ret);
- }
- Py_RETURN_NONE;
- }
- PyObject*
- hub_abort(void)
- {
- HubObject *self = internal_get_hub();
- DEBUG("self %p", self);
- if(loop_done == 1){
- stopped = 1;
- loop_done = 0;
- RDEBUG("loop_done = 0");
- if(PyGreenlet_STARTED(self->greenlet)){
- //if(!PyErr_Occurred()){
- //PyErr_SetString(PyExc_IOError, "hub aborted");
- //}
- return hub_switch();
- }
- }
- Py_RETURN_NONE;
- }
- static PyObject*
- HubObject_abort(HubObject *self, PyObject *args)
- {
- DEBUG("self %p", self);
- return hub_abort();
- }
- static PyObject*
- HubObject_reset(HubObject *self, PyObject *args)
- {
- DEBUG("self %p", self);
- if(stopped == 1){
- loop_done = 1;
- stopped = 0;
- }
- Py_RETURN_NONE;
- }
- static int
- internal_init_hub_thread(HubObject *self)
- {
- PyObject *run;
- PyGreenlet *temp;
- Py_CLEAR(self->greenlet);
- run = PyObject_GetAttrString((PyObject *)self, "run");
- if(run == NULL){
- return -1;
- }
- temp = greenlet_new(run, NULL);
- if(temp == NULL){
- return -1;
- }
- Py_DECREF(run);
- Py_INCREF(temp);
- self->greenlet = temp;
- //DEBUG("create new hub greenlet %p", temp);
- return 1;
- }
- int
- init_hub_thread(void)
- {
- return internal_init_hub_thread(internal_get_hub());
- }
- PyObject*
- hub_switch(void)
- {
- PyGreenlet *current = NULL, *parent = NULL;
- HubObject *self = internal_get_hub();
- current = greenlet_getcurrent();
- if(self->greenlet == current){
- parent = PyGreenlet_GET_PARENT(self->greenlet);
- Py_DECREF(current);
- return greenlet_switch(parent, NULL, NULL);
- }
- DEBUG("switch hub:%p hub_parent:%p current:%p", self->greenlet, PyGreenlet_GET_PARENT(self->greenlet), current);
- if(!stopped){
- //dead check
- if(greenlet_dead(self->greenlet)){
- //PyErr_SetString(PyExc_IOError, "stoped hub thread");
- DEBUG("warning !! hub is dead");
- if(internal_init_hub_thread(self) < 0){
- Py_DECREF(current);
- return NULL;
- }
- }
- parent = PyGreenlet_GET_PARENT(self->greenlet);
- if(parent != current){
- greenlet_setparent(current, self->greenlet);
- }
- }
- Py_DECREF(current);
- return greenlet_switch(self->greenlet, NULL, NULL);
- }
- static PyObject*
- HubObject_switch(HubObject *self, PyObject *args)
- {
- return hub_switch();
- }
- static PyObject*
- HubObject_join(HubObject *self, PyObject *args, PyObject *kwargs)
- {
- PyObject *ret;
- ret = hub_switch();
- if(PyErr_ExceptionMatches(HubAbortException)){
- DEBUG("hub abort");
- PyErr_Clear();
- Py_XDECREF(ret);
- Py_RETURN_NONE;
- }
- return ret;
- }
- PyObject*
- spawn(PyObject *callable, PyObject *args)
- {
- PyObject *ret;
- PyGreenlet *greenlet;
- HubObject *hub;
- hub = internal_get_hub();
- greenlet = greenlet_new(callable, hub->greenlet);
- if(greenlet == NULL){
- return NULL;
- }
- DEBUG("start thread:%p cnt:%d", greenlet, (int)Py_REFCNT(greenlet));
- ret = greenlet_switch(greenlet, args, NULL);
- Py_DECREF(greenlet);
- DEBUG("fin thread:%p ret:%p cnt:%d", greenlet, ret, (int)Py_REFCNT(greenlet));
- return ret;
- }
- static void
- print_exception(PyObject *context, PyObject *type, PyObject *value, PyObject *traceback)
- {
- if(PyObject_IsSubclass(type, system_errors)){
- DEBUG("ignore");
- return;
- }
- if(traceback == NULL){
- traceback = Py_None;
- }
- Py_INCREF(type);
- Py_INCREF(value);
- Py_INCREF(traceback);
- PyErr_Restore(type, value, traceback);
- PyErr_Print();
- if(context != NULL){
- PySys_WriteStderr("%s occured from ", PyExceptionClass_Name(type));
- PyObject_Print(context, stderr, 0);
- PySys_WriteStderr(" \n");
- }
- return ;
- }
- PyObject*
- internal_hub_handle_error(PyObject *type, PyObject *value, PyObject *traceback, int checktype)
- {
- PyGreenlet *current, *parent;
- PyObject *o, *throw, *timer;
- HubObject *hub = internal_get_hub();
- if(checktype && !PyObject_IsSubclass(type, system_errors)){
- DEBUG("ignore exception");
- Py_RETURN_NONE;
- }
- current = greenlet_getcurrent();
- parent = PyGreenlet_GET_PARENT(hub->greenlet);
- RDEBUG("hub->greenlet:%p current:%p parent:%p", hub->greenlet, current, parent);
- if(current == hub->greenlet || current == parent){
- Py_DECREF(current);
- return greenlet_throw(parent, type, value, traceback);
- }else{
- Py_DECREF(current);
- o = Py_BuildValue("OOO", type, value, traceback);
- if(o == NULL){
- return NULL;
- }
- throw = PyObject_GetAttrString((PyObject*)parent, "throw");
- if(throw == NULL){
- return NULL;
- }
- timer = internal_hub_schedule_call(0, throw, o, NULL, NULL);
- if(timer == NULL){
- Py_DECREF(timer);
- return NULL;
- }
- Py_DECREF(throw);
- Py_DECREF(timer);
- Py_RETURN_NONE;
- }
- }
- PyObject*
- hub_handle_error(PyObject *context, PyObject *type, PyObject *value, PyObject *traceback)
- {
- PyObject *t = type, *v = value, *tr = traceback;
-
- DEBUG("context:%p type:%p value:%p traceback:%p", context, type, value, traceback);
- if(t == NULL && v == NULL){
- PyErr_Fetch(&t, &v, &tr);
- PyErr_Clear();
- if(tr == NULL){
- tr = Py_None;
- Py_INCREF(tr);
- }
- }
- print_exception(context, type, value, traceback);
- return internal_hub_handle_error(t, v, tr, 1);
- }
- static PyObject*
- hub_handle_timeout_error(PyObject *context)
- {
- PyObject *t, *v, *tr;
- PyErr_Fetch(&t, &v, &tr);
- PyErr_Clear();
- if(tr == NULL){
- tr = Py_None;
- Py_INCREF(tr);
- }
- print_exception(context, t, v, tr);
- return internal_hub_handle_error(t, v, tr, 0);
- }
- static inline PyObject*
- internal_hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
- {
- TimerObject *timer;
- pending_queue_t *pendings = g_pendings;
- heapq_t *timers = g_timers;
- timer = TimerObject_new(seconds, cb, greenlet, args, kwargs);
- if(timer == NULL){
- return NULL;
- }
- if(!seconds){
- if(realloc_pendings() == -1){
- Py_DECREF(timer);
- return NULL;
- }
- Py_INCREF(timer);
- //timer->pending = ++pendings->size;
- pendings->q[pendings->size] = timer;
- pendings->size++;
- DEBUG("add timer:%p pendings->size:%d", timer, pendings->size);
- }else{
- if(heappush(timers, timer) == -1){
- Py_DECREF(timer);
- return NULL;
- }
- }
- activecnt++;
- return (PyObject *)timer;
- }
- PyObject*
- hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
- {
- return internal_hub_schedule_call(seconds, cb, args, kwargs, greenlet);
- }
- PyObject*
- hub_set_timeout(int seconds, PyObject *exception)
- {
- TimerObject *timer;
- PyGreenlet *greenlet;
- PyObject *o, *throw, *exc, *value;
- exc = exception;
- if(exc == NULL){
- exc = TimeoutException;
- }
- value = PyObject_CallFunction(exc, "", NULL);
- o = Py_BuildValue("OOO", exc, value, Py_None);
- if(o == NULL){
- return NULL;
- }
- greenlet = greenlet_getcurrent();
- throw = PyObject_GetAttrString((PyObject*)greenlet, "throw");
- if(throw == NULL){
- return NULL;
- }
- timer = (TimerObject*)internal_hub_schedule_call(seconds, throw, o, NULL, NULL);
- Py_DECREF(o);
- Py_DECREF(throw);
- Py_DECREF(greenlet);
- if(exc == TimeoutException && (PyObject_SetAttrString(value, "timer", (PyObject*)timer) == -1)){
- timer->called = 1;
- Py_DECREF(timer);
- return NULL;
- }
- return (PyObject *)timer;
- }
- static PyObject*
- internal_schedule_call(HubObject *self, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
- {
- long seconds = 0, ret;
- Py_ssize_t size;
- PyObject *sec = NULL, *cb = NULL, *cbargs = NULL, *timer;
- DEBUG("self %p", self);
- size = PyTuple_GET_SIZE(args);
- DEBUG("args size %d", (int)size);
- if(size < 2){
- PyErr_SetString(PyExc_TypeError, "schedule_call takes exactly 2 argument");
- return NULL;
- }
- sec = PyTuple_GET_ITEM(args, 0);
- cb = PyTuple_GET_ITEM(args, 1);
- #ifdef PY3
- if(!PyLong_Check(sec)){
- #else
- if(!PyInt_Check(sec)){
- #endif
- PyErr_SetString(PyExc_TypeError, "must be integer");
- return NULL;
- }
- if(!PyCallable_Check(cb)){
- PyErr_SetString(PyExc_TypeError, "must be callable");
- return NULL;
- }
- ret = PyLong_AsLong(sec);
- if(PyErr_Occurred()){
- return NULL;
- }
- if(ret < 0){
- PyErr_SetString(PyExc_TypeError, "seconds value out of range");
- return NULL;
- }
- seconds = ret;
- if(size > 2){
- cbargs = PyTuple_GetSlice(args, 2, size);
- }
- timer = internal_hub_schedule_call(seconds, cb, cbargs, kwargs, greenlet);
- Py_XDECREF(cbargs);
- return timer;
- }
- static PyObject*
- HubObject_schedule_call_local(HubObject *self, PyObject *args, PyObject *kwargs)
- {
- //DEBUG("HubObject_schedule_call_local self %p", self);
- PyObject *ret = NULL;
- PyGreenlet *temp = greenlet_getcurrent();
- if(temp == NULL){
- return NULL;
- }
- //DEBUG("schedule_call current greenlet:%p self:%p", temp, self->greenlet);
- if(temp == self->greenlet){
- DEBUG("global self %p", self);
- ret = internal_schedule_call(self, args, kwargs, NULL);
- }else{
- DEBUG("local self %p", self);
- ret = internal_schedule_call(self, args, kwargs, temp);
- }
- Py_DECREF(temp);
- return ret;
- }
- static PyObject*
- HubObject_schedule_call_global(HubObject *self, PyObject *args, PyObject *kwargs)
- {
- DEBUG("self %p", self);
- return internal_schedule_call(self, args, kwargs, NULL);
- }
- static void
- trampoline_switch_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
- {
- switch_arg_t *switch_arg = NULL;
- PyObject *res = NULL;
- switch_arg = (switch_arg_t*)cb_arg;
- DEBUG("trampoline_switch_callback loop:%p thread:%p fd:%d events:%d ", loop, switch_arg->greenlet, fd, events);
- if ((events & PICOEV_TIMEOUT) != 0) {
- DEBUG("trampoline_switch_callback timeout !!!!");
- PyErr_SetString(switch_arg->timeout_exc, "timeout");
- res = hub_handle_timeout_error((PyObject*)switch_arg->greenlet);
- } else if ((events & PICOEV_WRITE) != 0 || (events & PICOEV_READ) != 0) {
- res = greenlet_switch(switch_arg->greenlet, NULL, NULL);
- }
- Py_XDECREF(res);
- }
- static int
- ready_trampoline(HubObject *hub, int loop_check)
- {
- PyObject *o = NULL;
- PyGreenlet *current = NULL;
- if(hub->main_loop == NULL || greenlet_dead(hub->greenlet)){
- RDEBUG("hub not running !!!! hub:%p loop_done:%d hub->main_loop:%p", hub, loop_done, hub->main_loop);
- suspend_thread = greenlet_getcurrent();
- o = hub_switch();
- Py_XDECREF(o);
- return 1;
- }
- if(loop_check){
- current = greenlet_getcurrent();
- if(current == hub->greenlet){
- RDEBUG("Cannot switch to MAINLOOP from MAINLOOP");
- PyErr_SetString(PyExc_IOError, "Cannot switch to MAINLOOP from MAINLOOP");
- Py_DECREF(current);
- return -1;
- }
- Py_DECREF(current);
- }
- return 1;
- }
- static inline PyObject*
- internal_io_trampoline(HubObject *hub, int fd, int event, int timeout, PyObject *exception, PyObject *args)
- {
- int ret, active;
- int t = timeout < 0 ? 0 : timeout;
- switch_arg_t *switch_arg;
- PyGreenlet *current = NULL;
- PyObject *res;
- //TODO check exception type
- switch_arg = PyMem_Malloc(sizeof(switch_arg_t));
- if(switch_arg == NULL){
- return NULL;
- }
- memset(switch_arg, 0, sizeof(switch_arg_t));
- current = greenlet_getcurrent();
- DEBUG("thread:%p cnt:%d", current, (int)Py_REFCNT(current));
- // switch to hub
- RDEBUG("add event loop:%p thread:%p fd:%d event:%d timeout:%d", hub->main_loop, current, fd, event, t);
- switch_arg->greenlet = current;
- switch_arg->timeout_exc = exception != NULL ? exception : TimeoutException;
- active = picoev_is_active(hub->main_loop, fd);
- ret = picoev_add(hub->main_loop, fd, event, t, trampoline_switch_callback, (void *)switch_arg);
- if((ret == 0 && !active)){
- activecnt++;
- ioactivecnt++;
- }
- res = greenlet_switch(hub->greenlet, args, NULL);
- PyMem_Free(switch_arg);
- Py_DECREF(current);
- RDEBUG("del event fd:%d thread:%p", fd, current);
- //clear event
- picoev_del(hub->main_loop, fd);
- activecnt--;
- ioactivecnt--;
- return res;
- }
- int
- io_trampoline(int fd, int event, int timeout, PyObject *exception)
- {
- HubObject *hub = internal_get_hub();
- DEBUG("fd:%d event:%d timeout:%d exception:%p", fd, event, timeout, exception);
- if(ready_trampoline(hub, 1) < 0){
- return -1;
- }
- PyObject *ret = internal_io_trampoline(hub, fd, event, timeout, exception, NULL);
- Py_XDECREF(ret);
- if(ret == NULL && PyErr_Occurred()){
- //PyErr_Print();
- RDEBUG("io_trampoline exception !!!!");
- //error
- return -1;
- }
- return 1;
- }
- static PyObject*
- HubObject_trampoline(HubObject *self, PyObject *args, PyObject *kwargs)
- {
- int fd, event, timeout = 0;
- PyObject *read = Py_None, *write = Py_None;
- HubObject *hub = NULL;
- static char *keywords[] = {"fileno", "read", "write", "timeout", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|OOi:trampoline", keywords, &fd, &read, &write, &timeout)){
- return NULL;
- }
- if(fd < 0){
- PyErr_SetString(PyExc_ValueError, "fileno value out of range ");
- return NULL;
- }
- if(timeout < 0){
- PyErr_SetString(PyExc_ValueError, "timeout value out of range ");
- return NULL;
- }
- if(PyObject_IsTrue(read) && PyObject_IsTrue(write)){
- event = PICOEV_READWRITE;
- }else if(PyObject_IsTrue(read)){
- event = PICOEV_READ;
- }else if(PyObject_IsTrue(write)){
- event = PICOEV_WRITE;
- }else{
- event = PICOEV_TIMEOUT;
- if(timeout <= 0){
- PyErr_SetString(PyExc_ValueError, "timeout value out of range ");
- return NULL;
- }
- }
- hub = internal_get_hub();
- if(ready_trampoline(hub, 1) < 0){
- return NULL;
- }
- //TODO set exception
- return internal_io_trampoline(hub, fd, event, timeout, NULL, NULL);
- }
- void
- switch_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
- {
- PyGreenlet *t = (PyGreenlet *)cb_arg;
- PyObject *res, *args;
- DEBUG("thread:%p fd:%d events:%d",t, fd, events);
- args = Py_BuildValue("(i)", fd);
- res = PyGreenlet_Switch(t, args, NULL);
- Py_XDECREF(res);
- }
- int
- add_switch_event(int fd, int event, int timeout, picoev_handler *cb)
- {
- int ret, active;
- HubObject *hub = internal_get_hub();
- PyGreenlet *current = NULL;
-
- if(ready_trampoline(hub, 1) < 0){
- return -1;
- }
- current = greenlet_getcurrent();
- // switch to hub
- RDEBUG("add event loop:%p thread:%p fd:%d event:%d timeout:%d", hub->main_loop, current, fd, event, timeout);
- active = picoev_is_active(hub->main_loop, fd);
- ret = picoev_add(hub->main_loop, fd, event, timeout, cb, (void *)current);
- if(ret == 0 && !active){
- activecnt++;
- ioactivecnt++;
- }
- Py_DECREF(current);
- return 1;
- }
- int
- add_event(int fd, int event, int timeout, picoev_handler *cb, void *data)
- {
- int ret, active;
- HubObject *hub = internal_get_hub();
- if(ready_trampoline(hub, 0) < 0){
- return -1;
- }
- // switch to hub
- RDEBUG("add event loop:%p fd:%d event:%d timeout:%d", hub->main_loop, fd, event, timeout);
- active = picoev_is_active(hub->main_loop, fd);
- ret = picoev_add(hub->main_loop, fd, event, timeout, cb, (void *)data);
- if(ret == 0 && !active){
- activecnt++;
- ioactivecnt++;
- }
- return 1;
- }
- int
- is_active_event(int fd)
- {
- HubObject *hub = internal_get_hub();
- if(hub && hub->main_loop){
- return picoev_is_active(hub->main_loop, fd);
- }
- return 0;
- }
- void
- del_event(int fd)
- {
- HubObject *hub = internal_get_hub();
- if(hub->main_loop && picoev_is_active(hub->main_loop, fd)){
- RDEBUG("del event fd:%d", fd);
- picoev_del(hub->main_loop, fd);
- activecnt--;
- ioactivecnt--;
- }
- }
- void
- update_event_timeout(int fd, int timeout)
- {
- HubObject *hub = internal_get_hub();
- picoev_set_timeout(hub->main_loop, fd, timeout);
- }
- int
- cmp_hub_thread(PyGreenlet *greenlet)
- {
- HubObject *hub;
- hub = (HubObject*)get_hub();
- if(hub->greenlet == NULL){
- return 0;
- }
- return hub->greenlet == greenlet;
- }
- static PyObject*
- HubObject_sleep_callback(PyObject *self, PyObject *args)
- {
- PyObject *o, *ret;
-
- o = PyTuple_GET_ITEM(args, 0);
- if(o == NULL){
- return NULL;
- }
- ret = greenlet_switch((PyGreenlet*)o, NULL, NULL);
- Py_XDECREF(ret);
- Py_RETURN_NONE;
- }
- int
- time_sleep(int time)
- {
- PyObject *args, *timer, *ret;
- PyGreenlet *current;
- current = greenlet_getcurrent();
- if(current == NULL){
- return -1;
- }
- args = Py_BuildValue("(O)", current);
- if(args == NULL){
- Py_DECREF(current);
- return -1;
- }
- timer = internal_hub_schedule_call(time, sleep_callback, args, NULL, NULL);
- Py_DECREF(current);
- Py_DECREF(args);
- if(timer == NULL){
- return -1;
- }
- Py_DECREF(timer);
- ret = hub_switch();
- Py_XDECREF(ret);
- return 1;
- }
- static PyMethodDef HubObject_methods[] = {
- {"run", (PyCFunction)HubObject_run, METH_NOARGS, 0},
- {"join", (PyCFunction)HubObject_join, METH_VARARGS|METH_KEYWORDS, 0},
- {"schedule_call", (PyCFunction)HubObject_schedule_call_local, METH_VARARGS|METH_KEYWORDS, 0},
- {"schedule_call_local", (PyCFunction)HubObject_schedule_call_local, METH_VARARGS|METH_KEYWORDS, 0},
- {"schedule_call_global", (PyCFunction)HubObject_schedule_call_global, METH_VARARGS|METH_KEYWORDS, 0},
- {"trampoline", (PyCFunction)HubObject_trampoline, METH_VARARGS|METH_KEYWORDS, 0},
- {NULL, NULL}
- };
- static PyMemberDef HubObject_members[] = {
- {"greenlet", T_OBJECT_EX, offsetof(HubObject, greenlet), READONLY, "hub greenlet"},
- {NULL} /* Sentinel */
- };
- PyTypeObject HubObjectType = {
- #ifdef PY3
- PyVarObject_HEAD_INIT(NULL, 0)
- #else
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- #endif
- MODULE_NAME ".Hub", /*tp_name*/
- sizeof(HubObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)HubObject_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
- "Hub", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- HubObject_methods, /* tp_methods */
- HubObject_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- };
- static PyMethodDef sleep_callback_def = {"_callback", (PyCFunction)HubObject_sleep_callback, METH_VARARGS, 0};
- int
- init_hub_module(void)
- {
- int ret;
- //DEBUG("init_hub_module");
- //TODO Check alloc error, free, etc.
- system_errors = Py_BuildValue("OOOO", PyExc_KeyboardInterrupt, PyExc_SystemExit, PyExc_SystemError, PyExc_AssertionError);
- if(system_errors == NULL){
- return -1;
- }
- g_timers = init_queue();
- if(g_timers == NULL){
- return -1;
- }
- ret = init_pendings();
- if(ret == -1){
- return -1;
- }
- PyOS_setsig(SIGPIPE, sigpipe_cb);
- PyOS_setsig(SIGINT, sigint_cb);
- PyOS_setsig(SIGTERM, sigint_cb);
- if(get_hub() == NULL){
- return -1;
- }
- /*
- DEBUG("TimerObject size %d", sizeof(TimerObject));
- DEBUG("buffer size %d", sizeof(buffer));
- DEBUG("Socket size %d", sizeof(SocketObject));
- DEBUG("pending_queue_t size %d", sizeof(pending_queue_t));
- */
- sleep_callback = PyCFunction_NewEx(&sleep_callback_def, (PyObject *)NULL, NULL);
- return 1;
- }