Commit 022a063d authored by Jason Madden's avatar Jason Madden

flesh out remainder of libuv functions and callbacks.

parent 945abc50
......@@ -14,6 +14,7 @@ import struct
__all__ = []
WIN = sys.platform.startswith('win32')
def system_bits():
return struct.calcsize('P') * 8
......@@ -40,9 +41,11 @@ _source = read_source('_corecffi_source.c')
_cdef = _cdef.replace('#define GEVENT_ST_NLINK_T int', '')
_cdef = _cdef.replace('#define GEVENT_STRUCT_DONE int', '')
_cdef = _cdef.replace('#define GEVENT_UV_OS_SOCK_T int', '')
_cdef = _cdef.replace('GEVENT_ST_NLINK_T', st_nlink_type())
_cdef = _cdef.replace("GEVENT_STRUCT_DONE _;", '...;')
_cdef = _cdef.replace("GEVENT_UV_OS_SOCK_T", 'int' if not WIN else 'SOCKET')
# if sys.platform.startswith('win'):
# # We must have the vfd_open, etc, functions on
......
/* markers for the CFFI parser. Replaced when the string is read. */
#define GEVENT_STRUCT_DONE int
#define GEVENT_ST_NLINK_T int
#define GEVENT_UV_OS_SOCK_T int
typedef enum {
UV_RUN_DEFAULT = 0,
......@@ -10,33 +11,91 @@ typedef enum {
enum uv_poll_event {
UV_READABLE = 1,
UV_WRITABLE = 2
UV_WRITABLE = 2,
/* new in 1.9
UV_DISCONNECT = 4
*/
};
enum uv_fs_event {
UV_RENAME = 1,
UV_CHANGE = 2
};
enum uv_fs_event_flags {
/*
* By default, if the fs event watcher is given a directory name, we will
* watch for all events in that directory. This flags overrides this behavior
* and makes fs_event report only changes to the directory entry itself. This
* flag does not affect individual files watched.
* This flag is currently not implemented yet on any backend.
*/
UV_FS_EVENT_WATCH_ENTRY = 1,
/*
* By default uv_fs_event will try to use a kernel interface such as inotify
* or kqueue to detect events. This may not work on remote filesystems such
* as NFS mounts. This flag makes fs_event fall back to calling stat() on a
* regular interval.
* This flag is currently not implemented yet on any backend.
*/
UV_FS_EVENT_STAT = 2,
/*
* By default, event watcher, when watching directory, is not registering
* (is ignoring) changes in it's subdirectories.
* This flag will override this behaviour on platforms that support it.
*/
UV_FS_EVENT_RECURSIVE = 4
};
// handle structs and types
struct uv_loop_s {
void* data;
GEVENT_STRUCT_DONE _;
};
struct uv_handle_s {
struct uv_loop_s* loop;
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_idle_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_prepare_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_timer_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_signal_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_poll_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_check_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_async_s {
void *data;
GEVENT_STRUCT_DONE _;
};
struct uv_fs_event_s {
void* data;
GEVENT_STRUCT_DONE _;
};
struct uv_fs_poll_s {
void* data;
GEVENT_STRUCT_DONE _;
};
......@@ -48,20 +107,62 @@ typedef struct uv_timer_s uv_timer_t;
typedef struct uv_signal_s uv_signal_t;
typedef struct uv_poll_s uv_poll_t;
typedef struct uv_check_s uv_check_t;
typedef struct uv_async_s uv_async_t;
typedef struct uv_fs_event_s uv_fs_event_t;
typedef struct uv_fs_poll_s uv_fs_poll_t;
typedef void (*uv_walk_cb)(uv_handle_t *handle, void *arg);
// callbacks with the same signature
typedef void (*uv_close_cb)(uv_handle_t *handle);
typedef void (*uv_idle_cb)(uv_idle_t *handle);
typedef void (*uv_timer_cb)(uv_timer_t *handle);
typedef void (*uv_check_cb)(uv_check_t* handle);
typedef void (*uv_async_cb)(uv_async_t* handle);
typedef void (*uv_prepare_cb)(uv_prepare_t *handle);
// callbacks with distinct sigs
typedef void (*uv_walk_cb)(uv_handle_t *handle, void *arg);
typedef void (*uv_poll_cb)(uv_poll_t *handle, int status, int events);
typedef void (*uv_timer_cb)(uv_timer_t *handle);
typedef void (*uv_signal_cb)(uv_signal_t *handle, int signum);
typedef void (*uv_check_cb)(uv_check_t* handle);
// Callback passed to uv_fs_event_start() which will be called
// repeatedly after the handle is started. If the handle was started
// with a directory the filename parameter will be a relative path to
// a file contained in the directory. The events parameter is an ORed
// mask of uv_fs_event elements.
typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status);
typedef struct {
long tv_sec;
long tv_nsec;
} uv_timespec_t;
typedef struct {
uint64_t st_dev;
uint64_t st_mode;
uint64_t st_nlink;
uint64_t st_uid;
uint64_t st_gid;
uint64_t st_rdev;
uint64_t st_ino;
uint64_t st_size;
uint64_t st_blksize;
uint64_t st_blocks;
uint64_t st_flags;
uint64_t st_gen;
uv_timespec_t st_atim;
uv_timespec_t st_mtim;
uv_timespec_t st_ctim;
uv_timespec_t st_birthtim;
} uv_stat_t;
typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr);
// loop functions
uv_loop_t *uv_default_loop();
int uv_loop_init(uv_loop_t* loop);
int uv_loop_alive(const uv_loop_t *loop);
int uv_loop_close(uv_loop_t* loop);
int uv_run(uv_loop_t *, uv_run_mode mode);
void uv_stop(uv_loop_t *);
void uv_walk(uv_loop_t *loop, uv_walk_cb walk_cb, void *arg);
......@@ -100,6 +201,12 @@ int uv_check_init(uv_loop_t *, uv_check_t *check);
int uv_check_start(uv_check_t *check, uv_check_cb cb);
int uv_check_stop(uv_check_t *check);
// async functions
// Async handles allow the user to “wakeup” the event loop and get a callback called from another thread.
int uv_async_init(uv_loop_t *, uv_async_t*, uv_async_cb);
int uv_async_send(uv_async_t*);
// timer functions
// Timer handles are used to schedule callbacks to be called in the future.
int uv_timer_init(uv_loop_t *, uv_timer_t *handle);
......@@ -116,25 +223,70 @@ int uv_signal_init(uv_loop_t *loop, uv_signal_t *handle);
int uv_signal_start(uv_signal_t *handle, uv_signal_cb signal_cb, int signum);
int uv_signal_stop(uv_signal_t *handle);
// poll functions
// Poll handles are used to watch file descriptors for readability and
// writability, similar to the purpose of poll(2). It is not okay to have
// multiple active poll handles for the same socket, this can cause libuv to
// busyloop or otherwise malfunction.
// poll functions Poll handles are used to watch file descriptors for
// readability and writability, similar to the purpose of poll(2). It
// is not okay to have multiple active poll handles for the same
// socket, this can cause libuv to busyloop or otherwise malfunction.
//
// The purpose of poll handles is to enable integrating external
// libraries that rely on the event loop to signal it about the socket
// status changes, like c-ares or libssh2. Using uv_poll_t for any
// other purpose is not recommended; uv_tcp_t, uv_udp_t, etc. provide
// an implementation that is faster and more scalable than what can be
// achieved with uv_poll_t, especially on Windows.
//
// Note On windows only sockets can be polled with poll handles. On
// Unix any file descriptor that would be accepted by poll(2) can be
// used.
int uv_poll_init(uv_loop_t *loop, uv_poll_t *handle, int fd);
// Initialize the handle using a socket descriptor. On Unix this is identical to uv_poll_init(). On windows it takes a SOCKET handle.
// The socket is set to non-blocking mode.
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, GEVENT_UV_OS_SOCK_T socket);
int uv_poll_start(uv_poll_t *handle, int events, uv_poll_cb cb);
int uv_poll_stop(uv_poll_t *handle);
// FS Event handles allow the user to monitor a given path for
// changes, for example, if the file was renamed or there was a
// generic change in it. This handle uses the best backend for the job
// on each platform.
//
// Thereas also uv_fs_poll_t that uses stat for filesystems where
// the kernel event isn't available.
int uv_fs_event_init(uv_loop_t*, uv_fs_event_t*);
int uv_fs_event_start(uv_fs_event_t*, uv_fs_event_cb, const char* path, unsigned int flags);
int uv_fs_event_stop(uv_fs_event_t*);
int uv_fs_event_getpath(uv_fs_event_t*, char* buffer, size_t* size);
// FS Poll handles allow the user to monitor a given path for changes.
// Unlike uv_fs_event_t, fs poll handles use stat to detect when a
// file has changed so they can work on file systems where fs event
// handles can’t.
//
// This is a closer match to libev.
int uv_fs_poll_init(uv_loop_t*, uv_fs_poll_t*);
int uv_fs_poll_start(uv_fs_poll_t*, uv_fs_poll_cb, const char* path, unsigned int);
int uv_fs_poll_stop(uv_fs_poll_t*);
/* gevent callbacks */
//static int (*python_callback)(void* handle, int revents);
//static void (*python_handle_error)(void* handle, int revents);
//static void (*python_stop)(void* handle);
//uv_handle_t *cast_handle(void *handle);
// variables that we fill in. In the case of poll callbacks and fs
// callbacks, if *status* is less than 0, it will be passed in the revents
// field. In cases of no extra arguments, revents will be 0.
static int (*python_callback)(void* handle, int revents);
static void (*python_handle_error)(void* handle, int revents);
static void (*python_stop)(void* handle);
/*
* We use a single C callback for every watcher type, which in turn calls the
* Python callbacks. The ev_watcher pointer type can be used for every watcher type
* because they all start with the same members---libev itself relies on this. Each
* We use a single C callback for every watcher type that shares the same signature, which in turn calls the
* Python callbacks. The uv_handle_t pointer type can be used for every watcher type
* because they all start with the same members---libuv itself relies on this. Each
* watcher types has a 'void* data' that stores the CFFI handle to the Python watcher
* object.
*/
//static void _gevent_generic_callback(struct ev_loop* loop, struct ev_watcher* watcher, int revents);
static void _gevent_generic_callback0(uv_handle_t* handle); // no extra args
static void _gevent_generic_callback1(uv_handle_t* handle, int arg); // one extra args. Everything will funnel through this
static void _gevent_poll_callback2(uv_handle_t* handle, int status, int events);
static void _gevent_fs_event_callback3(uv_handle_t* handle, const char* filename, int events, int status);
static void _gevent_fs_poll_callback3(uv_handle_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr);
#include <uv.h>
#include "uv.h"
static int (*python_callback)(void* handle, int revents);
static void (*python_handle_error)(void* handle, int revents);
static void (*python_stop)(void* handle);
static void _gevent_generic_callback1(uv_handle_t* watcher, int arg)
{
void* handle = watcher->data;
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 0:
// Code to stop the event. 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)) {
python_stop(handle);
}
break;
default:
assert(cb_result == 1);
// watcher is already stopped and dead, nothing to do.
}
}
static void _gevent_generic_callback0(uv_handle_t* handle)
{
_gevent_generic_callback1(handle, 0);
}
static void _gevent_poll_callback2(uv_handle_t* handle, int status, int events)
{
_gevent_generic_callback1(handle, status < 0 ? status : events);
}
static void _gevent_fs_event_callback3(uv_handle_t* handle, const char* filename, int events, int status)
{
_gevent_generic_callback1(handle, status < 0 ? status : events);
}
static void _gevent_fs_poll_callback3(uv_handle_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr)
{
// stat pointers are valid for this callback only.
// Will need a custom callback for this or somehow be able to pass
// copied data up.
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment