changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/port/devdtracy.c

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