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