]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devdtracy.c
53da2c46b3004808a99c01d72fd5126e56d22a42
[plan9front.git] / sys / src / 9 / port / devdtracy.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
8 #include        <dtracy.h>
9
10 Lock *machlocks;
11
12 typedef struct DTKChan DTKChan;
13 typedef struct DTKAux DTKAux;
14 QLock dtracylock;
15
16 struct DTKChan {
17         DTChan *ch;
18         int ref;
19         int idx;
20 };
21 struct DTKAux {
22         char *str;
23 };
24
25 static void
26 prog(DTKChan *p, char *s)
27 {
28         DTClause *c;
29         int rc;
30
31         dtcrun(p->ch, DTCSTOP);
32         dtcreset(p->ch);
33         while(*s != 0){
34                 s = dtclunpack(s, &c);
35                 if(s == nil)
36                         error("invalid program");
37                 rc = dtcaddcl(p->ch, c);
38                 dtclfree(c);
39                 if(rc < 0){
40                         dtcreset(p->ch);
41                         error(up->syserrstr);
42                 }
43         }
44 }
45
46 enum {
47         /* Qdir */
48         Qclone = 1,
49 };
50
51 enum {
52         Qdir,
53         Qctl,
54         Qprog,
55         Qbuf,
56         Qepid,
57         Qaggbuf,
58 };
59
60 static Dirtab dtracydir[] = {
61         "ctl",  { Qctl, 0, 0 }, 0,      0660,
62         "prog", { Qprog, 0, 0 }, 0,     0660,
63         "buf",  { Qbuf, 0, 0, }, 0,     0440,
64         "epid", { Qepid, 0, 0 }, 0,     0440,
65         "aggbuf",       { Qaggbuf, 0, 0 }, 0,   0440,
66 };
67
68 enum {
69         CMstop,
70         CMgo,
71 };
72
73 static Cmdtab dtracyctlmsg[] = {
74         CMstop,         "stop",         1,
75         CMgo,           "go",           1,
76 };
77
78 DTKChan **dtktab;
79 int ndtktab;
80
81 static DTKChan *
82 dtklook(vlong n)
83 {
84         if((uvlong)n >= ndtktab) return nil;
85         return dtktab[n];
86 }
87 #define QIDPATH(q,e) ((q) + 1 << 8 | (e))
88 #define SLOT(q) ((vlong)((q).path >> 8) - 1)
89 #define FILE(q) ((int)(q).path & 0xff)
90
91 static DTKChan *
92 dtknew(void)
93 {
94         DTKChan *p;
95         DTKChan **newtab;
96         int i;
97         
98         p = malloc(sizeof(DTKChan));
99         if(p == nil) error(Enomem);
100         for(i = 0; i < ndtktab; i++)
101                 if(dtktab[i] == nil){
102                         dtktab[i] = p;
103                         p->idx = i;
104                         break;
105                 }
106         if(i == ndtktab){
107                 newtab = realloc(dtktab, (ndtktab + 1) * sizeof(DTKChan *));
108                 if(newtab == nil) error(Enomem);
109                 dtktab = newtab;
110                 dtktab[ndtktab] = p;
111                 p->idx = ndtktab++;
112         }
113         p->ch = dtcnew();
114         return p;
115 }
116
117 static void
118 dtkfree(DTKChan *p)
119 {
120         int idx;
121         
122         idx = p->idx;
123         dtcfree(p->ch);
124         free(p);
125         dtktab[idx] = nil;
126 }
127
128 static int dtracyen;
129
130 static void
131 dtracyinit(void)
132 {
133         dtracyen = getconf("*dtracy") != nil;
134         if(!dtracyen) return;
135         machlocks = smalloc(sizeof(Lock) * conf.nmach);
136         dtinit(conf.nmach);
137 }
138
139 static Chan*
140 dtracyattach(char *spec)
141 {
142         if(!dtracyen)
143                 error("*dtracy= not set");
144         return devattach(L'Δ', spec);
145 }
146
147 static int
148 dtracygen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
149 {
150         Dirtab *tab;
151         uvlong path;
152
153         if(s == DEVDOTDOT){
154                 devdir(c, (Qid){Qdir, 0, QTDIR}, "#Δ", 0, eve, 0555, dp);
155                 return 1;
156         }
157         if(c->qid.path == Qdir){
158                 if(s-- == 0) goto clone;
159                 if(s >= ndtktab) return -1;
160                 if(dtklook(s) == nil) return 0;
161                 sprint(up->genbuf, "%d", s);
162                 devdir(c, (Qid){QIDPATH(s, Qdir), 0, QTDIR}, up->genbuf, 0, eve, DMDIR|0555, dp);
163                 return 1;
164         }
165         if(c->qid.path == Qclone){
166         clone:
167                 strcpy(up->genbuf, "clone");
168                 devdir(c, (Qid){Qclone, 0, QTFILE}, up->genbuf, 0, eve, 0444, dp);
169                 return 1;
170         }
171         if(s >= nelem(dtracydir))
172                 return -1;
173         tab = &dtracydir[s];
174         path = QIDPATH(SLOT(c->qid), 0);
175         devdir(c, (Qid){tab->qid.path|path, tab->qid.vers, tab->qid.type}, tab->name, tab->length, eve, tab->perm, dp);
176         return 1;
177 }
178
179 static Walkqid*
180 dtracywalk(Chan *c, Chan *nc, char **name, int nname)
181 {
182         Walkqid *rc;
183
184         eqlock(&dtracylock);
185         if(waserror()){
186                 qunlock(&dtracylock);
187                 nexterror();
188         }
189         rc = devwalk(c, nc, name, nname, nil, 0, dtracygen);
190         qunlock(&dtracylock);
191         poperror();
192         return rc;
193 }
194
195 static int
196 dtracystat(Chan *c, uchar *dp, int n)
197 {
198         int rc;
199
200         eqlock(&dtracylock);
201         if(waserror()){
202                 qunlock(&dtracylock);
203                 nexterror();
204         }
205         rc = devstat(c, dp, n, nil, 0, dtracygen);
206         qunlock(&dtracylock);
207         poperror();
208         return rc;      
209 }
210
211 static Chan*
212 dtracyopen(Chan *c, int omode)
213 {
214         DTKChan *p;
215         Chan *ch;
216
217         eqlock(&dtracylock);
218         if(waserror()){
219                 qunlock(&dtracylock);
220                 nexterror();
221         }
222         if(c->qid.path == Qclone){
223                 if(!iseve()) error(Eperm);
224                 p = dtknew();
225                 c->qid.path = QIDPATH(p->idx, Qctl);
226         }
227         p = dtklook(SLOT(c->qid));
228         if(SLOT(c->qid) >= 0 && p == nil) error(Enonexist);
229         if(FILE(c->qid) != Qdir && !iseve()) error(Eperm);
230         ch = devopen(c, omode, nil, 0, dtracygen);
231         if(p != nil) p->ref++;
232         qunlock(&dtracylock);
233         poperror();
234         ch->aux = smalloc(sizeof(DTKAux));
235         return ch;
236 }
237
238 static void
239 dtracyclose(Chan *ch)
240 {
241         DTKAux *aux;
242         DTKChan *p;
243
244         if(ch->aux != nil){
245                 eqlock(&dtracylock);
246                 p = dtklook(SLOT(ch->qid));
247                 if(p != nil && --p->ref == 0)
248                         dtkfree(p);
249                 qunlock(&dtracylock);
250                 aux = ch->aux;
251                 free(aux->str);
252                 free(ch->aux);
253                 ch->aux = nil;
254         }
255 }
256
257 static int
258 epidread(DTKAux *aux, DTChan *c, char *a, long n, vlong off)
259 {
260         Fmt f;
261         DTEnab *e;
262
263         if(off == 0){
264                 free(aux->str);
265                 aux->str = nil;
266         }
267         if(aux->str == nil){
268                 fmtstrinit(&f);
269                 for(e = c->enab; e != nil; e = e->channext){
270                         fmtprint(&f, "%d %d %d %s:%s:%s\n", e->epid, e->gr->id, e->gr->reclen,
271                                 e->prob->provider == nil ? "" : e->prob->provider,
272                                 e->prob->function == nil ? "" : e->prob->function,
273                                 e->prob->name == nil ? "" : e->prob->name);
274                 }
275                 aux->str = fmtstrflush(&f);
276         }
277         return readstr(off, a, n, aux->str);
278 }
279
280 static long
281 lockedread(DTChan *c, void *a, long n, int(*readf)(DTChan *, void *, int))
282 {
283         long rc;
284
285         if(waserror()){
286                 qunlock(&dtracylock);
287                 nexterror();
288         }
289         eqlock(&dtracylock);
290         rc = readf(c, a, n);
291         qunlock(&dtracylock);
292         poperror();
293         return rc;
294 }
295
296 static long
297 handleread(DTChan *c, void *a, long n, int(*readf)(DTChan *, void *, int))
298 {
299         long rc, m;
300         int i;
301
302         for(;;){
303                 rc = lockedread(c, a, n, readf);
304                 if(rc < 0) return -1;
305                 if(rc > 0) break;
306                 tsleep(&up->sleep, return0, 0, 250);
307         }
308         m = rc;
309         for(i = 0; i < 3 && m < n/2; i++){
310                 tsleep(&up->sleep, return0, 0, 50);
311                 rc = lockedread(c, (uchar *)a + m, n - m, readf);
312                 if(rc < 0) break;
313                 m += rc;
314         }
315         return m;
316 }
317
318 static long
319 dtracyread(Chan *c, void *a, long n, vlong off)
320 {
321         int rc;
322         DTKChan *p;
323         DTChan *ch;
324
325         eqlock(&dtracylock);
326         if(waserror()){
327                 qunlock(&dtracylock);
328                 nexterror();
329         }
330         if(SLOT(c->qid) == -1)
331                 switch((int)c->qid.path){
332                 case Qdir:
333                         rc = devdirread(c, a, n, nil, 0, dtracygen);
334                         goto out;
335                 default:
336                         error(Egreg);
337                 }
338         p = dtklook(SLOT(c->qid));
339         if(p == nil) error(Enonexist);
340         switch(FILE(c->qid)){
341         case Qdir:
342                 rc = devdirread(c, a, n, nil, 0, dtracygen);
343                 break;
344         case Qctl:
345                 sprint(up->genbuf, "%d", p->idx);
346                 rc = readstr(off, a, n, up->genbuf);
347                 break;
348         case Qbuf:
349                 ch = p->ch;
350                 qunlock(&dtracylock);
351                 poperror();
352                 return handleread(ch, a, n, dtcread);
353         case Qaggbuf:
354                 ch = p->ch;
355                 qunlock(&dtracylock);
356                 poperror();
357                 return handleread(ch, a, n, dtcaggread);
358         case Qepid:
359                 rc = epidread(c->aux, p->ch, a, n, off);
360                 break;
361         default:
362                 error(Egreg);
363                 return 0;
364         }
365 out:
366         qunlock(&dtracylock);
367         poperror();
368         return rc;
369 }
370
371 static long
372 dtracywrite(Chan *c, void *a, long n, vlong)
373 {
374         int rc;
375         DTKChan *p;
376         Cmdbuf *cb;
377         Cmdtab *ct;
378
379         eqlock(&dtracylock);
380         if(waserror()){
381                 qunlock(&dtracylock);
382                 nexterror();
383         }
384         if(SLOT(c->qid) == -1)
385                 switch((int)c->qid.path){
386                 case Qdir:
387                         error(Eperm);
388                 default:
389                         error(Egreg);
390                 }
391         p = dtklook(SLOT(c->qid));
392         if(p == nil) error(Enonexist);
393         switch(FILE(c->qid)){
394         case Qdir:
395                 error(Eperm);
396                 return 0;
397         case Qctl:
398                 cb = parsecmd(a, n);
399                 if(waserror()){
400                         free(cb);
401                         nexterror();
402                 }
403                 ct = lookupcmd(cb, dtracyctlmsg, nelem(dtracyctlmsg));
404                 switch(ct->index){
405                 case CMstop: dtcrun(p->ch, DTCSTOP); break;
406                 case CMgo: dtcrun(p->ch, DTCGO); break;
407                 default:
408                         error(Egreg);
409                 }
410                 poperror();
411                 free(cb);
412                 rc = n;
413                 break;
414         case Qprog:
415                 {
416                         char *buf;
417                         
418                         buf = smalloc(n+1);
419                         if(waserror()){
420                                 free(buf);
421                                 nexterror();
422                         }
423                         memmove(buf, a, n);
424                         prog(p, buf);
425                         free(buf);
426                         poperror();
427                         rc = n;
428                         break;
429                 }
430         default:
431                 error(Egreg);
432                 return 0;
433         }
434         qunlock(&dtracylock);
435         poperror();
436         return rc;
437 }
438
439
440 Dev dtracydevtab = {
441         L'Δ',
442         "dtracy",
443         
444         devreset,
445         dtracyinit,
446         devshutdown,
447         dtracyattach,
448         dtracywalk,
449         dtracystat,
450         dtracyopen,
451         devcreate,
452         dtracyclose,
453         dtracyread,
454         devbread,
455         dtracywrite,
456         devbwrite,
457         devremove,
458         devwstat,
459 };
460
461 void *
462 dtmalloc(ulong n)
463 {
464         void *v;
465
466         v = smalloc(n);
467         setmalloctag(v, getcallerpc(&n));
468         return v;
469 }
470
471 void
472 dtfree(void *v)
473 {
474         free(v);
475 }
476
477 void *
478 dtrealloc(void *v, ulong n)
479 {
480         v = realloc(v, n);
481         if(v != nil)
482                 setrealloctag(v, getcallerpc(&v));
483         return v;
484 }
485
486 void
487 dtmachlock(int i)
488 {
489         ilock(&machlocks[i]);
490 }
491
492 void
493 dtmachunlock(int i)
494 {
495         iunlock(&machlocks[i]);
496 }
497
498 void
499 dtcoherence(void)
500 {
501         coherence();
502 }
503
504 uvlong
505 dttime(void)
506 {
507         return fastticks(nil);
508 }
509
510 uvlong
511 dtgetvar(int v)
512 {
513         switch(v){
514         case DTV_PID:
515                 return up != nil ? up->pid : 0;
516         default:
517                 return 0;
518         }
519 }
520
521 int
522 dtpeek(uvlong addr, void *buf, int len)
523 {
524         if((uintptr)addr != addr || up == nil || !okaddr((uintptr) addr, len, 0)) return -1;
525         memmove(buf, (void *) addr, len);
526         return 0;
527 }