diff options
Diffstat (limited to 'python/gevent/libuv/_corecffi_source.c')
-rw-r--r-- | python/gevent/libuv/_corecffi_source.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/python/gevent/libuv/_corecffi_source.c b/python/gevent/libuv/_corecffi_source.c new file mode 100644 index 0000000..83fe82e --- /dev/null +++ b/python/gevent/libuv/_corecffi_source.c @@ -0,0 +1,181 @@ +#include <string.h> +#include "uv.h" + +typedef void* GeventWatcherObject; + +static int python_callback(GeventWatcherObject handle, int revents); +static void python_queue_callback(uv_handle_t* watcher_ptr, int revents); +static void python_handle_error(GeventWatcherObject handle, int revents); +static void python_stop(GeventWatcherObject handle); + +static void _gevent_noop(void* handle) {} + +static void (*gevent_noop)(void* handle) = &_gevent_noop; + +static void _gevent_generic_callback1_unused(uv_handle_t* watcher, int arg) +{ + // Python code may set this to NULL or even change it + // out from under us, which would tend to break things. + GeventWatcherObject handle = watcher->data; + const int cb_result = python_callback(handle, arg); + switch(cb_result) { + case -1: + // in case of exception, call self.loop.handle_error; + // this function is also responsible for stopping the watcher + // and allowing memory to be freed + python_handle_error(handle, arg); + break; + case 1: + // Code to stop the event IF NEEDED. Note that if python_callback + // has disposed of the last reference to the handle, + // `watcher` could now be invalid/disposed memory! + if (!uv_is_active(watcher)) { + if (watcher->data != handle) { + if (watcher->data) { + // If Python set the data to NULL, then they + // expected to be stopped. That's fine. + // Otherwise, something weird happened. + fprintf(stderr, + "WARNING: gevent: watcher handle changed in callback " + "from %p to %p for watcher at %p of type %d\n", + handle, watcher->data, watcher, watcher->type); + // There's a very good chance that the object the + // handle referred to has been changed and/or the + // old handle has been deallocated (most common), so + // passing the old handle will crash. Instead we + // pass a sigil to let python distinguish this case. + python_stop(NULL); + } + } + else { + python_stop(handle); + } + } + break; + case 2: + // watcher is already stopped and dead, nothing to do. + break; + default: + fprintf(stderr, + "WARNING: gevent: Unexpected return value %d from Python callback " + "for watcher %p (of type %d) and handle %p\n", + cb_result, + watcher, watcher->type, handle); + // XXX: Possible leaking of resources here? Should we be + // closing the watcher? + } +} + + +static void _gevent_generic_callback1(uv_handle_t* watcher, int arg) +{ + python_queue_callback(watcher, arg); +} + +static void _gevent_generic_callback0(uv_handle_t* handle) +{ + _gevent_generic_callback1(handle, 0); +} + +static void _gevent_async_callback0(uv_async_t* handle) +{ + _gevent_generic_callback0((uv_handle_t*)handle); +} + +static void _gevent_timer_callback0(uv_timer_t* handle) +{ + _gevent_generic_callback0((uv_handle_t*)handle); +} + +static void _gevent_prepare_callback0(uv_prepare_t* handle) +{ + _gevent_generic_callback0((uv_handle_t*)handle); +} + +static void _gevent_check_callback0(uv_check_t* handle) +{ + _gevent_generic_callback0((uv_handle_t*)handle); +} + +static void _gevent_idle_callback0(uv_idle_t* handle) +{ + _gevent_generic_callback0((uv_handle_t*)handle); +} + +static void _gevent_signal_callback1(uv_signal_t* handle, int signum) +{ + _gevent_generic_callback1((uv_handle_t*)handle, signum); +} + + +static void _gevent_poll_callback2(void* handle, int status, int events) +{ + _gevent_generic_callback1(handle, status < 0 ? status : events); +} + +static void _gevent_fs_event_callback3(void* handle, const char* filename, int events, int status) +{ + _gevent_generic_callback1(handle, status < 0 ? status : events); +} + + +typedef struct _gevent_fs_poll_s { + uv_fs_poll_t handle; + uv_stat_t curr; + uv_stat_t prev; +} gevent_fs_poll_t; + +static void _gevent_fs_poll_callback3(void* handlep, int status, const uv_stat_t* prev, const uv_stat_t* curr) +{ + // stat pointers are valid for this callback only. + // if given, copy them into our structure, where they can be reached + // from python, just like libev's watcher does, before calling + // the callback. + + // The callback is invoked with status < 0 if path does not exist + // or is inaccessible. The watcher is not stopped but your + // callback is not called again until something changes (e.g. when + // the file is created or the error reason changes). + // In that case the fields will be 0 in curr/prev. + + + gevent_fs_poll_t* handle = (gevent_fs_poll_t*)handlep; + assert(status == 0); + + handle->curr = *curr; + handle->prev = *prev; + + _gevent_generic_callback1((uv_handle_t*)handle, 0); +} + +static void gevent_uv_walk_callback_close(uv_handle_t* handle, void* arg) +{ + if( handle && !uv_is_closing(handle) ) { + uv_close(handle, NULL); + } +} + +static void gevent_close_all_handles(uv_loop_t* loop) +{ + uv_walk(loop, gevent_uv_walk_callback_close, NULL); +} + +static void gevent_zero_timer(uv_timer_t* handle) +{ + memset(handle, 0, sizeof(uv_timer_t)); +} + +static void gevent_zero_check(uv_check_t* handle) +{ + memset(handle, 0, sizeof(uv_check_t)); +} + +static void gevent_zero_prepare(uv_prepare_t* handle) +{ + memset(handle, 0, sizeof(uv_prepare_t)); +} + +static void gevent_zero_loop(uv_loop_t* handle) +{ + memset(handle, 0, sizeof(uv_loop_t)); +} |