static int kqueue_max;
/** File descriptor for kqueue pseudo-file. */
static int kqueue_id;
+/** Current array of event descriptors. */
+static struct kevent *events;
+/** Number of ::events elements that have been populated. */
+static int events_used;
+/** Current processing position in ::events. */
+static int events_i;
/** Number of recent errors from kqueue. */
static int errors = 0;
struct kevent sigevent;
struct sigaction act;
- assert(0 != signal);
+ assert(0 != sig);
Debug((DEBUG_ENGINE, "kqueue: Adding filter for signal %d [%p]",
sig_signal(sig), sig));
static void
engine_delete(struct Socket* sock)
{
- struct kevent dellist[2];
+ int ii;
assert(0 != sock);
assert(sock == sockList[s_fd(sock)]);
Debug((DEBUG_ENGINE, "kqueue: Deleting socket %d [%p], state %s",
s_fd(sock), sock, state_to_name(s_state(sock))));
- dellist[0].ident = s_fd(sock); /* set up the delete list */
- dellist[0].filter = EVFILT_READ; /* readable filter */
- dellist[0].flags = EV_DELETE; /* delete it */
- dellist[0].fflags = 0;
- dellist[0].data = 0;
- dellist[0].udata = 0;
-
- dellist[1].ident = s_fd(sock);
- dellist[1].filter = EVFILT_WRITE; /* writable filter */
- dellist[1].flags = EV_DELETE; /* delete it */
- dellist[1].fflags = 0;
- dellist[1].data = 0;
- dellist[1].udata = 0;
-
sockList[s_fd(sock)] = 0;
+
+ /* Drop any unprocessed events citing this socket. */
+ for (ii = events_i; ii < events_used; ii++) {
+ if (events[ii].ident == s_fd(sock)) {
+ events[ii] = events[--events_used];
+ }
+ }
}
/** Run engine event loop.
static void
engine_loop(struct Generators* gen)
{
- struct kevent *events;
int events_count;
+ struct kevent *evt;
struct Socket* sock;
struct timespec wait;
- int nevs;
int i;
int errcode;
- size_t codesize;
+ socklen_t codesize;
if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
events_count = 20;
wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
wait.tv_nsec = 0;
- Debug((DEBUG_INFO, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen),
+ Debug((DEBUG_ENGINE, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen),
CurrentTime, wait.tv_sec));
/* check for active events */
- nevs = kevent(kqueue_id, 0, 0, events, events_count,
- wait.tv_sec < 0 ? 0 : &wait);
+ events_used = kevent(kqueue_id, 0, 0, events, events_count,
+ wait.tv_sec < 0 ? 0 : &wait);
CurrentTime = time(0); /* set current time... */
- if (nevs < 0) {
+ if (events_used < 0) {
if (errno != EINTR) { /* ignore kevent interrupts */
/* Log the kqueue error */
log_write(LS_SOCKET, L_ERROR, 0, "kevent() error: %m");
continue;
}
- for (i = 0; i < nevs; i++) {
- if (events[i].filter == EVFILT_SIGNAL) {
+ for (events_i = 0; events_i < events_used; events_i++) {
+ evt = &events[events_i];
+
+ if (evt->filter == EVFILT_SIGNAL) {
/* it's a signal; deal appropriately */
- event_generate(ET_SIGNAL, events[i].udata, events[i].ident);
+ event_generate(ET_SIGNAL, evt->udata, evt->ident);
continue; /* skip socket processing loop */
}
- assert(events[i].filter == EVFILT_READ ||
- events[i].filter == EVFILT_WRITE);
+ assert(evt->filter == EVFILT_READ || evt->filter == EVFILT_WRITE);
- sock = sockList[events[i].ident];
+ sock = sockList[evt->ident];
if (!sock) /* slots may become empty while processing events */
continue;
- assert(s_fd(sock) == events[i].ident);
+ assert(s_fd(sock) == evt->ident);
gen_ref_inc(sock); /* can't have it going away on us */
switch (s_state(sock)) {
case SS_CONNECTING:
- if (events[i].filter == EVFILT_WRITE) { /* connection completed */
+ if (evt->filter == EVFILT_WRITE) { /* connection completed */
Debug((DEBUG_ENGINE, "kqueue: Connection completed"));
event_generate(ET_CONNECT, sock, 0);
}
break;
case SS_LISTENING:
- if (events[i].filter == EVFILT_READ) { /* connect. to be accept. */
+ if (evt->filter == EVFILT_READ) { /* connect. to be accept. */
Debug((DEBUG_ENGINE, "kqueue: Ready for accept"));
event_generate(ET_ACCEPT, sock, 0);
}
case SS_NOTSOCK: /* doing nothing socket-specific */
case SS_CONNECTED:
- if (events[i].filter == EVFILT_READ) { /* data on socket */
+ if (evt->filter == EVFILT_READ) { /* data on socket */
Debug((DEBUG_ENGINE, "kqueue: EOF or data to be read"));
- event_generate(events[i].flags & EV_EOF ? ET_EOF : ET_READ, sock, 0);
+ event_generate(evt->flags & EV_EOF ? ET_EOF : ET_READ, sock, 0);
}
- if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+ if (evt->filter == EVFILT_WRITE) { /* socket writable */
Debug((DEBUG_ENGINE, "kqueue: Data can be written"));
event_generate(ET_WRITE, sock, 0);
}
break;
case SS_DATAGRAM: case SS_CONNECTDG:
- if (events[i].filter == EVFILT_READ) { /* socket readable */
+ if (evt->filter == EVFILT_READ) { /* socket readable */
Debug((DEBUG_ENGINE, "kqueue: Datagram to be read"));
event_generate(ET_READ, sock, 0);
}
- if (events[i].filter == EVFILT_WRITE) { /* socket writable */
+ if (evt->filter == EVFILT_WRITE) { /* socket writable */
Debug((DEBUG_ENGINE, "kqueue: Datagram can be written"));
event_generate(ET_WRITE, sock, 0);
}