|
|
@ -6,11 +6,13 @@ |
|
|
|
#include <stdint.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
#include "list.h" |
|
|
|
#include "linked_list.h" |
|
|
|
#include "poller.h" |
|
|
|
|
|
|
|
struct event_source_fd { |
|
|
|
struct linked_list link; // poller::fds
|
|
|
|
const struct event_source_fd_impl *impl; |
|
|
|
event_source_fd_func_t func; |
|
|
|
|
|
|
@ -20,9 +22,11 @@ struct event_source_fd { |
|
|
|
|
|
|
|
struct poller *poller; |
|
|
|
bool killed; |
|
|
|
ssize_t pollfd_idx; |
|
|
|
}; |
|
|
|
|
|
|
|
struct event_source_signal { |
|
|
|
struct linked_list link; // poller::signals
|
|
|
|
const struct event_source_signal_impl *impl; |
|
|
|
event_source_signal_func_t func; |
|
|
|
|
|
|
@ -40,38 +44,21 @@ struct poller *global_poller = NULL; |
|
|
|
void poller_init(struct poller *poller) { |
|
|
|
assert(global_poller == NULL); |
|
|
|
|
|
|
|
list_init(&poller->fds); |
|
|
|
list_init(&poller->new_fds); |
|
|
|
list_init(&poller->signals); |
|
|
|
list_init(&poller->new_signals); |
|
|
|
linked_list_init(&poller->fds); |
|
|
|
linked_list_init(&poller->signals); |
|
|
|
poller->pollfds = NULL; |
|
|
|
poller->pollfds_len = 0; |
|
|
|
poller->fd_event_sources = 0; |
|
|
|
global_poller = poller; |
|
|
|
} |
|
|
|
|
|
|
|
int poller_finish(struct poller *poller) { |
|
|
|
for (size_t idx = 0; idx < poller->fds.length; idx++) { |
|
|
|
struct event_source_fd *bpfd = poller->fds.items[idx]; |
|
|
|
while (!linked_list_empty(&poller->fds)) { |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)poller->fds.next; |
|
|
|
free(bpfd); |
|
|
|
} |
|
|
|
list_free(&poller->fds); |
|
|
|
for (size_t idx = 0; idx < poller->new_fds.length; idx++) { |
|
|
|
struct event_source_fd *bpfd = poller->new_fds.items[idx]; |
|
|
|
free(bpfd); |
|
|
|
} |
|
|
|
list_free(&poller->new_fds); |
|
|
|
for (size_t idx = 0; idx < poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = poller->signals.items[idx]; |
|
|
|
|
|
|
|
struct sigaction sa; |
|
|
|
sa.sa_handler = SIG_DFL; |
|
|
|
sigemptyset(&sa.sa_mask); |
|
|
|
sa.sa_flags = 0; |
|
|
|
sigaction(bps->signal, &sa, NULL); |
|
|
|
|
|
|
|
free(bps); |
|
|
|
} |
|
|
|
list_free(&poller->signals); |
|
|
|
for (size_t idx = 0; idx < poller->new_signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = poller->new_signals.items[idx]; |
|
|
|
while (!linked_list_empty(&poller->signals)) { |
|
|
|
struct event_source_signal *bps = (struct event_source_signal *)poller->signals.next; |
|
|
|
|
|
|
|
struct sigaction sa; |
|
|
|
sa.sa_handler = SIG_DFL; |
|
|
@ -81,7 +68,6 @@ int poller_finish(struct poller *poller) { |
|
|
|
|
|
|
|
free(bps); |
|
|
|
} |
|
|
|
list_free(&poller->new_signals); |
|
|
|
free(poller->pollfds); |
|
|
|
return 0; |
|
|
|
} |
|
|
@ -115,24 +101,31 @@ static uint32_t poll_mask_to_event_mask(int poll_mask) { |
|
|
|
} |
|
|
|
|
|
|
|
static int regenerate_pollfds(struct poller *poller) { |
|
|
|
if (poller->pollfds_len != poller->fds.length) { |
|
|
|
struct pollfd *fds = calloc(poller->fds.length, sizeof(struct pollfd)); |
|
|
|
if (!poller->pollfds_dirty) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (poller->fd_event_sources > poller->pollfds_len) { |
|
|
|
struct pollfd *fds = calloc(poller->fd_event_sources, sizeof(struct pollfd)); |
|
|
|
if (fds == NULL) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
free(poller->pollfds); |
|
|
|
poller->pollfds = fds; |
|
|
|
poller->pollfds_len = poller->fds.length; |
|
|
|
poller->pollfds_len = poller->fd_event_sources; |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < poller->fds.length; idx++) { |
|
|
|
struct event_source_fd *bpfd = poller->fds.items[idx]; |
|
|
|
poller->pollfds[idx] = (struct pollfd){ |
|
|
|
ssize_t idx = 0; |
|
|
|
for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)elem; |
|
|
|
bpfd->pollfd_idx = idx++; |
|
|
|
poller->pollfds[bpfd->pollfd_idx] = (struct pollfd){ |
|
|
|
.fd = bpfd->fd, |
|
|
|
.events = event_mask_to_poll_mask(bpfd->mask), |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
poller->pollfds_dirty = false; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -147,31 +140,19 @@ struct event_source_fd *poller_add_fd(struct poller *poller, int fd, uint32_t ma |
|
|
|
bpfd->data = data; |
|
|
|
bpfd->func = func; |
|
|
|
bpfd->poller = poller; |
|
|
|
poller->dirty = true; |
|
|
|
if (poller->inpoll) { |
|
|
|
list_add(&poller->new_fds, bpfd); |
|
|
|
} else { |
|
|
|
list_add(&poller->fds, bpfd); |
|
|
|
regenerate_pollfds(poller); |
|
|
|
} |
|
|
|
bpfd->pollfd_idx = -1; |
|
|
|
poller->fd_event_sources += 1; |
|
|
|
poller->pollfds_dirty = true; |
|
|
|
linked_list_insert(&poller->fds, &bpfd->link); |
|
|
|
return (struct event_source_fd *)bpfd; |
|
|
|
} |
|
|
|
|
|
|
|
int event_source_fd_destroy(struct event_source_fd *event_source) { |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)event_source; |
|
|
|
struct poller *poller = bpfd->poller; |
|
|
|
int idx = list_find(&poller->fds, event_source); |
|
|
|
if (idx == -1) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
poller->dirty = true; |
|
|
|
if (poller->inpoll) { |
|
|
|
bpfd->killed = true; |
|
|
|
} else { |
|
|
|
list_del(&poller->fds, idx); |
|
|
|
free(bpfd); |
|
|
|
regenerate_pollfds(poller); |
|
|
|
} |
|
|
|
poller->fd_event_sources -= 1; |
|
|
|
poller->pollfds_dirty = true; |
|
|
|
bpfd->killed = true; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -179,11 +160,7 @@ int event_source_fd_update(struct event_source_fd *event_source, uint32_t mask) |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)event_source; |
|
|
|
struct poller *poller = bpfd->poller; |
|
|
|
event_source->mask = mask; |
|
|
|
|
|
|
|
poller->dirty = true; |
|
|
|
if (!poller->inpoll) { |
|
|
|
regenerate_pollfds(poller); |
|
|
|
} |
|
|
|
poller->pollfds_dirty = true; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -191,9 +168,9 @@ static void signal_handler(int sig) { |
|
|
|
if (global_poller == NULL) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < global_poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = global_poller->signals.items[idx]; |
|
|
|
for (struct linked_list *elem = global_poller->signals.next; |
|
|
|
elem != &global_poller->signals; elem = elem->next) { |
|
|
|
struct event_source_signal *bps = (struct event_source_signal *)elem; |
|
|
|
if (bps->signal == sig) { |
|
|
|
bps->raised = true; |
|
|
|
} |
|
|
@ -208,32 +185,18 @@ struct event_source_signal *poller_add_signal(struct poller *poller, int signal, |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
int refcnt = 0; |
|
|
|
for (size_t idx = 0; idx < poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = poller->signals.items[idx]; |
|
|
|
if (bps->signal == signal) { |
|
|
|
refcnt++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bps->signal = signal; |
|
|
|
bps->data = data; |
|
|
|
bps->func = func; |
|
|
|
bps->poller = poller; |
|
|
|
|
|
|
|
if (refcnt == 0) { |
|
|
|
struct sigaction sa; |
|
|
|
sa.sa_handler = &signal_handler; |
|
|
|
sigemptyset(&sa.sa_mask); |
|
|
|
sa.sa_flags = 0; |
|
|
|
sigaction(signal, &sa, NULL); |
|
|
|
} |
|
|
|
struct sigaction sa; |
|
|
|
sa.sa_handler = &signal_handler; |
|
|
|
sigemptyset(&sa.sa_mask); |
|
|
|
sa.sa_flags = 0; |
|
|
|
sigaction(signal, &sa, NULL); |
|
|
|
|
|
|
|
if (poller->inpoll) { |
|
|
|
list_add(&poller->new_signals, bps); |
|
|
|
} else { |
|
|
|
list_add(&poller->signals, bps); |
|
|
|
} |
|
|
|
linked_list_insert(&poller->signals, &bps->link); |
|
|
|
|
|
|
|
return (struct event_source_signal *)bps; |
|
|
|
} |
|
|
@ -242,15 +205,11 @@ int event_source_signal_destroy(struct event_source_signal *event_source) { |
|
|
|
struct event_source_signal *bps = (struct event_source_signal *)event_source; |
|
|
|
struct poller *poller = bps->poller; |
|
|
|
|
|
|
|
int idx = list_find(&poller->signals, event_source); |
|
|
|
if (idx == -1) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
int refcnt = 0; |
|
|
|
for (size_t idx = 0; idx < poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *b = poller->signals.items[idx]; |
|
|
|
if (b->signal == bps->signal) { |
|
|
|
for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; |
|
|
|
elem = elem->next) { |
|
|
|
struct event_source_signal *b = (struct event_source_signal *)elem; |
|
|
|
if (b->signal == bps->signal && !b->killed) { |
|
|
|
refcnt++; |
|
|
|
} |
|
|
|
} |
|
|
@ -263,77 +222,63 @@ int event_source_signal_destroy(struct event_source_signal *event_source) { |
|
|
|
sigaction(bps->signal, &sa, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
if (poller->inpoll) { |
|
|
|
bps->killed = true; |
|
|
|
} else { |
|
|
|
list_del(&poller->signals, idx); |
|
|
|
free(bps); |
|
|
|
} |
|
|
|
bps->killed = true; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int poller_poll(struct poller *poller) { |
|
|
|
if (poll(poller->pollfds, poller->fds.length, -1) == -1 && errno != EINTR) { |
|
|
|
if (regenerate_pollfds(poller) == -1) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
poller->inpoll = true; |
|
|
|
if (poll(poller->pollfds, poller->fd_event_sources, -1) == -1 && errno != EINTR) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < poller->fds.length; idx++) { |
|
|
|
short revents = poller->pollfds[idx].revents; |
|
|
|
for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)elem; |
|
|
|
if (bpfd->pollfd_idx == -1 || bpfd->killed) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
short revents = poller->pollfds[bpfd->pollfd_idx].revents; |
|
|
|
if (revents == 0) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
struct event_source_fd *bpfd = poller->fds.items[idx]; |
|
|
|
bpfd->func(poller->pollfds[idx].fd, poll_mask_to_event_mask(revents), bpfd->data); |
|
|
|
bpfd->func(poller->pollfds[bpfd->pollfd_idx].fd, poll_mask_to_event_mask(revents), |
|
|
|
bpfd->data); |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = poller->signals.items[idx]; |
|
|
|
if (!bps->raised) { |
|
|
|
for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; |
|
|
|
elem = elem->next) { |
|
|
|
struct event_source_signal *bps = (struct event_source_signal *)elem; |
|
|
|
if (!bps->raised || bps->killed) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
bps->func(bps->signal, bps->data); |
|
|
|
bps->raised = false; |
|
|
|
} |
|
|
|
|
|
|
|
poller->inpoll = false; |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < poller->fds.length; idx++) { |
|
|
|
struct event_source_fd *bpfd = poller->fds.items[idx]; |
|
|
|
for (struct linked_list *elem = poller->fds.next; elem != &poller->fds; elem = elem->next) { |
|
|
|
struct event_source_fd *bpfd = (struct event_source_fd *)elem; |
|
|
|
if (!bpfd->killed) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
list_del(&poller->fds, idx); |
|
|
|
elem = elem->prev; |
|
|
|
linked_list_remove(&bpfd->link); |
|
|
|
free(bpfd); |
|
|
|
idx--; |
|
|
|
} |
|
|
|
|
|
|
|
for (size_t idx = 0; idx < poller->signals.length; idx++) { |
|
|
|
struct event_source_signal *bps = poller->signals.items[idx]; |
|
|
|
for (struct linked_list *elem = poller->signals.next; elem != &poller->signals; |
|
|
|
elem = elem->next) { |
|
|
|
struct event_source_signal *bps = (struct event_source_signal *)elem; |
|
|
|
if (!bps->killed) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
list_del(&poller->signals, idx); |
|
|
|
elem = elem->prev; |
|
|
|
linked_list_remove(&bps->link); |
|
|
|
free(bps); |
|
|
|
idx--; |
|
|
|
} |
|
|
|
|
|
|
|
if (poller->new_fds.length > 0) { |
|
|
|
list_concat(&poller->fds, &poller->new_fds); |
|
|
|
list_truncate(&poller->new_fds); |
|
|
|
} |
|
|
|
|
|
|
|
if (poller->new_signals.length > 0) { |
|
|
|
list_concat(&poller->signals, &poller->new_signals); |
|
|
|
list_truncate(&poller->new_signals); |
|
|
|
} |
|
|
|
|
|
|
|
if (poller->dirty) { |
|
|
|
regenerate_pollfds(poller); |
|
|
|
poller->dirty = false; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|