138 lines
3.0 KiB
C
138 lines
3.0 KiB
C
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "api.h"
|
|
#include "error.h"
|
|
#include "init.h"
|
|
#include "port.h"
|
|
#include "reflock-tree.h"
|
|
#include "util.h"
|
|
#include "win.h"
|
|
|
|
static reflock_tree_t _epoll_handle_tree;
|
|
|
|
static inline ep_port_t* _handle_tree_node_to_port(
|
|
reflock_tree_node_t* tree_node) {
|
|
return container_of(tree_node, ep_port_t, handle_tree_node);
|
|
}
|
|
|
|
int api_global_init(void) {
|
|
reflock_tree_init(&_epoll_handle_tree);
|
|
return 0;
|
|
}
|
|
|
|
static HANDLE _epoll_create(void) {
|
|
ep_port_t* port_info;
|
|
HANDLE ephnd;
|
|
|
|
if (init() < 0)
|
|
return NULL;
|
|
|
|
port_info = ep_port_new(&ephnd);
|
|
if (port_info == NULL)
|
|
return NULL;
|
|
|
|
if (reflock_tree_add(&_epoll_handle_tree,
|
|
&port_info->handle_tree_node,
|
|
(uintptr_t) ephnd) < 0) {
|
|
/* This should never happen. */
|
|
ep_port_delete(port_info);
|
|
return_error(NULL, ERROR_ALREADY_EXISTS);
|
|
}
|
|
|
|
return ephnd;
|
|
}
|
|
|
|
HANDLE epoll_create(int size) {
|
|
if (size <= 0)
|
|
return_error(NULL, ERROR_INVALID_PARAMETER);
|
|
|
|
return _epoll_create();
|
|
}
|
|
|
|
HANDLE epoll_create1(int flags) {
|
|
if (flags != 0)
|
|
return_error(NULL, ERROR_INVALID_PARAMETER);
|
|
|
|
return _epoll_create();
|
|
}
|
|
|
|
int epoll_close(HANDLE ephnd) {
|
|
reflock_tree_node_t* tree_node;
|
|
ep_port_t* port_info;
|
|
|
|
if (init() < 0)
|
|
return -1;
|
|
|
|
tree_node = reflock_tree_del_and_ref(&_epoll_handle_tree, (uintptr_t) ephnd);
|
|
if (tree_node == NULL)
|
|
return_handle_error(-1, ephnd, ERROR_INVALID_PARAMETER);
|
|
port_info = _handle_tree_node_to_port(tree_node);
|
|
|
|
ep_port_close(port_info);
|
|
|
|
reflock_tree_node_unref_and_destroy(tree_node);
|
|
|
|
return ep_port_delete(port_info);
|
|
}
|
|
|
|
int epoll_ctl(HANDLE ephnd, int op, SOCKET sock, struct epoll_event* ev) {
|
|
reflock_tree_node_t* tree_node;
|
|
ep_port_t* port_info;
|
|
int r;
|
|
|
|
if (init() < 0)
|
|
return -1;
|
|
|
|
tree_node =
|
|
reflock_tree_find_and_ref(&_epoll_handle_tree, (uintptr_t) ephnd);
|
|
if (tree_node == NULL) {
|
|
err_set_win_error(ERROR_INVALID_PARAMETER);
|
|
goto err;
|
|
}
|
|
|
|
port_info = _handle_tree_node_to_port(tree_node);
|
|
r = ep_port_ctl(port_info, op, sock, ev);
|
|
|
|
reflock_tree_node_unref(tree_node);
|
|
|
|
if (r < 0)
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
/* On Linux, in the case of epoll_ctl_mod(), EBADF takes precendence over
|
|
* other errors. Wepoll copies this behavior. */
|
|
err_check_handle(ephnd);
|
|
err_check_handle((HANDLE) sock);
|
|
return -1;
|
|
}
|
|
|
|
int epoll_wait(HANDLE ephnd,
|
|
struct epoll_event* events,
|
|
int maxevents,
|
|
int timeout) {
|
|
reflock_tree_node_t* tree_node;
|
|
ep_port_t* port_info;
|
|
int result;
|
|
|
|
if (maxevents <= 0)
|
|
return_error(-1, ERROR_INVALID_PARAMETER);
|
|
|
|
if (init() < 0)
|
|
return -1;
|
|
|
|
tree_node =
|
|
reflock_tree_find_and_ref(&_epoll_handle_tree, (uintptr_t) ephnd);
|
|
if (tree_node == NULL)
|
|
return_handle_error(-1, ephnd, ERROR_INVALID_PARAMETER);
|
|
port_info = _handle_tree_node_to_port(tree_node);
|
|
|
|
result = ep_port_wait(port_info, events, maxevents, timeout);
|
|
|
|
reflock_tree_node_unref(tree_node);
|
|
|
|
return result;
|
|
}
|