static void
vwk_kev(struct vwk *vwk, const struct kevent *kp)
{
	int i, j;
	struct sess *sp;
	struct sess *ss[NKEV];

	AN(kp->udata);
	if (kp->udata == vwk->pipes) {
		j = 0;
		i = read(vwk->pipes[0], ss, sizeof ss);
		if (i == -1 && errno == EAGAIN)
			return;
		while (i >= sizeof ss[0]) {
			CHECK_OBJ_NOTNULL(ss[j], SESS_MAGIC);
			assert(ss[j]->fd >= 0);
			AZ(ss[j]->obj);
			VTAILQ_INSERT_TAIL(&vwk->sesshead, ss[j], list);
			vwk_kq_sess(vwk, ss[j], EV_ADD | EV_ONESHOT);
			j++;
			i -= sizeof ss[0];
		}
		assert(i == 0);
		return;
	}
	CAST_OBJ_NOTNULL(sp, kp->udata, SESS_MAGIC);
	DSL(0x04, SLT_Debug, sp->vsl_id, "KQ: sp %p kev data %lu flags 0x%x%s",
	    sp, (unsigned long)kp->data, kp->flags,
	    (kp->flags & EV_EOF) ? " EOF" : "");

	assert((sp->vsl_id & VSL_IDENTMASK) == kp->ident);
	assert((sp->vsl_id & VSL_IDENTMASK) == sp->fd);
	if (kp->data > 0) {
		i = HTC_Rx(sp->htc);
		if (i == 0) {
			vwk_kq_sess(vwk, sp, EV_ADD | EV_ONESHOT);
			return;	/* more needed */
		}
		VTAILQ_REMOVE(&vwk->sesshead, sp, list);
		SES_Handle(sp, i);
		return;
	} else if (kp->flags & EV_EOF) {
		VTAILQ_REMOVE(&vwk->sesshead, sp, list);
		SES_Delete(sp, "EOF");
		return;
	} else {
		VSL(SLT_Debug, sp->vsl_id, "KQ: sp %p kev data %lu flags 0x%x%s",
		    sp, (unsigned long)kp->data, kp->flags,
		    (kp->flags & EV_EOF) ? " EOF" : "");
	}
}
static void
vwk_pipe_ev(struct vwk *vwk, const struct kevent *kp)
{
	int i, j;
	struct sess *ss[NKEV];

	AN(kp->udata);
	assert(kp->udata == vwk->pipes);
	j = 0;
	i = read(vwk->pipes[0], ss, sizeof ss);
	if (i == -1 && errno == EAGAIN)
		return;
	while (i >= sizeof ss[0]) {
		CHECK_OBJ_NOTNULL(ss[j], SESS_MAGIC);
		assert(ss[j]->fd >= 0);
		VTAILQ_INSERT_TAIL(&vwk->sesshead, ss[j], list);
		vwk_kq_sess(vwk, ss[j], EV_ADD | EV_ONESHOT);
		j++;
		i -= sizeof ss[0];
	}
	AZ(i);
}