Use FD taps for event delivery for #alarm
[akaros.git] / kern / drivers / dev / alarm.c
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * #alarm: a device for registering per-process alarms.
6  *
7  * Allows a process to set up alarms, which they can tap to get events at a
8  * certain TSC time.
9  *
10  * Every process has their own alarm sets and view of #alarm; gen and friends
11  * look at current's alarmset when it is time to gen or open a file.
12  *
13  * To use, first open #alarm/clone, and that gives you an alarm directory aN,
14  * where N is ID of the alarm.
15  *
16  * ctl takes one command: "cancel", to stop an alarm.  timer takes just the
17  * value (in absolute tsc time) to fire the alarm.  To find out about the timer
18  * firing, put an FD tap on the timer for FDTAP_FILT_WRITTEN.
19  *
20  * While each process has a separate view of #alarm, it is possible to post a
21  * chan to Qctl or Qtimer to #srv.  If another proc has your Qtimer, it can set
22  * it in the past, thereby triggering an immediate event.  More clever than
23  * useful.
24  *
25  * Notes on refcnting (the trickier parts here):
26  * - the proc_alarms have counted references to their proc
27  *              proc won't free til all alarms are closed, which is fine.  we close
28  *              all files in destroy.  if a proc drops a chan in srv, the proc will stay
29  *              alive because the alarm is alive - til that chan is closed (srvremove)
30  *
31  *              other shady ways to keep a chan alive: cd to it!  if it is ., we'd
32  *              keep a ref around.  however, only alarmdir *file* grab refs, not
33  *              directories.
34  *
35  * - proc_alarms are kref'd, since there can be multiple chans per alarm
36  *              the only thing that keeps an alarm alive is a chan on a CTL or TIMER (or
37  *              other file).  when you cloned, you got back an open CTL, which keeps the
38  *              alarm (and the dir) alive.
39  *
40  *              we need to be careful generating krefs, in case alarms are concurrently
41  *              released and removed from the lists.  just like with procs and pid2proc,
42  *              we need to sync with the source of the kref. */
43
44 #include <kmalloc.h>
45 #include <string.h>
46 #include <stdio.h>
47 #include <assert.h>
48 #include <error.h>
49 #include <pmap.h>
50 #include <sys/queue.h>
51 #include <smp.h>
52 #include <kref.h>
53 #include <atomic.h>
54 #include <alarm.h>
55 #include <umem.h>
56 #include <devalarm.h>
57
58 struct dev alarmdevtab;
59
60 static char *devname(void)
61 {
62         return alarmdevtab.name;
63 }
64
65 /* qid path types */
66 #define Qtopdir                                 1
67 #define Qclone                                  2
68 #define Qalarmdir                               3
69 #define Qctl                                    4
70 #define Qtimer                                  5       /* Qctl + 1 */
71
72 /* This paddr/kaddr is a bit dangerous.  it'll work so long as we don't need all
73  * 64 bits for a physical address (48 is the current norm on x86_64). */
74 #define ADDR_SHIFT 5
75 #define QID2A(q) ((struct proc_alarm*)KADDR(((q).path >> ADDR_SHIFT)))
76 #define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1))
77 #define QID(ptr, type) ((PADDR(ptr) << ADDR_SHIFT) | type)
78 extern char *eve;
79
80 static void alarm_release(struct kref *kref)
81 {
82         struct proc_alarm *a = container_of(kref, struct proc_alarm, kref);
83         struct proc *p = a->proc;
84         assert(p);
85         spin_lock(&p->alarmset.lock);
86         TAILQ_REMOVE(&p->alarmset.list, a, link);
87         spin_unlock(&p->alarmset.lock);
88         /* When this returns, the alarm has either fired or it never will */
89         unset_alarm(p->alarmset.tchain, &a->a_waiter);
90         proc_decref(p);
91         kfree(a);
92 }
93
94 static void alarm_fire_taps(struct proc_alarm *a, int filter)
95 {
96         struct fd_tap *tap_i;
97
98         if (SLIST_EMPTY(&a->fd_taps))
99                 return;
100         /* TODO: (RCU) Locking to protect the list and the tap's existence. */
101         spin_lock(&a->tap_lock);
102         SLIST_FOREACH(tap_i, &a->fd_taps, link)
103                 fire_tap(tap_i, filter);
104         spin_unlock(&a->tap_lock);
105 }
106
107 static void proc_alarm_handler(struct alarm_waiter *a_waiter)
108 {
109         struct proc_alarm *a = container_of(a_waiter, struct proc_alarm, a_waiter);
110
111         alarm_fire_taps(a, FDTAP_FILT_WRITTEN);
112 }
113
114 void devalarm_init(struct proc *p)
115 {
116         TAILQ_INIT(&p->alarmset.list);
117         spinlock_init(&p->alarmset.lock);
118         /* Just running all the proc alarms on core 0. */
119         p->alarmset.tchain = &per_cpu_info[0].tchain;
120         p->alarmset.id_counter = 0;
121 }
122
123 static int alarmgen(struct chan *c, char *entry_name,
124                                         struct dirtab *unused, int unused_nr_dirtab,
125                                         int s, struct dir *dp)
126 {
127         struct qid q;
128         struct proc_alarm *a_i;
129         struct proc *p = current;
130         /* Whether we're in one dir or at the top, .. still takes us to the top. */
131         if (s == DEVDOTDOT) {
132                 mkqid(&q, Qtopdir, 0, QTDIR);
133                 devdir(c, q, devname(), 0, eve, 0555, dp);
134                 return 1;
135         }
136         switch (TYPE(c->qid)) {
137                 case Qtopdir:
138                         /* Generate elements for the top level dir.  We support a clone and
139                          * alarm dirs at the top level */
140                         if (s == 0) {
141                                 mkqid(&q, Qclone, 0, QTFILE);
142                                 devdir(c, q, "clone", 0, eve, 0666, dp);
143                                 return 1;
144                         }
145                         s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
146                         /* Gets the s-th element (0 index)
147                          * 
148                          * I would like to take advantage of the state machine and our
149                          * previous answer to get the sth element of the list.  We can get
150                          * at our previous run of gen from dp (struct dir), and use that to
151                          * get the next item.  I'd like to do something like:
152                          *
153                          * if (dp->qid.path >> ADDR_SHIFT)
154                          *      a_i = TAILQ_NEXT(QID2A(dp->qid), link);
155                          *
156                          * Dev would give us a 0'd dp path on the first run, so if we have a
157                          * path, we know we're on an iterative run.  However, the problem is
158                          * that we could have lost the element dp refers to (QID2A(dp->qid))
159                          * since our previous run, so we can't even access that memory to
160                          * check for refcnts or anything.  We need a new model for how gen
161                          * works (probably a gen_start and gen_stop devop, passed as
162                          * parameters to devwalk), so that we can have some invariants
163                          * between gen runs.
164                          *
165                          * Til then, we're stuck with arrays like in #ip (though we can use
166                          * Linux style fdsets) or lousy O(n^2) linked lists (like #srv).
167                          *
168                          * Note that we won't always start a gen loop with s == 0
169                          * (devdirread, for instance) */
170                         spin_lock(&p->alarmset.lock);
171                         TAILQ_FOREACH(a_i, &p->alarmset.list, link) {
172                                 if (s-- == 0)
173                                         break;
174                         }
175                         /* As soon as we unlock, someone could free a_i */
176                         if (!a_i) {
177                                 spin_unlock(&p->alarmset.lock);
178                                 return -1;
179                         }
180                         snprintf(get_cur_genbuf(), GENBUF_SZ, "a%d", a_i->id);
181                         mkqid(&q, QID(a_i, Qalarmdir), 0, QTDIR);
182                         devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
183                         spin_unlock(&p->alarmset.lock);
184                         return 1;
185                 case Qalarmdir:
186                         /* Gen the contents of the alarm dirs */
187                         s += Qctl;      /* first time through, start on Qctl */
188                         switch (s) {
189                                 case Qctl:
190                                         mkqid(&q, QID(QID2A(c->qid), Qctl), 0, QTFILE);
191                                         devdir(c, q, "ctl", 0, eve, 0666, dp);
192                                         return 1;
193                                 case Qtimer:
194                                         mkqid(&q, QID(QID2A(c->qid), Qtimer), 0, QTFILE);
195                                         devdir(c, q, "timer", 0, eve, 0666, dp);
196                                         return 1;
197                         }
198                         return -1;
199                         /* Need to also provide a direct hit for Qclone and all other files
200                          * (at all levels of the hierarchy).  Every file is both generated
201                          * (via the s increments in their respective directories) and
202                          * directly gen-able.  devstat() will call gen with a specific path
203                          * in the qid.  In these cases, we make a dir for whatever they are
204                          * asking for.  Note the qid stays the same.  I think this is what
205                          * the old plan9 comments above devgen were talking about for (ii).
206                          *
207                          * We don't need to do this for the directories - devstat will look
208                          * for the a directory by path and fail.  Then it will manually
209                          * build the stat output (check the -1 case in devstat). */
210                 case Qclone:
211                         devdir(c, c->qid, "clone", 0, eve, 0666, dp);
212                         return 1;
213                 case Qctl:
214                         devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
215                         return 1;
216                 case Qtimer:
217                         devdir(c, c->qid, "timer", 0, eve, 0666, dp);
218                         return 1;
219         }
220         return -1;
221 }
222
223 static void alarminit(void)
224 {
225 }
226
227 static struct chan *alarmattach(char *spec)
228 {
229         struct chan *c = devattach(devname(), spec);
230         mkqid(&c->qid, Qtopdir, 0, QTDIR);
231         return c;
232 }
233
234 static struct walkqid *alarmwalk(struct chan *c, struct chan *nc, char **name,
235                                                                  int nname)
236 {
237         return devwalk(c, nc, name, nname, 0, 0, alarmgen);
238 }
239
240 static int alarmstat(struct chan *c, uint8_t * db, int n)
241 {
242         return devstat(c, db, n, 0, 0, alarmgen);
243 }
244
245 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
246  * the open chan into p's fd table, then decref the chan. */
247 static struct chan *alarmopen(struct chan *c, int omode)
248 {
249         struct proc *p = current;
250         struct proc_alarm *a, *a_i;
251         switch (TYPE(c->qid)) {
252                 case Qtopdir:
253                 case Qalarmdir:
254                         if (omode & O_REMCLO)
255                                 error(EPERM, ERROR_FIXME);
256                         if (omode & O_WRITE)
257                                 error(EISDIR, ERROR_FIXME);
258                         break;
259                 case Qclone:
260                         a = kzmalloc(sizeof(struct proc_alarm), MEM_WAIT);
261                         kref_init(&a->kref, alarm_release, 1);
262                         SLIST_INIT(&a->fd_taps);
263                         spinlock_init(&a->tap_lock);
264                         init_awaiter(&a->a_waiter, proc_alarm_handler);
265                         spin_lock(&p->alarmset.lock);
266                         a->id = p->alarmset.id_counter++;
267                         proc_incref(p, 1);
268                         a->proc = p;
269                         TAILQ_INSERT_TAIL(&p->alarmset.list, a, link);
270                         spin_unlock(&p->alarmset.lock);
271                         mkqid(&c->qid, QID(a, Qctl), 0, QTFILE);
272                         break;
273                 case Qctl:
274                 case Qtimer:
275                         /* the purpose of opening is to hold a kref on the proc_alarm */
276                         a = QID2A(c->qid);
277                         assert(a);
278                         /* this isn't a valid pointer yet, since our chan doesn't have a
279                          * ref.  since the time that walk gave our chan the qid, the chan
280                          * could have been closed, and the alarm decref'd and freed.  the
281                          * qid is essentially an uncounted reference, and we need to go to
282                          * the source to attempt to get a real ref.  Unfortunately, this is
283                          * another scan of the list, same as devsrv. */
284                         spin_lock(&p->alarmset.lock);
285                         TAILQ_FOREACH(a_i, &p->alarmset.list, link) {
286                                 if (a_i == a) {
287                                         assert(a->proc == current);
288                                         /* it's still possible we're not getting the ref, racing
289                                          * with the release method */
290                                         if (!kref_get_not_zero(&a->kref, 1)) {
291                                                 a_i = 0;        /* lost the race, will error out later */
292                                         }
293                                         break;
294                                 }
295                         }
296                         spin_unlock(&p->alarmset.lock);
297                         if (!a_i)
298                                 error(EFAIL, "Unable to open alarm, concurrent closing");
299                         break;
300         }
301         c->mode = openmode(omode);
302         /* Assumes c is unique (can't be closed concurrently */
303         c->flag |= COPEN;
304         c->offset = 0;
305         return c;
306 }
307
308 static void alarmcreate(struct chan *c, char *name, int omode, uint32_t perm)
309 {
310         error(EPERM, ERROR_FIXME);
311 }
312
313 static void alarmremove(struct chan *c)
314 {
315         error(EPERM, ERROR_FIXME);
316 }
317
318 static int alarmwstat(struct chan *c, uint8_t * dp, int n)
319 {
320         error(EFAIL, "No alarmwstat");
321         return 0;
322 }
323
324 static void alarmclose(struct chan *c)
325 {
326         /* There are more closes than opens.  For instance, sysstat doesn't open,
327          * but it will close the chan it got from namec.  We only want to clean
328          * up/decref chans that were actually open. */
329         if (!(c->flag & COPEN))
330                 return;
331         switch (TYPE(c->qid)) {
332                 case Qctl:
333                 case Qtimer:
334                         kref_put(&QID2A(c->qid)->kref);
335                         break;
336         }
337 }
338
339 static long alarmread(struct chan *c, void *ubuf, long n, int64_t offset)
340 {
341         struct proc_alarm *p_alarm;
342         switch (TYPE(c->qid)) {
343                 case Qtopdir:
344                 case Qalarmdir:
345                         return devdirread(c, ubuf, n, 0, 0, alarmgen);
346                 case Qctl:
347                         p_alarm = QID2A(c->qid);
348                         return readnum(offset, ubuf, n, p_alarm->id, NUMSIZE32);
349                 case Qtimer:
350                         p_alarm = QID2A(c->qid);
351                         return readnum(offset, ubuf, n, p_alarm->a_waiter.wake_up_time,
352                                                    NUMSIZE64);
353                 default:
354                         panic("Bad QID %p in devalarm", c->qid.path);
355         }
356         return 0;
357 }
358
359 /* Note that in read and write we have an open chan, which means we have an
360  * active kref on the p_alarm.  Also note that we make no assumptions about
361  * current here - we find the proc (and the tchain) via the ref stored in the
362  * proc_alarm. */
363 static long alarmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
364 {
365         ERRSTACK(1);
366         char num64[NUMSIZE64];
367         struct cmdbuf *cb;
368         struct proc_alarm *p_alarm;
369         uint64_t hexval;
370
371         switch (TYPE(c->qid)) {
372                 case Qtopdir:
373                 case Qalarmdir:
374                         error(EPERM, ERROR_FIXME);
375                 case Qctl:
376                         p_alarm = QID2A(c->qid);
377                         cb = parsecmd(ubuf, n);
378                         if (waserror()) {
379                                 kfree(cb);
380                                 nexterror();
381                         }
382                         if (cb->nf < 1)
383                                 error(EFAIL, "short control request");
384                         if (!strcmp(cb->f[0], "cancel")) {
385                                 unset_alarm(p_alarm->proc->alarmset.tchain, &p_alarm->a_waiter);
386                         } else {
387                                 error(EFAIL, "%s: not implemented", cb->f[0]);
388                         }
389                         kfree(cb);
390                         poperror();
391                         break;
392                 case Qtimer:
393                         /* want to give strtoul a null-terminated buf (can't handle random
394                          * user strings) */
395                         if (n > sizeof(num64)) {
396                                 set_errno(EINVAL);
397                                 error(EFAIL, "attempted to write %d chars, max %d", n,
398                                           sizeof(num64));
399                         }
400                         memcpy(num64, ubuf, n);
401                         num64[n] = 0;   /* enforce trailing 0 */
402                         hexval = strtoul(num64, 0, 16);
403                         p_alarm = QID2A(c->qid);
404                         /* if you don't know if it was running or not, resetting will turn
405                          * it on regardless. */
406                         reset_alarm_abs(p_alarm->proc->alarmset.tchain, &p_alarm->a_waiter,
407                                                         hexval);
408                         break;
409                 default:
410                         panic("Bad QID %p in devalarm", c->qid.path);
411         }
412         return n;
413 }
414
415 static int alarm_tapfd(struct chan *c, struct fd_tap *tap, int cmd)
416 {
417         int ret;
418         struct proc_alarm *a = QID2A(c->qid);
419
420         /* We don't actually support HANGUP, but epoll implies it. */
421         #define ALARM_LEGAL_TIMER_TAPS (FDTAP_FILT_WRITTEN | FDTAP_FILT_HANGUP)
422
423         switch (TYPE(c->qid)) {
424         case Qtimer:
425                 if (tap->filter & ~ALARM_LEGAL_TIMER_TAPS) {
426                         set_error(ENOSYS, "Unsupported #%s tap, must be %p", devname(),
427                                           ALARM_LEGAL_TIMER_TAPS);
428                         return -1;
429                 }
430                 spin_lock(&a->tap_lock);
431                 switch (cmd) {
432                 case (FDTAP_CMD_ADD):
433                         SLIST_INSERT_HEAD(&a->fd_taps, tap, link);
434                         ret = 0;
435                         break;
436                 case (FDTAP_CMD_REM):
437                         SLIST_REMOVE(&a->fd_taps, tap, fd_tap, link);
438                         ret = 0;
439                         break;
440                 default:
441                         set_error(ENOSYS, "Unsupported #%s tap command %p",
442                                           devname(), cmd);
443                         ret = -1;
444                 }
445                 spin_unlock(&a->tap_lock);
446                 return ret;
447         default:
448                 set_error(ENOSYS, "Can't tap #%s file type %d", devname(),
449                           c->qid.path);
450                 return -1;
451         }
452 }
453
454 static char *alarm_chaninfo(struct chan *ch, char *ret, size_t ret_l)
455 {
456         struct proc_alarm *a = QID2A(ch->qid);
457
458         switch (TYPE(ch->qid)) {
459         case Qctl:
460         case Qtimer:
461                 snprintf(ret, ret_l, "Id %d, %s, expires %llu", a->id,
462                          SLIST_EMPTY(&a->fd_taps) ? "untapped" : "tapped",
463                          a->a_waiter.wake_up_time);
464                 break;
465         default:
466                 return devchaninfo(ch, ret, ret_l);
467         }
468         return ret;
469 }
470
471 struct dev alarmdevtab __devtab = {
472         .name = "alarm",
473
474         .reset = devreset,
475         .init = alarminit,
476         .shutdown = devshutdown,
477         .attach = alarmattach,
478         .walk = alarmwalk,
479         .stat = alarmstat,
480         .open = alarmopen,
481         .create = alarmcreate,
482         .close = alarmclose,
483         .read = alarmread,
484         .bread = devbread,
485         .write = alarmwrite,
486         .bwrite = devbwrite,
487         .remove = alarmremove,
488         .wstat = alarmwstat,
489         .power = devpower,
490         .chaninfo = alarm_chaninfo,
491         .tapfd = alarm_tapfd,
492 };