+static bool
+io_event_kqueue_commit_cache(void)
+{
+ struct kevent *events;
+ bool ret;
+ int len = (int) array_length(&io_evcache, sizeof (struct kevent));
+
+ if (!len) /* nothing to do */
+ return true;
+
+ assert(len>0);
+
+ if (len < 0) {
+ array_free(&io_evcache);
+ return false;
+ }
+
+ events = array_start(&io_evcache);
+
+ assert(events != NULL);
+
+ ret = kevent(io_masterfd, events, len, NULL, 0, NULL) == 0;
+ if (ret)
+ array_trunc(&io_evcache);
+ return ret;
+}
+
+static bool
+io_event_change_kqueue(int fd, short what, const int action)
+{
+ struct kevent kev;
+ bool ret = true;
+
+ if (what & IO_WANTREAD) {
+ EV_SET(&kev, fd, EVFILT_READ, action, 0, 0, 0);
+ ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
+ if (!ret)
+ ret = kevent(io_masterfd, &kev,1, NULL, 0, NULL) == 0;
+ }
+
+ if (ret && (what & IO_WANTWRITE)) {
+ EV_SET(&kev, fd, EVFILT_WRITE, action, 0, 0, 0);
+ ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
+ if (!ret)
+ ret = kevent(io_masterfd, &kev, 1, NULL, 0, NULL) == 0;
+ }
+
+ if (array_length(&io_evcache, sizeof kev) >= 100)
+ io_event_kqueue_commit_cache();
+ return ret;
+}
+
+static int
+io_dispatch_kqueue(struct timeval *tv)
+{
+ int i, ret;
+ struct kevent kev[MAX_EVENTS];
+ struct kevent *newevents;
+ struct timespec ts;
+ int newevents_len;
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+
+ newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent));
+ newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL;
+ assert(newevents_len >= 0);
+
+ ret = kevent(io_masterfd, newevents, newevents_len, kev, MAX_EVENTS, &ts);
+ if (newevents && ret != -1)
+ array_trunc(&io_evcache);
+
+ for (i = 0; i < ret; i++) {
+ io_debug("dispatch_kqueue: fd, kev.flags", (int)kev[i].ident, kev[i].flags);
+ if (kev[i].flags & (EV_EOF|EV_ERROR)) {
+ if (kev[i].flags & EV_ERROR)
+ Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)",
+ (int)kev[i].ident, strerror((int)kev[i].data));
+ io_docallback((int)kev[i].ident, IO_ERROR);
+ continue;
+ }
+
+ switch (kev[i].filter) {
+ case EVFILT_READ:
+ io_docallback((int)kev[i].ident, IO_WANTREAD);
+ break;
+ case EVFILT_WRITE:
+ io_docallback((int)kev[i].ident, IO_WANTWRITE);
+ break;
+ default:
+ LogDebug("Unknown kev.filter number %d for fd %d",
+ kev[i].filter, kev[i].ident);
+ /* Fall through */
+ case EV_ERROR:
+ io_docallback((int)kev[i].ident, IO_ERROR);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void
+io_library_init_kqueue(unsigned int eventsize)
+{