| /* Copyright (c) 2013 The Regents of the University of California | 
 |  * Copyright (c) 2016 Google Inc. | 
 |  * Barret Rhoden <brho@cs.berkeley.edu> | 
 |  * See LICENSE for details. | 
 |  * | 
 |  * #alarm: a device for registering per-process alarms. | 
 |  * | 
 |  * Allows a process to set up alarms, which they can tap to get events at a | 
 |  * certain TSC time. | 
 |  * | 
 |  * Every process has their own alarm sets and view of #alarm; gen and friends | 
 |  * look at current's alarmset when it is time to gen or open a file. | 
 |  * | 
 |  * To use, first open #alarm/clone, and that gives you an alarm directory aN, | 
 |  * where N is ID of the alarm.  The FD you get from clone points to 'ctl.' | 
 |  * | 
 |  * 'ctl' takes no commands.  You can read it to get the ID.  That's it. | 
 |  * | 
 |  * 'timer' takes the hex string value (in absolute tsc time) to fire the alarm. | 
 |  * Writing 0 disables the alarm.  You can read 'timer' to get the next time it | 
 |  * will fire, in TSC time.  0 means it is disabled.  To find out about the timer | 
 |  * firing, put an FD tap on 'timer' for FDTAP_FILT_WRITTEN. | 
 |  * | 
 |  * 'period' takes the hex string value (in TSC ticks) for the period of the | 
 |  * alarm.  If non-zero, the alarm will rearm when it fires.  You can read the | 
 |  * period. | 
 |  * | 
 |  * Reading the 'count' file will return the number of times the alarm has | 
 |  * expired since the last read or the last write to 'timer'.  If this is 0, then | 
 |  * read() will block or EAGAIN.  You cannot write 'count'.  You can tap it for | 
 |  * FDTAP_FILT_READABLE. | 
 |  * | 
 |  * While each process has a separate view of #alarm, it is possible to post a | 
 |  * chan to Qctl or Qtimer to #srv.  If another proc has your Qtimer, it can set | 
 |  * it in the past, thereby triggering an immediate event.  More clever than | 
 |  * useful. | 
 |  * | 
 |  * Notes on refcnting (the trickier parts here): | 
 |  * - the proc_alarms have counted references to their proc | 
 |  * 	proc won't free til all alarms are closed, which is fine.  we close | 
 |  * 	all files in destroy.  if a proc drops a chan in srv, the proc will stay | 
 |  * 	alive because the alarm is alive - til that chan is closed (srvremove) | 
 |  * | 
 |  * 	other shady ways to keep a chan alive: cd to it!  if it is ., we'd | 
 |  * 	keep a ref around.  however, only alarmdir *file* grab refs, not | 
 |  * 	directories. | 
 |  * | 
 |  * - proc_alarms are kref'd, since there can be multiple chans per alarm | 
 |  * 	the only thing that keeps an alarm alive is a chan on a CTL or TIMER (or | 
 |  * 	other file).  when you cloned, you got back an open CTL, which keeps the | 
 |  * 	alarm (and the dir) alive. | 
 |  * | 
 |  * 	we need to be careful generating krefs, in case alarms are concurrently | 
 |  * 	released and removed from the lists.  just like with procs and pid2proc, | 
 |  * 	we need to sync with the source of the kref. */ | 
 |  | 
 | #include <kmalloc.h> | 
 | #include <string.h> | 
 | #include <stdio.h> | 
 | #include <assert.h> | 
 | #include <error.h> | 
 | #include <pmap.h> | 
 | #include <sys/queue.h> | 
 | #include <smp.h> | 
 | #include <kref.h> | 
 | #include <atomic.h> | 
 | #include <alarm.h> | 
 | #include <umem.h> | 
 | #include <devalarm.h> | 
 |  | 
 | struct dev alarmdevtab; | 
 |  | 
 | static char *devname(void) | 
 | { | 
 | 	return alarmdevtab.name; | 
 | } | 
 |  | 
 | /* qid path types */ | 
 | #define Qtopdir			1 | 
 | #define Qclone			2 | 
 | #define Qalarmdir		3 | 
 | #define Qctl			4 | 
 | #define Qtimer			5	/* Qctl + 1 */ | 
 | #define Qperiod			6 | 
 | #define Qcount			7 | 
 |  | 
 | /* This paddr/kaddr is a bit dangerous.  it'll work so long as we don't need all | 
 |  * 64 bits for a physical address (48 is the current norm on x86_64). */ | 
 | #define ADDR_SHIFT 5 | 
 | #define QID2A(q) ((struct proc_alarm*)KADDR(((q).path >> ADDR_SHIFT))) | 
 | #define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1)) | 
 | #define QID(ptr, type) ((PADDR(ptr) << ADDR_SHIFT) | type) | 
 | extern struct username eve; | 
 |  | 
 | static void alarm_release(struct kref *kref) | 
 | { | 
 | 	struct proc_alarm *a = container_of(kref, struct proc_alarm, kref); | 
 | 	struct proc *p = a->proc; | 
 |  | 
 | 	assert(p); | 
 | 	spin_lock(&p->alarmset.lock); | 
 | 	TAILQ_REMOVE(&p->alarmset.list, a, link); | 
 | 	spin_unlock(&p->alarmset.lock); | 
 | 	/* When this returns, the alarm has either fired or it never will */ | 
 | 	unset_alarm(p->alarmset.tchain, &a->a_waiter); | 
 | 	proc_decref(p); | 
 | 	kfree(a); | 
 | } | 
 |  | 
 | static void alarm_fire_taps(struct proc_alarm *a, int filter) | 
 | { | 
 | 	struct fd_tap *tap_i; | 
 |  | 
 | 	SLIST_FOREACH(tap_i, &a->fd_taps, link) | 
 | 		fire_tap(tap_i, filter); | 
 | } | 
 |  | 
 | static void proc_alarm_handler(struct alarm_waiter *a_waiter) | 
 | { | 
 | 	struct proc_alarm *a = container_of(a_waiter, struct proc_alarm, | 
 | 					    a_waiter); | 
 |  | 
 | 	cv_lock(&a->cv); | 
 | 	a->count++; | 
 | 	if (!a->period) { | 
 | 		a_waiter->wake_up_time = 0; | 
 | 	} else { | 
 | 		/* TODO: use an alarm helper, once we switch over to nsec */ | 
 | 		a_waiter->wake_up_time += a->period; | 
 | 		set_alarm(a->proc->alarmset.tchain, a_waiter); | 
 | 	} | 
 | 	__cv_broadcast(&a->cv); | 
 | 	/* Fires taps for both Qtimer and Qcount. */ | 
 | 	alarm_fire_taps(a, FDTAP_FILT_WRITTEN | FDTAP_FILT_READABLE); | 
 | 	cv_unlock(&a->cv); | 
 | } | 
 |  | 
 | void devalarm_init(struct proc *p) | 
 | { | 
 | 	TAILQ_INIT(&p->alarmset.list); | 
 | 	spinlock_init(&p->alarmset.lock); | 
 | 	/* Just running all the proc alarms on core 0. */ | 
 | 	p->alarmset.tchain = &per_cpu_info[0].tchain; | 
 | 	p->alarmset.id_counter = 0; | 
 | } | 
 |  | 
 | static int alarmgen(struct chan *c, char *entry_name, struct dirtab *unused, | 
 | 		    int unused_nr_dirtab, int s, struct dir *dp) | 
 | { | 
 | 	struct qid q; | 
 | 	struct proc_alarm *a_i; | 
 | 	struct proc *p = current; | 
 |  | 
 | 	/* Whether we're in one dir or at the top, .. still takes us to the top. | 
 | 	 */ | 
 | 	if (s == DEVDOTDOT) { | 
 | 		mkqid(&q, Qtopdir, 0, QTDIR); | 
 | 		devdir(c, q, devname(), 0, eve.name, 0555, dp); | 
 | 		return 1; | 
 | 	} | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qtopdir: | 
 | 		/* Generate elements for the top level dir.  We support a clone | 
 | 		 * and alarm dirs at the top level */ | 
 | 		if (s == 0) { | 
 | 			mkqid(&q, Qclone, 0, QTFILE); | 
 | 			devdir(c, q, "clone", 0, eve.name, 0666, dp); | 
 | 			return 1; | 
 | 		} | 
 | 		s--;	/* 1 -> 0th element, 2 -> 1st element, etc */ | 
 | 		/* Gets the s-th element (0 index) | 
 | 		 * | 
 | 		 * I would like to take advantage of the state machine and our | 
 | 		 * previous answer to get the sth element of the list.  We can | 
 | 		 * get at our previous run of gen from dp (struct dir), and use | 
 | 		 * that to get the next item.  I'd like to do something like: | 
 | 		 * | 
 | 		 * if (dp->qid.path >> ADDR_SHIFT) | 
 | 		 *      a_i = TAILQ_NEXT(QID2A(dp->qid), link); | 
 | 		 * | 
 | 		 * Dev would give us a 0'd dp path on the first run, so if we | 
 | 		 * have a path, we know we're on an iterative run.  However, the | 
 | 		 * problem is that we could have lost the element dp refers to | 
 | 		 * (QID2A(dp->qid)) since our previous run, so we can't even | 
 | 		 * access that memory to check for refcnts or anything.  We need | 
 | 		 * a new model for how gen works (probably a gen_start and | 
 | 		 * gen_stop devop, passed as parameters to devwalk), so that we | 
 | 		 * can have some invariants between gen runs. | 
 | 		 * | 
 | 		 * Til then, we're stuck with arrays like in #ip (though we can | 
 | 		 * use Linux style fdsets) or lousy O(n^2) linked lists (like | 
 | 		 * #srv). | 
 | 		 * | 
 | 		 * Note that we won't always start a gen loop with s == 0 | 
 | 		 * (devdirread, for instance) */ | 
 | 		spin_lock(&p->alarmset.lock); | 
 | 		TAILQ_FOREACH(a_i, &p->alarmset.list, link) { | 
 | 			if (s-- == 0) | 
 | 				break; | 
 | 		} | 
 | 		/* As soon as we unlock, someone could free a_i */ | 
 | 		if (!a_i) { | 
 | 			spin_unlock(&p->alarmset.lock); | 
 | 			return -1; | 
 | 		} | 
 | 		snprintf(get_cur_genbuf(), GENBUF_SZ, "a%d", a_i->id); | 
 | 		mkqid(&q, QID(a_i, Qalarmdir), 0, QTDIR); | 
 | 		devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp); | 
 | 		spin_unlock(&p->alarmset.lock); | 
 | 		return 1; | 
 | 	case Qalarmdir: | 
 | 		/* Gen the contents of the alarm dirs */ | 
 | 		s += Qctl;	/* first time through, start on Qctl */ | 
 | 		switch (s) { | 
 | 		case Qctl: | 
 | 			mkqid(&q, QID(QID2A(c->qid), Qctl), 0, QTFILE); | 
 | 			devdir(c, q, "ctl", 0, eve.name, 0666, dp); | 
 | 			return 1; | 
 | 		case Qtimer: | 
 | 			mkqid(&q, QID(QID2A(c->qid), Qtimer), 0, QTFILE); | 
 | 			devdir(c, q, "timer", 0, eve.name, 0666, dp); | 
 | 			return 1; | 
 | 		case Qperiod: | 
 | 			mkqid(&q, QID(QID2A(c->qid), Qperiod), 0, QTFILE); | 
 | 			devdir(c, q, "period", 0, eve.name, 0666, dp); | 
 | 			return 1; | 
 | 		case Qcount: | 
 | 			mkqid(&q, QID(QID2A(c->qid), Qcount), 0, QTFILE); | 
 | 			devdir(c, q, "count", 0, eve.name, 0666, dp); | 
 | 			return 1; | 
 | 		} | 
 | 		return -1; | 
 | 		/* Need to also provide a direct hit for Qclone and all other | 
 | 		 * files (at all levels of the hierarchy).  Every file is both | 
 | 		 * generated (via the s increments in their respective | 
 | 		 * directories) and directly gen-able.  devstat() will call gen | 
 | 		 * with a specific path in the qid.  In these cases, we make a | 
 | 		 * dir for whatever they are asking for.  Note the qid stays the | 
 | 		 * same.  I think this is what the old plan9 comments above | 
 | 		 * devgen were talking about for (ii). | 
 | 		 * | 
 | 		 * We don't need to do this for the directories - devstat will | 
 | 		 * look for the a directory by path and fail.  Then it will | 
 | 		 * manually build the stat output (check the -1 case in | 
 | 		 * devstat). */ | 
 | 	case Qclone: | 
 | 		devdir(c, c->qid, "clone", 0, eve.name, 0666, dp); | 
 | 		return 1; | 
 | 	case Qctl: | 
 | 		devdir(c, c->qid, "ctl", 0, eve.name, 0666, dp); | 
 | 		return 1; | 
 | 	case Qtimer: | 
 | 		devdir(c, c->qid, "timer", 0, eve.name, 0666, dp); | 
 | 		return 1; | 
 | 	case Qperiod: | 
 | 		devdir(c, c->qid, "period", 0, eve.name, 0666, dp); | 
 | 		return 1; | 
 | 	case Qcount: | 
 | 		devdir(c, c->qid, "count", 0, eve.name, 0666, dp); | 
 | 		return 1; | 
 | 	} | 
 | 	return -1; | 
 | } | 
 |  | 
 | static void alarminit(void) | 
 | { | 
 | } | 
 |  | 
 | static struct chan *alarmattach(char *spec) | 
 | { | 
 | 	struct chan *c = devattach(devname(), spec); | 
 |  | 
 | 	mkqid(&c->qid, Qtopdir, 0, QTDIR); | 
 | 	return c; | 
 | } | 
 |  | 
 | static struct walkqid *alarmwalk(struct chan *c, struct chan *nc, char **name, | 
 | 				 unsigned int nname) | 
 | { | 
 | 	return devwalk(c, nc, name, nname, 0, 0, alarmgen); | 
 | } | 
 |  | 
 | static size_t alarmstat(struct chan *c, uint8_t *db, size_t n) | 
 | { | 
 | 	return devstat(c, db, n, 0, 0, alarmgen); | 
 | } | 
 |  | 
 | /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert | 
 |  * the open chan into p's fd table, then decref the chan. */ | 
 | static struct chan *alarmopen(struct chan *c, int omode) | 
 | { | 
 | 	struct proc *p = current; | 
 | 	struct proc_alarm *a, *a_i; | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qtopdir: | 
 | 	case Qalarmdir: | 
 | 		if (omode & O_REMCLO) | 
 | 			error(EPERM, ERROR_FIXME); | 
 | 		if (omode & O_WRITE) | 
 | 			error(EISDIR, ERROR_FIXME); | 
 | 		break; | 
 | 	case Qclone: | 
 | 		a = kzmalloc(sizeof(struct proc_alarm), MEM_WAIT); | 
 | 		kref_init(&a->kref, alarm_release, 1); | 
 | 		SLIST_INIT(&a->fd_taps); | 
 | 		cv_init(&a->cv); | 
 | 		qlock_init(&a->qlock); | 
 | 		init_awaiter(&a->a_waiter, proc_alarm_handler); | 
 | 		spin_lock(&p->alarmset.lock); | 
 | 		a->id = p->alarmset.id_counter++; | 
 | 		proc_incref(p, 1); | 
 | 		a->proc = p; | 
 | 		TAILQ_INSERT_TAIL(&p->alarmset.list, a, link); | 
 | 		spin_unlock(&p->alarmset.lock); | 
 | 		mkqid(&c->qid, QID(a, Qctl), 0, QTFILE); | 
 | 		break; | 
 | 	case Qctl: | 
 | 	case Qtimer: | 
 | 	case Qperiod: | 
 | 	case Qcount: | 
 | 		/* the purpose of opening is to hold a kref on the proc_alarm */ | 
 | 		a = QID2A(c->qid); | 
 | 		assert(a); | 
 | 		/* this isn't a valid pointer yet, since our chan doesn't have a | 
 | 		 * ref.  since the time that walk gave our chan the qid, the | 
 | 		 * chan could have been closed, and the alarm decref'd and | 
 | 		 * freed.  the qid is essentially an uncounted reference, and we | 
 | 		 * need to go to the source to attempt to get a real ref. | 
 | 		 * Unfortunately, this is another scan of the list, same as | 
 | 		 * devsrv. */ | 
 | 		spin_lock(&p->alarmset.lock); | 
 | 		TAILQ_FOREACH(a_i, &p->alarmset.list, link) { | 
 | 			if (a_i == a) { | 
 | 				assert(a->proc == current); | 
 | 				/* it's still possible we're not getting the | 
 | 				 * ref, racing with the release method */ | 
 | 				if (!kref_get_not_zero(&a->kref, 1)) { | 
 | 					/* lost the race; error out later */ | 
 | 					a_i = 0; | 
 | 				} | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 		spin_unlock(&p->alarmset.lock); | 
 | 		if (!a_i) | 
 | 			error(EFAIL, | 
 | 			      "Unable to open alarm, concurrent closing"); | 
 | 		break; | 
 | 	} | 
 | 	c->mode = openmode(omode); | 
 | 	/* Assumes c is unique (can't be closed concurrently */ | 
 | 	c->flag |= COPEN; | 
 | 	c->offset = 0; | 
 | 	return c; | 
 | } | 
 |  | 
 | static void alarmclose(struct chan *c) | 
 | { | 
 | 	/* There are more closes than opens.  For instance, sysstat doesn't | 
 | 	 * open, but it will close the chan it got from namec.  We only want to | 
 | 	 * clean up/decref chans that were actually open. */ | 
 | 	if (!(c->flag & COPEN)) | 
 | 		return; | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qctl: | 
 | 	case Qtimer: | 
 | 	case Qperiod: | 
 | 	case Qcount: | 
 | 		kref_put(&QID2A(c->qid)->kref); | 
 | 		break; | 
 | 	} | 
 | } | 
 |  | 
 | /* Helper for Qcount to encapsulate timerfd. */ | 
 | static long read_qcount(struct chan *c, void *ubuf, size_t n) | 
 | { | 
 | 	ERRSTACK(1); | 
 | 	struct proc_alarm *a = QID2A(c->qid); | 
 | 	struct cv_lookup_elm cle; | 
 | 	unsigned long old_count; | 
 |  | 
 | 	if (n > sizeof(old_count)) | 
 | 		error(EINVAL, "timerfd buffer is too small (%llu)", n); | 
 | 	/* TODO: have easily abortable CVs that don't require this mechanism. */ | 
 | 	cv_lock(&a->cv); | 
 | 	__reg_abortable_cv(&cle, &a->cv); | 
 | 	if (waserror()) { | 
 | 		cv_unlock(&a->cv); | 
 | 		dereg_abortable_cv(&cle); | 
 | 		nexterror(); | 
 | 	} | 
 | 	while (!a->count) { | 
 | 		if (c->flag & O_NONBLOCK) | 
 | 			error(EAGAIN, "#alarm count was 0"); | 
 | 		if (should_abort(&cle)) | 
 | 			error(EINTR, "syscall aborted"); | 
 | 		cv_wait(&a->cv); | 
 | 	} | 
 | 	old_count = a->count; | 
 | 	a->count = 0; | 
 | 	cv_unlock(&a->cv); | 
 | 	dereg_abortable_cv(&cle); | 
 | 	poperror(); | 
 | 	if (copy_to_user(ubuf, &old_count, sizeof(old_count))) | 
 | 		error(EFAULT, "timerfd copy_to_user failed"); | 
 | 	return sizeof(old_count); | 
 | } | 
 |  | 
 | static size_t alarmread(struct chan *c, void *ubuf, size_t n, off64_t offset) | 
 | { | 
 | 	struct proc_alarm *p_alarm; | 
 |  | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qtopdir: | 
 | 	case Qalarmdir: | 
 | 		return devdirread(c, ubuf, n, 0, 0, alarmgen); | 
 | 	case Qctl: | 
 | 		p_alarm = QID2A(c->qid); | 
 | 		/* simple reads from p_alarm shouldn't need a lock */ | 
 | 		return readnum(offset, ubuf, n, p_alarm->id, NUMSIZE32); | 
 | 	case Qtimer: | 
 | 		p_alarm = QID2A(c->qid); | 
 | 		return readnum(offset, ubuf, n, p_alarm->a_waiter.wake_up_time, | 
 | 					   NUMSIZE64); | 
 | 	case Qperiod: | 
 | 		p_alarm = QID2A(c->qid); | 
 | 		return readnum(offset, ubuf, n, p_alarm->period, NUMSIZE64); | 
 | 	case Qcount: | 
 | 		return read_qcount(c, ubuf, n);	/* ignore offset */ | 
 | 	default: | 
 | 		panic("Bad QID %p in devalarm", c->qid.path); | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* Helper, sets the procalarm to hexval (abs TSC ticks).  0 disarms. */ | 
 | static void set_proc_alarm(struct proc_alarm *a, uint64_t hexval) | 
 | { | 
 | 	/* Due to how we have to maintain 'count', we need to strictly account | 
 | 	 * for the firings of the alarm.  Easiest thing is to disarm it, reset | 
 | 	 * everything, then rearm it.  Note that if someone is blocked on count | 
 | 	 * = 0, they may still be blocked until the next time the alarm fires. | 
 | 	 * | 
 | 	 * unset waits on the handler, which grabs the cv lock, so we don't grab | 
 | 	 * the cv lock.  However, we still need to protect ourselves from | 
 | 	 * multiple setters trying to run this at once.  Unset actually can | 
 | 	 * handle being called concurrently, but alarm setters can't, nor can it | 
 | 	 * handle the unsets and sets getting out of sync.  For instance, two | 
 | 	 * unsets followed by two sets would be a bug.  Likewise, setting the | 
 | 	 * awaiter value while it is on a tchain is a bug.  The qlock prevents | 
 | 	 * that. */ | 
 | 	qlock(&a->qlock); | 
 | 	unset_alarm(a->proc->alarmset.tchain, &a->a_waiter); | 
 | 	cv_lock(&a->cv); | 
 | 	a->count = 0; | 
 | 	if (hexval) { | 
 | 		set_awaiter_abs(&a->a_waiter, hexval); | 
 | 		set_alarm(a->proc->alarmset.tchain, &a->a_waiter); | 
 | 	} | 
 | 	cv_unlock(&a->cv); | 
 | 	qunlock(&a->qlock); | 
 | } | 
 |  | 
 | /* Note that in read and write we have an open chan, which means we have an | 
 |  * active kref on the p_alarm.  Also note that we make no assumptions about | 
 |  * current here - we find the proc (and the tchain) via the ref stored in the | 
 |  * proc_alarm. */ | 
 | static size_t alarmwrite(struct chan *c, void *ubuf, size_t n, off64_t unused) | 
 | { | 
 | 	struct proc_alarm *p_alarm; | 
 |  | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qtopdir: | 
 | 	case Qalarmdir: | 
 | 	case Qctl: | 
 | 	case Qcount: | 
 | 		error(EPERM, ERROR_FIXME); | 
 | 	case Qtimer: | 
 | 		set_proc_alarm(QID2A(c->qid), strtoul_from_ubuf(ubuf, n, 16)); | 
 | 		break; | 
 | 	case Qperiod: | 
 | 		p_alarm = QID2A(c->qid); | 
 | 		/* racing with the handler which checks the val repeatedly */ | 
 | 		cv_lock(&p_alarm->cv); | 
 | 		p_alarm->period = strtoul_from_ubuf(ubuf, n, 16); | 
 | 		cv_unlock(&p_alarm->cv); | 
 | 		break; | 
 | 	default: | 
 | 		panic("Bad QID %p in devalarm", c->qid.path); | 
 | 	} | 
 | 	return n; | 
 | } | 
 |  | 
 | /* We use the same tap list, regardless of Qtimer or Qcount */ | 
 | static int tap_alarm(struct proc_alarm *a, struct fd_tap *tap, int cmd, | 
 |                      int legal_filter) | 
 | { | 
 | 	int ret; | 
 |  | 
 | 	if (tap->filter & ~legal_filter) { | 
 | 		set_error(ENOSYS, "Unsupported #%s tap %p, must be %p", | 
 | 			  devname(), tap->filter, legal_filter); | 
 | 		return -1; | 
 | 	} | 
 | 	cv_lock(&a->cv); | 
 | 	switch (cmd) { | 
 | 	case (FDTAP_CMD_ADD): | 
 | 		SLIST_INSERT_HEAD(&a->fd_taps, tap, link); | 
 | 		ret = 0; | 
 | 		break; | 
 | 	case (FDTAP_CMD_REM): | 
 | 		SLIST_REMOVE(&a->fd_taps, tap, fd_tap, link); | 
 | 		ret = 0; | 
 | 		break; | 
 | 	default: | 
 | 		set_error(ENOSYS, "Unsupported #%s tap command %p", | 
 | 				  devname(), cmd); | 
 | 		ret = -1; | 
 | 	} | 
 | 	cv_unlock(&a->cv); | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int alarm_tapfd(struct chan *c, struct fd_tap *tap, int cmd) | 
 | { | 
 | 	struct proc_alarm *a = QID2A(c->qid); | 
 |  | 
 | 	/* We don't actually support HANGUP, but epoll implies it. */ | 
 | 	#define ALARM_LEGAL_TIMER_TAPS (FDTAP_FILT_WRITTEN | FDTAP_FILT_HANGUP) | 
 | 	#define ALARM_LEGAL_COUNT_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_HANGUP) | 
 |  | 
 | 	switch (TYPE(c->qid)) { | 
 | 	case Qtimer: | 
 | 		return tap_alarm(a, tap, cmd, ALARM_LEGAL_TIMER_TAPS); | 
 | 	case Qcount: | 
 | 		return tap_alarm(a, tap, cmd, ALARM_LEGAL_COUNT_TAPS); | 
 | 	default: | 
 | 		set_error(ENOSYS, "Can't tap #%s file type %d", devname(), | 
 | 		          c->qid.path); | 
 | 		return -1; | 
 | 	} | 
 | } | 
 |  | 
 | static char *alarm_chaninfo(struct chan *ch, char *ret, size_t ret_l) | 
 | { | 
 | 	struct proc_alarm *a; | 
 | 	struct timespec ts; | 
 |  | 
 | 	switch (TYPE(ch->qid)) { | 
 | 	case Qctl: | 
 | 	case Qtimer: | 
 | 	case Qperiod: | 
 | 	case Qcount: | 
 | 		a = QID2A(ch->qid); | 
 | 		ts = tsc2timespec(a->a_waiter.wake_up_time); | 
 | 		snprintf(ret, ret_l, | 
 | 		         "Id %d, %s, expires [%7d.%09d] (%p), period %llu, count %llu", | 
 | 		         a->id, | 
 | 		         SLIST_EMPTY(&a->fd_taps) ? "untapped" : "tapped", | 
 | 		         ts.tv_sec, ts.tv_nsec, a->a_waiter.wake_up_time, | 
 | 		         a->period, a->count); | 
 | 		break; | 
 | 	default: | 
 | 		return devchaninfo(ch, ret, ret_l); | 
 | 	} | 
 | 	return ret; | 
 | } | 
 |  | 
 | struct dev alarmdevtab __devtab = { | 
 | 	.name = "alarm", | 
 |  | 
 | 	.reset = devreset, | 
 | 	.init = alarminit, | 
 | 	.shutdown = devshutdown, | 
 | 	.attach = alarmattach, | 
 | 	.walk = alarmwalk, | 
 | 	.stat = alarmstat, | 
 | 	.open = alarmopen, | 
 | 	.create = devcreate, | 
 | 	.close = alarmclose, | 
 | 	.read = alarmread, | 
 | 	.bread = devbread, | 
 | 	.write = alarmwrite, | 
 | 	.bwrite = devbwrite, | 
 | 	.remove = devremove, | 
 | 	.wstat = devwstat, | 
 | 	.power = devpower, | 
 | 	.chaninfo = alarm_chaninfo, | 
 | 	.tapfd = alarm_tapfd, | 
 | }; |