static int eventer_epoll_impl_loop() { struct epoll_event *epev; struct epoll_spec *spec; spec = eventer_get_spec_for_event(NULL); epev = malloc(sizeof(*epev) * maxfds); #ifdef HAVE_SYS_EVENTFD_H if(spec->event_fd >= 0) { eventer_t e = eventer_alloc(); e->callback = eventer_epoll_eventfd_read; e->fd = spec->event_fd; e->mask = EVENTER_READ; eventer_add(e); } #endif while(1) { struct timeval __now, __sleeptime; int fd_cnt = 0; __sleeptime = eventer_max_sleeptime; mtev_gettimeofday(&__now, NULL); eventer_dispatch_timed(&__now, &__sleeptime); /* Handle cross_thread dispatches */ eventer_cross_thread_process(); /* Handle recurrent events */ eventer_dispatch_recurrent(&__now); /* Now we move on to our fd-based events */ do { fd_cnt = epoll_wait(spec->epoll_fd, epev, maxfds, __sleeptime.tv_sec * 1000 + __sleeptime.tv_usec / 1000); } while(fd_cnt < 0 && errno == EINTR); mtevLT(eventer_deb, &__now, "debug: epoll_wait(%d, [], %d) => %d\n", spec->epoll_fd, maxfds, fd_cnt); if(fd_cnt < 0) { mtevLT(eventer_err, &__now, "epoll_wait: %s\n", strerror(errno)); } else { int idx; /* loop once to clear */ for(idx = 0; idx < fd_cnt; idx++) { struct epoll_event *ev; eventer_t e; int fd, mask = 0; ev = &epev[idx]; if(ev->events & (EPOLLIN | EPOLLPRI)) mask |= EVENTER_READ; if(ev->events & (EPOLLOUT)) mask |= EVENTER_WRITE; if(ev->events & (EPOLLERR|EPOLLHUP)) mask |= EVENTER_EXCEPTION; fd = ev->data.fd; e = master_fds[fd].e; /* It's possible that someone removed the event and freed it * before we got here. */ if(!e) continue; eventer_epoll_impl_trigger(e, mask); } } } /* NOTREACHED */ return 0; }
static int eventer_ports_impl_loop(int id) { struct timeval __dyna_sleep = { 0, 0 }; struct ports_spec *spec; spec = eventer_get_spec_for_event(NULL); while(1) { struct timeval __sleeptime; struct timespec __ports_sleeptime; unsigned int fd_cnt = 0; int ret; port_event_t pevents[MAX_PORT_EVENTS]; if(compare_timeval(eventer_max_sleeptime, __dyna_sleep) < 0) __dyna_sleep = eventer_max_sleeptime; __sleeptime = __dyna_sleep; eventer_dispatch_timed(&__sleeptime); if(compare_timeval(__sleeptime, __dyna_sleep) > 0) __sleeptime = __dyna_sleep; /* Handle cross_thread dispatches */ eventer_cross_thread_process(); /* Handle recurrent events */ eventer_dispatch_recurrent(); /* Now we move on to our fd-based events */ __ports_sleeptime.tv_sec = __sleeptime.tv_sec; __ports_sleeptime.tv_nsec = __sleeptime.tv_usec * 1000; fd_cnt = 1; pevents[0].portev_source = 65535; /* This is impossible */ ret = port_getn(spec->port_fd, pevents, MAX_PORT_EVENTS, &fd_cnt, &__ports_sleeptime); spec->wakeup_notify = 0; /* force unlock */ /* The timeout case is a tad complex with ports. -1/ETIME is clearly * a timeout. However, it i spossible that we got that and fd_cnt isn't * 0, which means we both timed out and got events... WTF? */ if(fd_cnt == 0 || (ret == -1 && errno == ETIME && pevents[0].portev_source == 65535)) add_timeval(__dyna_sleep, __dyna_increment, &__dyna_sleep); if(ret == -1 && (errno != ETIME && errno != EINTR)) mtevL(eventer_err, "port_getn: %s\n", strerror(errno)); if(ret < 0) mtevL(eventer_deb, "port_getn: %s\n", strerror(errno)); mtevL(eventer_deb, "debug: port_getn(%d, [], %d) => %d\n", spec->port_fd, fd_cnt, ret); if(pevents[0].portev_source == 65535) { /* the impossible still remains, which means our fd_cnt _must_ be 0 */ fd_cnt = 0; } if(fd_cnt > 0) { int idx; /* Loop a last time to process */ __dyna_sleep.tv_sec = __dyna_sleep.tv_usec = 0; /* reset */ for(idx = 0; idx < fd_cnt; idx++) { port_event_t *pe; eventer_t e; int fd, mask; pe = &pevents[idx]; if(pe->portev_source != PORT_SOURCE_FD) continue; fd = (int)pe->portev_object; mtevAssert((intptr_t)pe->portev_user == fd); e = master_fds[fd].e; /* It's possible that someone removed the event and freed it * before we got here.... bail out if we're null. */ if (!e) continue; mask = 0; if(pe->portev_events & (POLLIN | POLLHUP)) mask |= EVENTER_READ; if(pe->portev_events & (POLLOUT)) mask |= EVENTER_WRITE; if(pe->portev_events & (POLLERR | POLLHUP | POLLNVAL)) mask |= EVENTER_EXCEPTION; eventer_ports_impl_trigger(e, mask); } } } /* NOTREACHED */ return 0; }
static int eventer_kqueue_impl_loop() { struct timeval __dyna_sleep = { 0, 0 }; KQUEUE_DECL; KQUEUE_SETUP(NULL); if(eventer_kqueue_impl_register_wakeup(kqs) == -1) { mtevFatal(mtev_error, "error in eventer_kqueue_impl_loop: could not eventer_kqueue_impl_register_wakeup\n"); } while(1) { struct timeval __now, __sleeptime; struct timespec __kqueue_sleeptime; int fd_cnt = 0; if(compare_timeval(eventer_max_sleeptime, __dyna_sleep) < 0) __dyna_sleep = eventer_max_sleeptime; __sleeptime = __dyna_sleep; eventer_dispatch_timed(&__now, &__sleeptime); if(compare_timeval(__sleeptime, __dyna_sleep) > 0) __sleeptime = __dyna_sleep; /* Handle cross_thread dispatches */ eventer_cross_thread_process(); /* Handle recurrent events */ eventer_dispatch_recurrent(&__now); /* Now we move on to our fd-based events */ __kqueue_sleeptime.tv_sec = __sleeptime.tv_sec; __kqueue_sleeptime.tv_nsec = __sleeptime.tv_usec * 1000; fd_cnt = kevent(kqs->kqueue_fd, ke_vec, ke_vec_used, ke_vec, ke_vec_a, &__kqueue_sleeptime); kqs->wakeup_notify = 0; if(fd_cnt > 0 || ke_vec_used) mtevLT(eventer_deb, &__now, "[t@%llx] kevent(%d, [...], %d) => %d\n", (vpsized_int)pthread_self(), kqs->kqueue_fd, ke_vec_used, fd_cnt); ke_vec_used = 0; if(fd_cnt < 0) { mtevLT(eventer_err, &__now, "kevent(s/%d): %s\n", kqs->kqueue_fd, strerror(errno)); } else if(fd_cnt == 0 || (fd_cnt == 1 && ke_vec[0].filter == EVFILT_USER)) { /* timeout */ if(fd_cnt) eventer_kqueue_impl_register_wakeup(kqs); add_timeval(__dyna_sleep, __dyna_increment, &__dyna_sleep); } else { int idx; __dyna_sleep.tv_sec = __dyna_sleep.tv_usec = 0; /* reset */ /* loop once to clear */ for(idx = 0; idx < fd_cnt; idx++) { struct kevent *ke; ke = &ke_vec[idx]; if(ke->flags & EV_ERROR) continue; if(ke->filter == EVFILT_USER) { eventer_kqueue_impl_register_wakeup(kqs); continue; } masks[ke->ident] = 0; } /* Loop again to aggregate */ for(idx = 0; idx < fd_cnt; idx++) { struct kevent *ke; ke = &ke_vec[idx]; if(ke->flags & EV_ERROR) continue; if(ke->filter == EVFILT_USER) continue; if(ke->filter == EVFILT_READ) masks[ke->ident] |= EVENTER_READ; if(ke->filter == EVFILT_WRITE) masks[ke->ident] |= EVENTER_WRITE; } /* Loop a last time to process */ for(idx = 0; idx < fd_cnt; idx++) { struct kevent *ke; eventer_t e; int fd; ke = &ke_vec[idx]; if(ke->filter == EVFILT_USER) continue; if(ke->flags & EV_ERROR) { if(ke->data != EBADF && ke->data != ENOENT) mtevLT(eventer_err, &__now, "error [%d]: %s\n", (int)ke->ident, strerror(ke->data)); continue; } mtevAssert((vpsized_int)ke->udata == (vpsized_int)ke->ident); fd = ke->ident; e = master_fds[fd].e; /* If we've seen this fd, don't callback twice */ if(!masks[fd]) continue; /* It's possible that someone removed the event and freed it * before we got here. */ if(e) eventer_kqueue_impl_trigger(e, masks[fd]); masks[fd] = 0; /* indicates we've processed this fd */ } } } /* NOTREACHED */ return 0; }