static void eventer_ports_impl_trigger(eventer_t e, int mask) { ev_lock_state_t lockstate; const char *cbname; struct timeval __now; int fd, oldmask, newmask; fd = e->fd; if(e != master_fds[fd].e) return; lockstate = acquire_master_fd(fd); if(lockstate == EV_ALREADY_OWNED) return; assert(lockstate == EV_OWNED); gettimeofday(&__now, NULL); oldmask = e->mask; cbname = eventer_name_for_callback(e->callback); noitLT(eventer_deb, &__now, "ports: fire on %d/%x to %s(%p)\n", fd, mask, cbname?cbname:"???", e->callback); EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask); newmask = e->callback(e, mask, e->closure, &__now); EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask); if(newmask) { alter_fd(e, newmask); /* Set our mask */ e->mask = newmask; noitLT(eventer_deb, &__now, "ports: complete on %d/(%x->%x) to %s(%p)\n", fd, mask, newmask, cbname?cbname:"???", e->callback); } else { noitLT(eventer_deb, &__now, "ports: complete on %d/none to %s(%p)\n", fd, cbname?cbname:"???", e->callback); /* * Long story long: * When integrating with a few external event systems, we find * it difficult to make their use of remove+add as an update * as it can be recurrent in a single handler call and you cannot * remove completely from the event system if you are going to * just update (otherwise the eventer_t in your call stack could * be stale). What we do is perform a superficial remove, marking * the mask as 0, but not eventer_remove_fd. Then on an add, if * we already have an event, we just update the mask (as we * have not yet returned to the eventer's loop. * This leaves us in a tricky situation when a remove is called * and the add doesn't roll in, we return 0 (mask == 0) and hit * this spot. We have intended to remove the event, but it still * resides at master_fds[fd].e -- even after we free it. * So, in the evnet that we return 0 and the event that * master_fds[fd].e == the event we're about to free... we NULL * it out. */ if(master_fds[fd].e == e) master_fds[fd].e = NULL; eventer_free(e); } release_master_fd(fd, lockstate); }
static void eventer_epoll_impl_trigger(eventer_t e, int mask) { struct timeval __now; int fd, newmask; const char *cbname; ev_lock_state_t lockstate; fd = e->fd; if(e != master_fds[fd].e) return; lockstate = acquire_master_fd(fd); if(lockstate == EV_ALREADY_OWNED) return; assert(lockstate == EV_OWNED); gettimeofday(&__now, NULL); cbname = eventer_name_for_callback_e(e->callback, e); noitLT(eventer_deb, &__now, "epoll: fire on %d/%x to %s(%p)\n", fd, mask, cbname?cbname:"???", e->callback); EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask); newmask = e->callback(e, mask, e->closure, &__now); EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask); if(newmask) { struct epoll_event _ev; memset(&_ev, 0, sizeof(_ev)); _ev.data.fd = fd; if(newmask & EVENTER_READ) _ev.events |= (EPOLLIN|EPOLLPRI); if(newmask & EVENTER_WRITE) _ev.events |= (EPOLLOUT); if(newmask & EVENTER_EXCEPTION) _ev.events |= (EPOLLERR|EPOLLHUP); if(master_fds[fd].e == NULL) { noitL(noit_debug, "eventer %s(%p) epoll asked to modify descheduled fd: %d\n", cbname?cbname:"???", e->callback, fd); } else { assert(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &_ev) == 0); } /* Set our mask */ e->mask = newmask; } else { /* see kqueue implementation for details on the next line */ if(master_fds[fd].e == e) master_fds[fd].e = NULL; eventer_free(e); } release_master_fd(fd, lockstate); }
static void eventer_kqueue_impl_trigger(eventer_t e, int mask) { ev_lock_state_t lockstate; struct timeval __now; int oldmask, newmask; const char *cbname; int fd; fd = e->fd; if(e != master_fds[fd].e) return; lockstate = acquire_master_fd(fd); if(lockstate == EV_ALREADY_OWNED) return; assert(lockstate == EV_OWNED); gettimeofday(&__now, NULL); /* We're going to lie to ourselves. You'd think this should be: * oldmask = e->mask; However, we just fired with masks[fd], so * kqueue is clearly looking for all of the events in masks[fd]. * So, we combine them "just to be safe." */ oldmask = e->mask | masks[fd]; cbname = eventer_name_for_callback(e->callback); noitLT(eventer_deb, &__now, "kqueue: fire on %d/%x to %s(%p)\n", fd, masks[fd], cbname?cbname:"???", e->callback); EVENTER_CALLBACK_ENTRY((void *)e->callback, (char *)cbname, fd, e->mask, mask); newmask = e->callback(e, mask, e->closure, &__now); EVENTER_CALLBACK_RETURN((void *)e->callback, (char *)cbname, newmask); if(newmask) { /* toggle the read bits if needed */ if(newmask & (EVENTER_READ | EVENTER_EXCEPTION)) { if(!(oldmask & (EVENTER_READ | EVENTER_EXCEPTION))) ke_change(fd, EVFILT_READ, EV_ADD | EV_ENABLE, e); } else if(oldmask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e); /* toggle the write bits if needed */ if(newmask & EVENTER_WRITE) { if(!(oldmask & EVENTER_WRITE)) ke_change(fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, e); } else if(oldmask & EVENTER_WRITE) ke_change(fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e); /* Set our mask */ e->mask = newmask; } else { /* * Long story long: * When integrating with a few external event systems, we find * it difficult to make their use of remove+add as an update * as it can be recurrent in a single handler call and you cannot * remove completely from the event system if you are going to * just update (otherwise the eventer_t in your call stack could * be stale). What we do is perform a superficial remove, marking * the mask as 0, but not eventer_remove_fd. Then on an add, if * we already have an event, we just update the mask (as we * have not yet returned to the eventer's loop. * This leaves us in a tricky situation when a remove is called * and the add doesn't roll in, we return 0 (mask == 0) and hit * this spot. We have intended to remove the event, but it still * resides at master_fds[fd].e -- even after we free it. * So, in the evnet that we return 0 and the event that * master_fds[fd].e == the event we're about to free... we NULL * it out. */ if(master_fds[fd].e == e) master_fds[fd].e = NULL; eventer_free(e); } release_master_fd(fd, lockstate); }