mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
243 lines
4.7 KiB
C
243 lines
4.7 KiB
C
#include "upoll_sun.h"
|
|
|
|
#define uhash_slot(K, S) (((K) ^ (K >> 8)) & (S - 1))
|
|
|
|
static uhash_t*
|
|
uhash_create(uint32_t size)
|
|
{
|
|
int i;
|
|
size--;
|
|
size |= size >> 1;
|
|
size |= size >> 2;
|
|
size |= size >> 4;
|
|
size |= size >> 8;
|
|
size |= size >> 16;
|
|
size++;
|
|
|
|
uhash_t* hash = (uhash_t*)calloc(1, sizeof(uhash_t) + size * sizeof(ulist_t));
|
|
hash->count = 0;
|
|
hash->size = size;
|
|
hash->items = (ulist_t*)(((char*)hash) + sizeof(uhash_t));
|
|
|
|
for(i = 0; i < size; i++)
|
|
{
|
|
ulist_init(&hash->items[i]);
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
static void*
|
|
uhash_lookup(uhash_t* hash, intptr_t key)
|
|
{
|
|
uint32_t slot = uhash_slot(key, hash->size);
|
|
ulist_t* q;
|
|
ulist_scan(q, &hash->items[slot])
|
|
{
|
|
uitem_t* i = ulist_data(q, uitem_t, list);
|
|
if(i->key == key)
|
|
return i->val;
|
|
}
|
|
return NULL;
|
|
}
|
|
static void
|
|
uhash_insert(uhash_t* hash, intptr_t key, void* val)
|
|
{
|
|
uint32_t slot = uhash_slot(key, hash->size);
|
|
|
|
uitem_t* item = (uitem_t*)calloc(1, sizeof(uitem_t));
|
|
ulist_init(&item->list);
|
|
item->key = key;
|
|
item->val = val;
|
|
|
|
ulist_append(&hash->items[slot], &item->list);
|
|
}
|
|
static int
|
|
uhash_delete(uhash_t* hash, intptr_t key)
|
|
{
|
|
uint32_t slot = uhash_slot(key, hash->size);
|
|
ulist_t* q;
|
|
ulist_scan(q, &hash->items[slot])
|
|
{
|
|
uitem_t* i = ulist_data(q, uitem_t, list);
|
|
if(i->key == key)
|
|
{
|
|
ulist_remove(q);
|
|
free(q);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
static int
|
|
uhash_destroy(uhash_t* hash)
|
|
{
|
|
int i;
|
|
for(i = 0; i < hash->size; i++)
|
|
{
|
|
while(!ulist_empty(&hash->items[i]))
|
|
{
|
|
ulist_t* q = ulist_next(&hash->items[i]);
|
|
uitem_t* n = ulist_data(q, uitem_t, list);
|
|
ulist_remove(q);
|
|
free(n);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
upoll_t*
|
|
upoll_create(uint32_t size)
|
|
{
|
|
assert(size > 0);
|
|
upoll_t* upq = (upoll_t*)calloc(1, sizeof(upoll_t));
|
|
|
|
ulist_init(&upq->alive);
|
|
|
|
upq->table = uhash_create(size);
|
|
return upq;
|
|
}
|
|
|
|
void
|
|
upoll_destroy(upoll_t* upq)
|
|
{
|
|
assert(upq != NULL);
|
|
uhash_destroy(upq->table);
|
|
ulist_t* q;
|
|
unote_t* n;
|
|
while(!ulist_empty(&upq->alive))
|
|
{
|
|
q = ulist_next(&upq->alive);
|
|
n = ulist_data(n, unote_t, queue);
|
|
ulist_remove(q);
|
|
free(n);
|
|
}
|
|
free(upq);
|
|
}
|
|
|
|
int
|
|
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event)
|
|
{
|
|
if(fd < 0)
|
|
return -EBADF;
|
|
|
|
unote_t* note = NULL;
|
|
switch(op)
|
|
{
|
|
case UPOLL_CTL_ADD:
|
|
{
|
|
note = (unote_t*)uhash_lookup(upq->table, fd);
|
|
if(!note)
|
|
{
|
|
note = (unote_t*)calloc(1, sizeof(unote_t));
|
|
note->upoll = upq;
|
|
ulist_init(¬e->queue);
|
|
note->event = *event;
|
|
note->fd = fd;
|
|
ulist_append(&upq->alive, ¬e->queue);
|
|
uhash_insert(upq->table, fd, (void*)note);
|
|
}
|
|
break;
|
|
}
|
|
case UPOLL_CTL_DEL:
|
|
{
|
|
note = (unote_t*)uhash_lookup(upq->table, fd);
|
|
if(!note)
|
|
return -ENOENT;
|
|
event = ¬e->event;
|
|
ulist_remove(¬e->queue);
|
|
uhash_delete(upq->table, fd);
|
|
free(note);
|
|
break;
|
|
}
|
|
case UPOLL_CTL_MOD:
|
|
{
|
|
note = (unote_t*)uhash_lookup(upq->table, fd);
|
|
if(!note)
|
|
return -ENOENT;
|
|
note->event = *event;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
upoll_wait_poll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
|
|
{
|
|
/* FD_SETSIZE should be smaller than OPEN_MAX, but OPEN_MAX isn't portable */
|
|
if(nev > FD_SETSIZE)
|
|
nev = FD_SETSIZE;
|
|
|
|
unote_t* nvec[nev];
|
|
int r, i, nfds = 0;
|
|
uint32_t hint;
|
|
struct pollfd pfds[nev];
|
|
|
|
unote_t* n = NULL;
|
|
ulist_t* s = ulist_mark(&upq->alive);
|
|
ulist_t* q = ulist_next(&upq->alive);
|
|
|
|
while(q != s && nfds < nev)
|
|
{
|
|
n = ulist_data(q, unote_t, queue);
|
|
q = ulist_next(q);
|
|
|
|
ulist_remove(&n->queue);
|
|
ulist_insert(&upq->alive, &n->queue);
|
|
|
|
nvec[nfds] = n;
|
|
pfds[nfds].events = 0;
|
|
pfds[nfds].fd = n->fd;
|
|
if(n->event.events & UPOLLIN)
|
|
{
|
|
pfds[nfds].events |= POLLIN;
|
|
}
|
|
if(n->event.events & UPOLLOUT)
|
|
{
|
|
pfds[nfds].events |= POLLOUT;
|
|
}
|
|
nfds++;
|
|
}
|
|
|
|
r = poll(pfds, nfds, timeout);
|
|
if(r < 0)
|
|
return -errno;
|
|
|
|
int e = 0;
|
|
for(i = 0; i < nfds && e < nev; i++)
|
|
{
|
|
hint = 0;
|
|
if(pfds[i].revents)
|
|
{
|
|
n = nvec[i];
|
|
if(pfds[i].revents & POLLIN)
|
|
hint |= UPOLLIN;
|
|
if(pfds[i].revents & POLLOUT)
|
|
hint |= UPOLLOUT;
|
|
if(pfds[i].revents & (POLLERR | POLLNVAL | POLLHUP))
|
|
hint |= (UPOLLERR | UPOLLIN);
|
|
|
|
if(hint & UPOLLERR)
|
|
hint &= ~UPOLLOUT;
|
|
|
|
evs[e].data = n->event.data;
|
|
evs[e].events = hint;
|
|
++e;
|
|
}
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
int
|
|
upoll_wait(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
|
|
{
|
|
int r = 0;
|
|
r = upoll_wait_poll(upq, evs, nev, timeout);
|
|
return r;
|
|
} |