261 lines
5.6 KiB
C
261 lines
5.6 KiB
C
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
|
|
#define __USE_GNU
|
|
#include <fcntl.h>
|
|
|
|
#include "fdevent.h"
|
|
#include "settings.h"
|
|
#include "buffer.h"
|
|
|
|
#ifdef USE_LINUX_SIGIO
|
|
static void fdevent_linux_rtsig_free(fdevents *ev) {
|
|
free(ev->pollfds);
|
|
if (ev->unused.ptr) free(ev->unused.ptr);
|
|
|
|
bitset_free(ev->sigbset);
|
|
}
|
|
|
|
|
|
static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
|
|
if (fde_ndx < 0) return -1;
|
|
|
|
if ((size_t)fde_ndx >= ev->used) {
|
|
fprintf(stderr, "%s.%d: del! out of range %d %u\n", __FILE__, __LINE__, fde_ndx, ev->used);
|
|
SEGFAULT();
|
|
}
|
|
|
|
if (ev->pollfds[fde_ndx].fd == fd) {
|
|
size_t k = fde_ndx;
|
|
|
|
ev->pollfds[k].fd = -1;
|
|
|
|
bitset_clear_bit(ev->sigbset, fd);
|
|
|
|
if (ev->unused.size == 0) {
|
|
ev->unused.size = 16;
|
|
ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
|
|
} else if (ev->unused.size == ev->unused.used) {
|
|
ev->unused.size += 16;
|
|
ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
|
|
}
|
|
|
|
ev->unused.ptr[ev->unused.used++] = k;
|
|
} else {
|
|
fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
|
|
|
|
SEGFAULT();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
#if 0
|
|
static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
|
|
size_t j;
|
|
|
|
if (ev->used == 0) return 0;
|
|
if (ev->unused.used != 0) return 0;
|
|
|
|
for (j = ev->used - 1; j + 1 > 0; j--) {
|
|
if (ev->pollfds[j].fd == -1) ev->used--;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
|
|
/* known index */
|
|
if (fde_ndx != -1) {
|
|
if (ev->pollfds[fde_ndx].fd == fd) {
|
|
ev->pollfds[fde_ndx].events = events;
|
|
|
|
return fde_ndx;
|
|
}
|
|
fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
|
|
SEGFAULT();
|
|
}
|
|
|
|
if (ev->unused.used > 0) {
|
|
int k = ev->unused.ptr[--ev->unused.used];
|
|
|
|
ev->pollfds[k].fd = fd;
|
|
ev->pollfds[k].events = events;
|
|
|
|
bitset_set_bit(ev->sigbset, fd);
|
|
|
|
return k;
|
|
} else {
|
|
if (ev->size == 0) {
|
|
ev->size = 16;
|
|
ev->pollfds = malloc(sizeof(*ev->pollfds) * ev->size);
|
|
} else if (ev->size == ev->used) {
|
|
ev->size += 16;
|
|
ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
|
|
}
|
|
|
|
ev->pollfds[ev->used].fd = fd;
|
|
ev->pollfds[ev->used].events = events;
|
|
|
|
bitset_set_bit(ev->sigbset, fd);
|
|
|
|
return ev->used++;
|
|
}
|
|
}
|
|
|
|
static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
|
|
struct timespec ts;
|
|
int r;
|
|
|
|
#if 0
|
|
fdevent_linux_rtsig_event_compress(ev);
|
|
#endif
|
|
|
|
ev->in_sigio = 1;
|
|
|
|
ts.tv_sec = timeout_ms / 1000;
|
|
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
|
|
r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
|
|
|
|
if (r == -1) {
|
|
if (errno == EAGAIN) return 0;
|
|
return r;
|
|
} else if (r == SIGIO) {
|
|
struct sigaction act;
|
|
|
|
/* flush the signal queue */
|
|
memset(&act, 0, sizeof(act));
|
|
act.sa_handler = SIG_IGN;
|
|
sigaction(ev->signum, &act, NULL);
|
|
|
|
/* re-enable the signal queue */
|
|
act.sa_handler = SIG_DFL;
|
|
sigaction(ev->signum, &act, NULL);
|
|
|
|
ev->in_sigio = 0;
|
|
r = poll(ev->pollfds, ev->used, timeout_ms);
|
|
|
|
return r;
|
|
} else if (r == ev->signum) {
|
|
# if 0
|
|
fprintf(stderr, "event: %d %02lx\n", ev->siginfo.si_fd, ev->siginfo.si_band);
|
|
# endif
|
|
return bitset_test_bit(ev->sigbset, ev->siginfo.si_fd);
|
|
} else {
|
|
/* ? */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
|
|
if (ev->in_sigio == 1) {
|
|
# if 0
|
|
if (ev->siginfo.si_band == POLLERR) {
|
|
fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
|
|
}
|
|
# endif
|
|
if (ndx != 0) {
|
|
fprintf(stderr, "+\n");
|
|
return 0;
|
|
}
|
|
|
|
return ev->siginfo.si_band & 0x3f;
|
|
} else {
|
|
if (ndx >= ev->used) {
|
|
fprintf(stderr, "%s.%d: event: %u %u\n", __FILE__, __LINE__, ndx, ev->used);
|
|
return 0;
|
|
}
|
|
return ev->pollfds[ndx].revents;
|
|
}
|
|
}
|
|
|
|
static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
|
|
if (ev->in_sigio == 1) {
|
|
return ev->siginfo.si_fd;
|
|
} else {
|
|
return ev->pollfds[ndx].fd;
|
|
}
|
|
}
|
|
|
|
static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
|
|
static pid_t pid = 0;
|
|
|
|
if (pid == 0) pid = getpid();
|
|
|
|
if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
|
|
|
|
if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
|
|
|
|
return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
|
|
}
|
|
|
|
|
|
static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
|
|
if (ev->in_sigio == 1) {
|
|
if (ndx < 0) return 0;
|
|
return -1;
|
|
} else {
|
|
size_t i;
|
|
|
|
i = (ndx < 0) ? 0 : ndx + 1;
|
|
for (; i < ev->used; i++) {
|
|
if (ev->pollfds[i].revents) break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
int fdevent_linux_rtsig_init(fdevents *ev) {
|
|
ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
|
|
#define SET(x) \
|
|
ev->x = fdevent_linux_rtsig_##x;
|
|
|
|
SET(free);
|
|
SET(poll);
|
|
|
|
SET(event_del);
|
|
SET(event_add);
|
|
|
|
SET(event_next_fdndx);
|
|
SET(fcntl_set);
|
|
SET(event_get_fd);
|
|
SET(event_get_revent);
|
|
|
|
ev->signum = SIGRTMIN + 1;
|
|
|
|
sigemptyset(&(ev->sigset));
|
|
sigaddset(&(ev->sigset), ev->signum);
|
|
sigaddset(&(ev->sigset), SIGIO);
|
|
if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
|
|
fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
|
|
__FILE__, __LINE__, strerror(errno));
|
|
|
|
return -1;
|
|
}
|
|
|
|
ev->in_sigio = 1;
|
|
|
|
ev->sigbset = bitset_init(ev->maxfds);
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
int fdevent_linux_rtsig_init(fdevents *ev) {
|
|
UNUSED(ev);
|
|
|
|
fprintf(stderr, "%s.%d: linux-rtsig not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
|
|
__FILE__, __LINE__);
|
|
return -1;
|
|
}
|
|
#endif
|