#include <algorithm>
#include <vector>
+#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
+
namespace netpoll {
struct pollfd {
void *assoc;
- SOCKET fd;
- int type;
+ uv_os_sock_t fd;
+ int type, revents, events;
+ bool dead;
+ uv_poll_t handle;
};
-#define NETPOLL_MAXFDS 1024
static std::vector<pollfd*> fds;
+static size_t lastptr = 0;
-#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
-struct polldata {
- uv_poll_t uv;
- int events, revents, fd, dead;
-};
-static polldata *uvpoll[NETPOLL_MAXFDS] = {};
static uv_loop_t *uvloop = 0;
-static size_t lastptr = 0;
-namespace uvalloc {
- static polldata uvpollbuf[NETPOLL_MAXFDS] = {};
- static polldata *freelist = 0;
- static polldata *get() {
- polldata *p = freelist;
- freelist = static_cast<polldata *>(p->uv.data);
- if (!p)
- abortf("uvalloc::get: out of polldata!\n");
- return p;
- }
- static void put(polldata *p) {
- p->uv.data = freelist;
- freelist = p;
- }
- static void init() {
- for (int i = NETPOLL_MAXFDS-1; i >= 0; i--)
- put(&uvpollbuf[i]);
- }
-}
void init(void)
{
- uvalloc::init();
uvloop = uv_default_loop();
}
void fini(void)
}
static void cb(uv_poll_t *handle, int status, int events)
{
- struct polldata *poll = container_of(handle, struct polldata, uv);
+ pollfd *pfd = container_of(handle, pollfd, handle);
if (status == 0) {
- poll->revents = events;
+ pfd->revents = events;
}
uv_poll_stop(handle);
if (status == -EBADF) {
- fprintf(stderr, "netpoll::cb: %d EBADF!\n", poll->fd);
- poll->dead = 1;
- poll->revents = poll->events & (UV_READABLE | UV_WRITABLE);
+ fprintf(stderr, "netpoll::cb: %d EBADF!\n", pfd->fd);
+ pfd->dead = true;
+ pfd->revents = pfd->events;
}
lastptr = 0;
}
void begin(void)
{
- for (size_t i = 0; i < fds.size(); i++) {
- if (uvpoll[i]->dead == 0) {
- uv_poll_start(&uvpoll[i]->uv, uvpoll[i]->events, cb);
- uvpoll[i]->revents = 0;
+ for (pollfd *pfd : fds) {
+ if (!pfd->dead) {
+ uv_poll_start(&pfd->handle, pfd->events, cb);
+ pfd->revents = 0;
} else {
- uvpoll[i]->revents = uvpoll[i]->events & (UV_READABLE | UV_WRITABLE);
+ pfd->revents = pfd->events;
+ lastptr = 0;
}
}
uv_run(uvloop, UV_RUN_ONCE);
}
bool get(event &out)
{
- while (lastptr != fds.size() && !uvpoll[lastptr]->revents) {
+ while (lastptr != fds.size() && !fds[lastptr]->revents) {
lastptr++;
}
if (lastptr == fds.size())
out.assoc = pfd->assoc;
out.fd = pfd->fd;
out.type = pfd->type;
- out.revents = uvpoll[lastptr]->revents;
+ out.revents = pfd->revents;
lastptr++;
return true;
}
-static size_t search(SOCKET fd, bool add) {
+static std::vector<pollfd*>::iterator search(uv_os_sock_t fd, bool add=false)
+{
if (fd == INVALID_SOCKET)
abortf("netpoll::search: INVALID_SOCKET\n");
auto it = std::partition_point(fds.begin(), fds.end(), [fd](const auto &p){ return p->fd < fd; });
if (found == add)
abortf("netpoll::search: duplicate or missing socket\n");
if (add) {
- if (fds.size() == NETPOLL_MAXFDS)
- abortf("netpoll::add: NETPOLL_MAXFDS limit\n");
+ lastptr += int(lastptr >= size_t(it - fds.begin()));
it = fds.insert(it, new pollfd());
(*it)->fd = fd;
}
- return it - fds.begin();
+ return it;
}
-void add(SOCKET fd, int type, void *assoc)
+void add(uv_os_sock_t fd, int type, void *assoc)
{
- size_t i = search(fd, true);
- fds[i]->assoc = assoc;
- fds[i]->type = type;
- struct polldata *poll = uvalloc::get();
- memmove(uvpoll+i+1, uvpoll+i, sizeof(uvpoll[0])*(fds.size()-1-i));
- uvpoll[i] = poll;
- poll->events = 0;
- poll->revents = 0;
- poll->fd = fds[i]->fd;
- poll->dead = 0;
- uv_poll_init_socket(uvloop, &poll->uv, fds[i]->fd);
- if (lastptr >= i)
- lastptr++;
+ pollfd *pfd = *search(fd, true);
+ pfd->assoc = assoc;
+ pfd->type = type;
+ uv_poll_init_socket(uvloop, &pfd->handle, pfd->fd);
}
-void del_and_close(SOCKET fd)
+void del_and_close(uv_os_sock_t fd)
{
- size_t i = search(fd, false);
- uvpoll[i]->events = 0;
- struct polldata *poll = uvpoll[i];
- memmove(uvpoll+i, uvpoll+i+1, sizeof(uvpoll[0])*(fds.size()-(i+1)));
- uv_close((uv_handle_t *)&poll->uv, [](uv_handle_t *handle){
- struct polldata *p = container_of(handle, struct polldata, uv);
- closesocket(p->fd);
- uvalloc::put(p);
+ auto it = search(fd);
+ pollfd *pfd = *it;
+ uv_close((uv_handle_t *)&pfd->handle, [](uv_handle_t *handle){
+ pollfd *pfd = container_of(handle, pollfd, handle);
+ closesocket(pfd->fd);
+ delete pfd;
});
- if (lastptr > i)
- lastptr--;
- delete fds[i];
- fds.erase(fds.begin()+i);
+ lastptr -= int(lastptr > size_t(it - fds.begin()));
+ it = fds.erase(it);
}
-void reg(SOCKET fd, int ev)
+void reg(uv_os_sock_t fd, int ev)
{
- uvpoll[search(fd, false)]->events = ev & (UV_READABLE | UV_WRITABLE);
+ pollfd *pfd = *search(fd);
+ pfd->events = ev & (UV_READABLE | UV_WRITABLE);
}
-void change_type(SOCKET fd, int type)
+void change_type(uv_os_sock_t fd, int type)
{
- fds[search(fd, false)]->type = type;
+ pollfd *pfd = *search(fd);
+ pfd->type = type;
}
}