static eventer_t eventer_kqueue_impl_remove(eventer_t e) { eventer_t removed = NULL; if(e->mask & EVENTER_ASYNCH) { abort(); } if(e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) { ev_lock_state_t lockstate; lockstate = acquire_master_fd(e->fd); noitL(eventer_deb, "kqueue: remove(%d)\n", e->fd); if(e == master_fds[e->fd].e) { removed = e; master_fds[e->fd].e = NULL; if(e->mask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(e->fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e); if(e->mask & (EVENTER_WRITE)) ke_change(e->fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e); } else noitL(eventer_deb, "kqueue: remove(%d) failed.\n", e->fd); release_master_fd(e->fd, lockstate); } else if(e->mask & EVENTER_TIMER) { removed = eventer_remove_timed(e); } else if(e->mask & EVENTER_RECURRENT) { removed = eventer_remove_recurrent(e); } else { abort(); } return removed; }
static void eventer_kqueue_impl_update(eventer_t e, int mask) { if(e->mask & EVENTER_TIMER) { eventer_update_timed(e, mask); return; } noitL(eventer_deb, "kqueue: update(%d, %x->%x)\n", e->fd, e->mask, mask); /* Disable old, if they aren't active in the new */ if((e->mask & (EVENTER_READ | EVENTER_EXCEPTION)) && !(mask & (EVENTER_READ | EVENTER_EXCEPTION))) ke_change(e->fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e); if((e->mask & (EVENTER_WRITE)) && !(mask & (EVENTER_WRITE))) ke_change(e->fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e); /* Enable new, if the weren't in the old */ if((mask & (EVENTER_READ | EVENTER_EXCEPTION)) && !(e->mask & (EVENTER_READ | EVENTER_EXCEPTION))) ke_change(e->fd, EVFILT_READ, EV_ADD | EV_ENABLE, e); if((mask & (EVENTER_WRITE)) && !(e->mask & (EVENTER_WRITE))) ke_change(e->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, e); /* Switch */ e->mask = mask; }
static eventer_t eventer_kqueue_impl_remove(eventer_t e) { eventer_t removed = NULL; if(e->mask & EVENTER_ASYNCH) { mtevFatal(mtev_error, "error in eventer_kqueue_impl_remove: got unexpected EVENTER_ASYNCH mask\n"); } if(e->mask & (EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION)) { ev_lock_state_t lockstate; lockstate = acquire_master_fd(e->fd); mtevL(eventer_deb, "kqueue: remove(%d)\n", e->fd); if(e == master_fds[e->fd].e) { removed = e; master_fds[e->fd].e = NULL; if(e->mask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(e->fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e); if(e->mask & (EVENTER_WRITE)) ke_change(e->fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e); } else mtevL(eventer_deb, "kqueue: remove(%d) failed.\n", e->fd); release_master_fd(e->fd, lockstate); } else if(e->mask & EVENTER_TIMER) { removed = eventer_remove_timed(e); } else if(e->mask & EVENTER_RECURRENT) { removed = eventer_remove_recurrent(e); } else { mtevFatal(mtev_error, "error in eventer_kqueue_impl_remove: got unknown mask (0x%04x)\n", e->mask); } return removed; }
static eventer_t eventer_kqueue_impl_remove_fd(int fd) { eventer_t eiq = NULL; ev_lock_state_t lockstate; if(master_fds[fd].e) { noitL(eventer_deb, "kqueue: remove_fd(%d)\n", fd); lockstate = acquire_master_fd(fd); eiq = master_fds[fd].e; master_fds[fd].e = NULL; if(eiq->mask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(fd, EVFILT_READ, EV_DELETE | EV_DISABLE, eiq); if(eiq->mask & (EVENTER_WRITE)) ke_change(fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, eiq); release_master_fd(fd, lockstate); } return eiq; }
static void alter_kqueue_mask(eventer_t e, int oldmask, int newmask) { /* toggle the read bits if needed */ if(newmask & (EVENTER_READ | EVENTER_EXCEPTION)) { if(!(oldmask & (EVENTER_READ | EVENTER_EXCEPTION))) ke_change(e->fd, EVFILT_READ, EV_ADD | EV_ENABLE, e); } else if(oldmask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(e->fd, EVFILT_READ, EV_DELETE | EV_DISABLE, e); /* toggle the write bits if needed */ if(newmask & EVENTER_WRITE) { if(!(oldmask & EVENTER_WRITE)) ke_change(e->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, e); } else if(oldmask & EVENTER_WRITE) ke_change(e->fd, EVFILT_WRITE, EV_DELETE | EV_DISABLE, e); }
static void eventer_kqueue_impl_add(eventer_t e) { mtevAssert(e->mask); mtevAssert(eventer_is_loop(e->thr_owner) >= 0); ev_lock_state_t lockstate; const char *cbname; cbname = eventer_name_for_callback_e(e->callback, e); if(e->mask & EVENTER_ASYNCH) { mtevL(eventer_deb, "debug: eventer_add asynch (%s)\n", cbname ? cbname : "???"); eventer_add_asynch(NULL, e); return; } /* Recurrent delegation */ if(e->mask & EVENTER_RECURRENT) { mtevL(eventer_deb, "debug: eventer_add recurrent (%s)\n", cbname ? cbname : "???"); eventer_add_recurrent(e); return; } /* Timed events are simple */ if(e->mask & EVENTER_TIMER) { eventer_add_timed(e); return; } /* file descriptor event */ mtevL(eventer_deb, "debug: eventer_add fd (%s,%d,0x%04x)\n", cbname ? cbname : "???", e->fd, e->mask); mtevAssert(e->whence.tv_sec == 0 && e->whence.tv_usec == 0); lockstate = acquire_master_fd(e->fd); master_fds[e->fd].e = e; if(e->mask & (EVENTER_READ | EVENTER_EXCEPTION)) ke_change(e->fd, EVFILT_READ, EV_ADD | EV_ENABLE, e); if(e->mask & (EVENTER_WRITE)) ke_change(e->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, e); release_master_fd(e->fd, lockstate); }
static void do_accept (register struct kevent const *const kep) { auto sockaddr_in sin; auto socklen_t sinsiz; register int s; register ecb *ecbp; if ((s = accept (kep->ident, (struct sockaddr *)&sin, &sinsiz)) == -1) fatal ("Error in accept(): %s", strerror (errno)); ecbp = (ecb *) xmalloc (sizeof (ecb)); ecbp->do_read = do_read; ecbp->buf = NULL; ecbp->bufsiz = 0; ke_change (s, EVFILT_READ, EV_ADD | EV_ENABLE, ecbp); }
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); newmask = e->callback(e, mask, e->closure, &__now); 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); }
int main (register int const argc, register char *const argv[]) { auto in_addr listen_addr; register int optch; auto int one = 1; register int portno = 0; register int option_errors = 0; register int server_sock; auto sockaddr_in sin; register servent *servp; auto ecb listen_ecb; register int kq; pname = strrchr (argv[0], '/'); pname = pname ? pname+1 : argv[0]; listen_addr.s_addr = htonl (INADDR_ANY); /* Default. */ while ((optch = getopt (argc, argv, "p:")) != EOF) { switch (optch) { case 'p': if (strlen (optarg) == 0 || !all_digits (optarg)) { error ("Invalid argument for -p option: %s", optarg); option_errors++; } portno = atoi (optarg); if (portno == 0 || portno >= (1u << 16)) { error ("Invalid argument for -p option: %s", optarg); option_errors++; } break; default: error ("Invalid option: -%c", optch); option_errors++; } } if (option_errors || optind != argc) usage (); if (daemon(0,0) < 0) perror("daemon failed"); if (portno == 0) { if ((servp = getservbyname (servname, protoname)) == NULL) fatal ("Error getting port number for service `%s': %s", servname, strerror (errno)); portno = ntohs (servp->s_port); } if ((server_sock = socket (PF_INET, SOCK_STREAM, 0)) == -1) fatal ("Error creating socket: %s", strerror (errno)); if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) == -1) fatal ("Error setting SO_REUSEADDR for socket: %s", strerror (errno)); memset (&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_addr = listen_addr; sin.sin_port = htons (portno); if (bind (server_sock, (const struct sockaddr *)&sin, sizeof sin) == -1) fatal ("Error binding socket: %s", strerror (errno)); if (listen (server_sock, 20) == -1) fatal ("Error listening to socket: %s", strerror (errno)); if ((kq = kqueue ()) == -1) fatal ("Error creating kqueue: %s", strerror (errno)); listen_ecb.do_read = do_accept; listen_ecb.buf = NULL; listen_ecb.buf = 0; ke_change (server_sock, EVFILT_READ, EV_ADD | EV_ENABLE, &listen_ecb); event_loop (kq); }