ruby-dtrace-consumer 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/LICENCE +20 -0
  2. data/README.md +51 -0
  3. data/ext/Makefile +187 -0
  4. data/ext/dtrace_aggdata.c +132 -0
  5. data/ext/dtrace_aggdata.c~ +141 -0
  6. data/ext/dtrace_aggdata.o +0 -0
  7. data/ext/dtrace_api.bundle +0 -0
  8. data/ext/dtrace_api.c +102 -0
  9. data/ext/dtrace_api.c~ +113 -0
  10. data/ext/dtrace_api.h +138 -0
  11. data/ext/dtrace_api.h~ +155 -0
  12. data/ext/dtrace_api.o +0 -0
  13. data/ext/dtrace_bufdata.c +130 -0
  14. data/ext/dtrace_bufdata.c~ +139 -0
  15. data/ext/dtrace_bufdata.o +0 -0
  16. data/ext/dtrace_dropdata.c +121 -0
  17. data/ext/dtrace_dropdata.c~ +131 -0
  18. data/ext/dtrace_dropdata.o +0 -0
  19. data/ext/dtrace_errdata.c +100 -0
  20. data/ext/dtrace_errdata.c~ +110 -0
  21. data/ext/dtrace_errdata.o +0 -0
  22. data/ext/dtrace_hdl.c +677 -0
  23. data/ext/dtrace_hdl.c~ +689 -0
  24. data/ext/dtrace_hdl.o +0 -0
  25. data/ext/dtrace_probedata.c +273 -0
  26. data/ext/dtrace_probedata.c~ +283 -0
  27. data/ext/dtrace_probedata.o +0 -0
  28. data/ext/dtrace_probedesc.c +93 -0
  29. data/ext/dtrace_probedesc.c~ +78 -0
  30. data/ext/dtrace_probedesc.o +0 -0
  31. data/ext/dtrace_process.c +44 -0
  32. data/ext/dtrace_process.c~ +56 -0
  33. data/ext/dtrace_process.o +0 -0
  34. data/ext/dtrace_program.c +52 -0
  35. data/ext/dtrace_program.c~ +62 -0
  36. data/ext/dtrace_program.o +0 -0
  37. data/ext/dtrace_programinfo.c +70 -0
  38. data/ext/dtrace_programinfo.c~ +60 -0
  39. data/ext/dtrace_programinfo.o +0 -0
  40. data/ext/dtrace_recdesc.c +37 -0
  41. data/ext/dtrace_recdesc.c~ +46 -0
  42. data/ext/dtrace_recdesc.o +0 -0
  43. data/ext/dtrace_util.c +92 -0
  44. data/ext/dtrace_util.o +0 -0
  45. data/ext/extconf.rb +7 -0
  46. data/lib/dtrace.rb +95 -0
  47. data/lib/dtrace/aggregate.rb +40 -0
  48. data/lib/dtrace/aggregateset.rb +19 -0
  49. data/lib/dtrace/consumer.rb +174 -0
  50. data/lib/dtrace/data.rb +85 -0
  51. data/lib/dtrace/dof.rb +8 -0
  52. data/lib/dtrace/printfrecord.rb +10 -0
  53. data/lib/dtrace/probedata.rb +23 -0
  54. data/lib/dtrace/probedesc.rb +15 -0
  55. data/lib/dtrace/record.rb +11 -0
  56. data/lib/dtrace/stackrecord.rb +31 -0
  57. data/lib/dtrace/tracer.rb +35 -0
  58. data/lib/dtrace/version.rb +8 -0
  59. data/lib/dtrace/version.rb~ +8 -0
  60. data/lib/dtraceconsumer.rb +9 -0
  61. data/test/test_aggregates.rb +45 -0
  62. data/test/test_drops_errors.rb +166 -0
  63. data/test/test_dtrace.rb +155 -0
  64. data/test/test_gc.rb +11 -0
  65. data/test/test_helper.rb +20 -0
  66. data/test/test_helper.rb~ +16 -0
  67. data/test/test_legacy_consumer.rb +47 -0
  68. data/test/test_probedata.rb +30 -0
  69. data/test/test_processes.rb +66 -0
  70. data/test/test_profile.rb +198 -0
  71. data/test/test_repeat.rb +50 -0
  72. data/test/test_rubyprobe.rb +52 -0
  73. data/test/test_rubyprobe.rb~ +52 -0
  74. data/test/test_typefilter.rb +94 -0
  75. metadata +121 -0
@@ -0,0 +1,689 @@
1
+ /* Ruby-DTrace
2
+ * (c) 2007 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ RUBY_EXTERN VALUE eDTraceException;
8
+
9
+ RUBY_EXTERN VALUE cDTrace;
10
+ RUBY_EXTERN VALUE cDTraceProbeDesc;
11
+ RUBY_EXTERN VALUE cDTraceProgram;
12
+ RUBY_EXTERN VALUE cDTraceRecDesc;
13
+ RUBY_EXTERN VALUE cDTraceProbeData;
14
+ RUBY_EXTERN VALUE cDTraceBufData;
15
+ RUBY_EXTERN VALUE cDTraceProcess;
16
+ RUBY_EXTERN VALUE cDTraceDropData;
17
+ RUBY_EXTERN VALUE cDTraceErrData;
18
+
19
+ static void dtrace_hdl_free(void *arg)
20
+ {
21
+ dtrace_handle_t *handle = (dtrace_handle_t *)arg;
22
+ VALUE proc;
23
+
24
+ if (handle->hdl != NULL) {
25
+ if (handle->procs != Qnil) {
26
+ while ((proc = rb_ary_pop(handle->procs)) != Qnil) {
27
+ dtrace_process_release(proc);
28
+ }
29
+ }
30
+ dtrace_close(handle->hdl);
31
+ }
32
+ free(handle);
33
+ }
34
+
35
+ static void dtrace_hdl_mark(void *arg)
36
+ {
37
+ dtrace_handle_t *handle = (dtrace_handle_t *)arg;
38
+
39
+ if (handle) {
40
+ rb_gc_mark(handle->probe);
41
+ rb_gc_mark(handle->rec);
42
+ rb_gc_mark(handle->buf);
43
+ rb_gc_mark(handle->err);
44
+ rb_gc_mark(handle->drop);
45
+ rb_gc_mark(handle->procs);
46
+ }
47
+ }
48
+
49
+ VALUE dtrace_hdl_alloc(VALUE klass)
50
+ {
51
+ dtrace_hdl_t *hdl;
52
+ dtrace_handle_t *handle;
53
+ int err;
54
+ VALUE obj;
55
+
56
+ hdl = dtrace_open(DTRACE_VERSION, 0, &err);
57
+
58
+ if (hdl) {
59
+ /*
60
+ * Leopard's DTrace requires symbol resolution to be
61
+ * switched on explicitly
62
+ */
63
+ #ifdef __APPLE__
64
+ (void) dtrace_setopt(hdl, "stacksymbols", "enabled");
65
+ #endif
66
+
67
+ /* always request flowindent information */
68
+ (void) dtrace_setopt(hdl, "flowindent", 0);
69
+
70
+ handle = ALLOC(dtrace_handle_t);
71
+ if (!handle) {
72
+ rb_raise(eDTraceException, "alloc failed");
73
+ return Qnil;
74
+ }
75
+
76
+ handle->hdl = hdl;
77
+ handle->probe = Qnil;
78
+ handle->rec = Qnil;
79
+ handle->buf = Qnil;
80
+ handle->err = Qnil;
81
+ handle->drop = Qnil;
82
+ handle->procs = Qnil;
83
+
84
+ obj = Data_Wrap_Struct(klass, dtrace_hdl_mark, dtrace_hdl_free, handle);
85
+ return obj;
86
+ }
87
+ else {
88
+ rb_raise(eDTraceException, "unable to open dtrace: %s (not root?)", strerror(err));
89
+ return Qnil;
90
+ }
91
+ }
92
+
93
+ /* :nodoc: */
94
+ VALUE dtrace_init(VALUE self)
95
+ {
96
+ dtrace_handle_t *handle;
97
+
98
+ Data_Get_Struct(self, dtrace_handle_t, handle);
99
+ if (handle)
100
+ return self;
101
+ else
102
+ return Qnil;
103
+ }
104
+
105
+ VALUE dtrace_hdl_close(VALUE self)
106
+ {
107
+ dtrace_handle_t *handle;
108
+
109
+ Data_Get_Struct(self, dtrace_handle_t, handle);
110
+ dtrace_close(handle->hdl);
111
+ handle->hdl = NULL;
112
+
113
+ return Qnil;
114
+ }
115
+
116
+ static
117
+ int _dtrace_next_probe(dtrace_hdl_t *hdl, const dtrace_probedesc_t *pdp, void *arg)
118
+ {
119
+ VALUE probe;
120
+
121
+ probe = Data_Wrap_Struct(cDTraceProbeDesc, 0, NULL, (dtrace_probedesc_t *)pdp);
122
+
123
+ rb_yield(probe);
124
+ return 0;
125
+ }
126
+
127
+ /*
128
+ * Yields each probe found on the system.
129
+ * (equivalent to dtrace -l)
130
+ *
131
+ * Each probe is represented by a DTraceProbe object
132
+ */
133
+ VALUE dtrace_each_probe_all(VALUE self)
134
+ {
135
+ dtrace_handle_t *handle;
136
+
137
+ Data_Get_Struct(self, dtrace_handle_t, handle);
138
+ (void) dtrace_probe_iter(handle->hdl, NULL, _dtrace_next_probe, NULL);
139
+
140
+ return self;
141
+ }
142
+
143
+ /*
144
+ * Yields each probe found on the system, matching against a
145
+ * partial name.
146
+ * (equivalent to dtrace -l -n 'probe:::spec')
147
+ *
148
+ * Each probe is represented by a DTraceProbe object
149
+ */
150
+ VALUE dtrace_each_probe_match(VALUE self, VALUE provider, VALUE mod, VALUE func, VALUE name)
151
+ {
152
+ dtrace_handle_t *handle;
153
+
154
+ dtrace_probedesc_t desc;
155
+ desc.dtpd_id = 0;
156
+ strcpy(desc.dtpd_provider, RSTRING_PTR(provider));
157
+ strcpy(desc.dtpd_mod, RSTRING_PTR(mod));
158
+ strcpy(desc.dtpd_func, RSTRING_PTR(func));
159
+ strcpy(desc.dtpd_name, RSTRING_PTR(name));
160
+
161
+ Data_Get_Struct(self, dtrace_handle_t, handle);
162
+ (void) dtrace_probe_iter(handle->hdl, &desc, _dtrace_next_probe, NULL);
163
+
164
+ return self;
165
+ }
166
+
167
+ static int
168
+ _dtrace_next_stmt(dtrace_hdl_t *hdl, dtrace_prog_t *program,
169
+ dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last)
170
+ {
171
+ dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
172
+
173
+ if (edp == *last)
174
+ return 0;
175
+
176
+ if (dtrace_probe_iter(hdl, &edp->dted_probe, _dtrace_next_probe, NULL) != 0) {
177
+ rb_raise(eDTraceException, "failed to match %s:%s:%s:%s: %s\n",
178
+ edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod,
179
+ edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name,
180
+ dtrace_errmsg(hdl, dtrace_errno(hdl)));
181
+
182
+ }
183
+
184
+ *last = edp;
185
+ return 0;
186
+ }
187
+
188
+ /*
189
+ * Yields each probe enabled by the given D program.
190
+ * (equivalent to dtrace -n -s program.d)
191
+ */
192
+ VALUE dtrace_each_probe_prog(VALUE self, VALUE program)
193
+ {
194
+ dtrace_handle_t *handle;
195
+ dtrace_prog_t *prog;
196
+ dtrace_ecbdesc_t *last = NULL;
197
+
198
+ Data_Get_Struct(self, dtrace_handle_t, handle);
199
+ Data_Get_Struct(program, dtrace_prog_t, prog);
200
+
201
+ (void) dtrace_stmt_iter(handle->hdl, prog, (dtrace_stmt_f *)_dtrace_next_stmt, &last);
202
+ return Qnil;
203
+ }
204
+
205
+ /*
206
+ * Compile a D program.
207
+ *
208
+ * Arguments:
209
+ * * The program text to compile
210
+ * * (Optionally) any arguments required by the program
211
+ *
212
+ * Raises a DTraceException if the program cannot be compiled.
213
+ */
214
+ VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
215
+ {
216
+ dtrace_handle_t *handle;
217
+ dtrace_prog_t *program;
218
+ VALUE dtrace_program;
219
+
220
+ VALUE dtrace_text;
221
+ int dtrace_argc;
222
+ VALUE dtrace_argv_array;
223
+
224
+ char **dtrace_argv;
225
+ int i;
226
+
227
+ rb_scan_args(argc, argv, "1*", &dtrace_text, &dtrace_argv_array);
228
+
229
+ dtrace_argc = rb_ary_len(dtrace_argv_array);
230
+ dtrace_argv = ALLOC_N(char *, dtrace_argc + 1);
231
+ if (!dtrace_argv) {
232
+ rb_raise(eDTraceException, "alloc failed");
233
+ return Qnil;
234
+ }
235
+
236
+ for (i = 0; i < dtrace_argc; i++) {
237
+ dtrace_argv[i + 1] = strdup(RSTRING_PTR(rb_ary_entry(dtrace_argv_array, i)));
238
+ }
239
+
240
+ dtrace_argv[0] = "ruby";
241
+ dtrace_argc++;
242
+
243
+ Data_Get_Struct(self, dtrace_handle_t, handle);
244
+ program = dtrace_program_strcompile(
245
+ handle->hdl, RSTRING_PTR(dtrace_text),
246
+ DTRACE_PROBESPEC_NAME, DTRACE_C_PSPEC,
247
+ dtrace_argc, dtrace_argv
248
+ );
249
+
250
+ if (!program) {
251
+ rb_raise(eDTraceException, "%s", dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
252
+ return Qnil;
253
+ }
254
+ else {
255
+ dtrace_program = Data_Wrap_Struct(cDTraceProgram, 0, NULL, program);
256
+ rb_iv_set(dtrace_program, "@handle", self);
257
+ return dtrace_program;
258
+ }
259
+ }
260
+
261
+ /*
262
+ * Start tracing. Must be called once a program has been successfully
263
+ * compiled and executed.
264
+ *
265
+ * Raises a DTraceException on any error.
266
+ */
267
+ VALUE dtrace_hdl_go(VALUE self)
268
+ {
269
+ dtrace_handle_t *handle;
270
+
271
+ Data_Get_Struct(self, dtrace_handle_t, handle);
272
+ if (dtrace_go(handle->hdl) < 0)
273
+ rb_raise(eDTraceException, "%s", dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
274
+
275
+ return Qnil;
276
+ }
277
+
278
+ /*
279
+ * Returns the status of the DTrace handle.
280
+ *
281
+ * Status values are defined as:
282
+ *
283
+ * * 0 - none
284
+ * * 1 - ok
285
+ * * 4 - stopped
286
+ */
287
+ VALUE dtrace_hdl_status(VALUE self)
288
+ {
289
+ dtrace_handle_t *handle;
290
+ int status;
291
+
292
+ Data_Get_Struct(self, dtrace_handle_t, handle);
293
+ if ((status = dtrace_status(handle->hdl)) < 0)
294
+ rb_raise(eDTraceException, "%s", dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
295
+
296
+ return INT2FIX(status);
297
+ }
298
+
299
+ /*
300
+ * Set an option on the DTrace handle.
301
+ *
302
+ * Options which may be set:
303
+ *
304
+ * * aggsize
305
+ * * bufsize
306
+ */
307
+ VALUE dtrace_hdl_setopt(VALUE self, VALUE key, VALUE value)
308
+ {
309
+ dtrace_handle_t *handle;
310
+ int ret;
311
+
312
+ Data_Get_Struct(self, dtrace_handle_t, handle);
313
+
314
+ if (NIL_P(value)) {
315
+ ret = dtrace_setopt(handle->hdl, RSTRING_PTR(key), 0);
316
+ }
317
+ else {
318
+ ret = dtrace_setopt(handle->hdl, RSTRING_PTR(key), RSTRING_PTR(value));
319
+ }
320
+
321
+ if (ret < 0)
322
+ rb_raise(eDTraceException, "%s", dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
323
+
324
+ return Qnil;
325
+ }
326
+
327
+ /* Stop tracing.
328
+ *
329
+ * Must be called after go has been called to start tracing.
330
+ */
331
+ VALUE dtrace_hdl_stop(VALUE self)
332
+ {
333
+ dtrace_handle_t *handle;
334
+
335
+ Data_Get_Struct(self, dtrace_handle_t, handle);
336
+ if (dtrace_stop(handle->hdl) < 0)
337
+ rb_raise(eDTraceException, "%s",
338
+ dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
339
+
340
+ return Qnil;
341
+ }
342
+
343
+ /*
344
+ * Return the most recent DTrace error.
345
+ */
346
+ VALUE dtrace_hdl_error(VALUE self)
347
+ {
348
+ dtrace_handle_t *handle;
349
+ const char *error_string;
350
+
351
+ Data_Get_Struct(self, dtrace_handle_t, handle);
352
+ error_string = dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl));
353
+ return rb_str_new2(error_string);
354
+ }
355
+
356
+ /*
357
+ * Sleep until we need to wake up to honour D options controlling
358
+ * consumption rates.
359
+ */
360
+ VALUE dtrace_hdl_sleep(VALUE self)
361
+ {
362
+ dtrace_handle_t *handle;
363
+
364
+ Data_Get_Struct(self, dtrace_handle_t, handle);
365
+ dtrace_sleep(handle->hdl);
366
+ return Qnil;
367
+ }
368
+
369
+ static int _probe_consumer(const dtrace_probedata_t *data, void *arg)
370
+ {
371
+ VALUE proc;
372
+ dtrace_work_handlers_t handlers;
373
+ VALUE probedata;
374
+
375
+ handlers = *(dtrace_work_handlers_t *) arg;
376
+ proc = handlers.probe;
377
+
378
+ if (!NIL_P(proc)) {
379
+ probedata = Data_Wrap_Struct(cDTraceProbeData, 0, NULL,
380
+ (dtrace_probedata_t *)data);
381
+
382
+ rb_iv_set(probedata, "@handle", handlers.handle);
383
+ rb_funcall(proc, rb_intern("call"), 1, probedata);
384
+ }
385
+
386
+ return (DTRACE_CONSUME_THIS);
387
+ }
388
+
389
+ static int _rec_consumer(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
390
+ {
391
+ VALUE proc;
392
+ dtrace_work_handlers_t handlers;
393
+ VALUE recdesc;
394
+ VALUE probedata;
395
+
396
+ dtrace_actkind_t act;
397
+
398
+ handlers = *(dtrace_work_handlers_t *) arg;
399
+ proc = handlers.rec;
400
+ if (!NIL_P(proc)) {
401
+ if (rec) {
402
+ recdesc = Data_Wrap_Struct(cDTraceRecDesc, 0, NULL, (dtrace_recdesc_t *)rec);
403
+ rb_iv_set(recdesc, "@handle", handlers.handle);
404
+ rb_funcall(proc, rb_intern("call"), 1, recdesc);
405
+ }
406
+ else {
407
+ rb_funcall(proc, rb_intern("call"), 1, Qnil);
408
+ return (DTRACE_CONSUME_NEXT);
409
+ }
410
+ }
411
+
412
+ if (rec) {
413
+ act = rec->dtrd_action;
414
+ if (act == DTRACEACT_EXIT)
415
+ return (DTRACE_CONSUME_NEXT);
416
+ }
417
+
418
+ return (DTRACE_CONSUME_THIS);
419
+ }
420
+
421
+ static int _buf_consumer(const dtrace_bufdata_t *bufdata, void *arg)
422
+ {
423
+ VALUE proc;
424
+ VALUE dtracebufdata;
425
+
426
+ proc = (VALUE)arg;
427
+
428
+ if (!NIL_P(proc)) {
429
+ dtracebufdata = Data_Wrap_Struct(cDTraceBufData, 0, NULL, (dtrace_bufdata_t *)bufdata);
430
+ rb_funcall(proc, rb_intern("call"), 1, dtracebufdata);
431
+ }
432
+
433
+ return (DTRACE_HANDLE_OK);
434
+ }
435
+
436
+ /*
437
+ * Process any data waiting from the D program.
438
+ *
439
+ * Takes a Proc to which DTraceProbeData objects will be yielded, and
440
+ * an optional second Proc to which DTraceRecDesc objects will be
441
+ * yielded.
442
+ *
443
+ */
444
+ VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self)
445
+ {
446
+ dtrace_handle_t *handle;
447
+ dtrace_workstatus_t status;
448
+ dtrace_work_handlers_t handlers;
449
+ VALUE probe_consumer;
450
+ VALUE rec_consumer;
451
+
452
+ Data_Get_Struct(self, dtrace_handle_t, handle);
453
+
454
+ /* handle args - probe_consumer_proc is mandatory, rec_consumer_proc
455
+ is optional */
456
+ rb_scan_args(argc, argv, "11", &probe_consumer, &rec_consumer);
457
+
458
+ /* to mark during GC */
459
+ handle->probe = probe_consumer;
460
+ if (!NIL_P(rec_consumer))
461
+ handle->rec = rec_consumer;
462
+
463
+ /* fill out the handlers struct */
464
+ handlers.probe = probe_consumer;
465
+ handlers.rec = rec_consumer;
466
+ handlers.handle = self;
467
+
468
+ FILE *devnull = fopen("/dev/null", "w");
469
+ status = dtrace_work(handle->hdl, devnull, _probe_consumer, _rec_consumer, &handlers);
470
+ fclose(devnull);
471
+
472
+ if (status < 0)
473
+ rb_raise(eDTraceException, "%s", dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
474
+
475
+ return INT2FIX(status);
476
+ }
477
+
478
+ /*
479
+ * Set up the buffered output handler for this handle.
480
+ */
481
+ VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer)
482
+ {
483
+ dtrace_handle_t *handle;
484
+ Data_Get_Struct(self, dtrace_handle_t, handle);
485
+
486
+ /* to mark during GC */
487
+ handle->buf = buf_consumer;
488
+
489
+ /* attach the buffered output handler */
490
+ if (dtrace_handle_buffered(handle->hdl, &_buf_consumer, (void *)buf_consumer) == -1) {
491
+ rb_raise(eDTraceException, "failed to establish buffered handler: %s",
492
+ (dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl))));
493
+ }
494
+
495
+ return Qnil;
496
+ }
497
+
498
+ static int _drop_consumer(const dtrace_dropdata_t *dropdata, void *arg)
499
+ {
500
+ VALUE proc;
501
+ VALUE dtracedropdata;
502
+
503
+ proc = (VALUE)arg;
504
+
505
+ if (!NIL_P(proc)) {
506
+ dtracedropdata = Data_Wrap_Struct(cDTraceDropData, 0, NULL, (dtrace_dropdata_t *)dropdata);
507
+ rb_funcall(proc, rb_intern("call"), 1, dtracedropdata);
508
+ }
509
+
510
+ return (DTRACE_HANDLE_OK);
511
+ }
512
+
513
+ /*
514
+ * Set up the drop-record handler for this handle. Takes a block,
515
+ * which will be called with any drop records returned by DTrace,
516
+ * represented by DTraceDropData objects.
517
+ */
518
+ VALUE dtrace_hdl_drop_consumer(VALUE self, VALUE drop_consumer)
519
+ {
520
+ dtrace_handle_t *handle;
521
+ Data_Get_Struct(self, dtrace_handle_t, handle);
522
+
523
+ /* to mark during GC */
524
+ handle->drop = drop_consumer;
525
+
526
+ /* attach the drop-record handler */
527
+ if (dtrace_handle_drop(handle->hdl, &_drop_consumer, (void *)drop_consumer) == -1) {
528
+ rb_raise(eDTraceException, "failed to establish drop-record handler");
529
+ }
530
+
531
+ return Qnil;
532
+ }
533
+
534
+ static int _err_consumer(const dtrace_errdata_t *errdata, void *arg)
535
+ {
536
+ VALUE proc;
537
+ VALUE dtraceerrdata;
538
+
539
+ proc = (VALUE)arg;
540
+
541
+ /* guard against bad invocations where arg is not what we provided... */
542
+ if (TYPE(proc) == T_DATA) {
543
+ dtraceerrdata = Data_Wrap_Struct(cDTraceErrData, 0, NULL,
544
+ (dtrace_errdata_t *)errdata);
545
+ rb_funcall(proc, rb_intern("call"), 1, dtraceerrdata);
546
+ }
547
+ else {
548
+ /* arg looked bad, throw an exception */
549
+ rb_raise(eDTraceException,
550
+ "bad argument to _err_consumer: %p -> type 0x%x\n", arg, TYPE(proc));
551
+ }
552
+
553
+ return (DTRACE_HANDLE_OK);
554
+ }
555
+
556
+ /*
557
+ * Set up the err-record handler for this handle. Takes a block, which
558
+ * will be called with any error records returned by DTrace,
559
+ * represented by DTraceErrData records.
560
+ */
561
+ VALUE dtrace_hdl_err_consumer(VALUE self, VALUE err_consumer)
562
+ {
563
+ dtrace_handle_t *handle;
564
+ void *arg;
565
+ Data_Get_Struct(self, dtrace_handle_t, handle);
566
+
567
+ if (dtrace_status(handle->hdl) != 0) {
568
+ rb_raise(eDTraceException, "too late to add error handler");
569
+ return Qnil;
570
+ }
571
+
572
+ /* to mark during GC */
573
+ handle->err = err_consumer;
574
+
575
+ /* attach the err-record handler */
576
+ if (dtrace_handle_err(handle->hdl, &_err_consumer, (void *)err_consumer) == -1) {
577
+ rb_raise(eDTraceException, "failed to establish err-record handler: %s",
578
+ dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
579
+ }
580
+
581
+ return Qnil;
582
+ }
583
+
584
+ static void _push_proc(dtrace_handle_t *handle, VALUE proc)
585
+ {
586
+ if (handle->procs == Qnil)
587
+ handle->procs = rb_ary_new();
588
+
589
+ rb_ary_push(handle->procs, proc);
590
+ }
591
+
592
+ /*
593
+ * Start a process which will be traced. The pid of the started
594
+ * process will be available in D as $target.
595
+ *
596
+ * Pass an array, where the first element is the full path to the
597
+ * program to start, and subsequent elements are its arguments.
598
+ *
599
+ * Returns a DTraceProcess object which is used to start the process
600
+ * once tracing is set up.
601
+ */
602
+ VALUE dtrace_hdl_createprocess(VALUE self, VALUE rbargv)
603
+ {
604
+ dtrace_handle_t *handle;
605
+ struct ps_prochandle *P;
606
+ char **argv;
607
+ long len;
608
+ int i;
609
+ dtrace_process_t *process;
610
+ VALUE rb_process;
611
+
612
+ Data_Get_Struct(self, dtrace_handle_t, handle);
613
+
614
+ Check_Type(rbargv, T_ARRAY);
615
+ len = rb_ary_len(rbargv);
616
+
617
+ argv = ALLOC_N(char *, len + 1);
618
+ if (!argv) {
619
+ rb_raise(eDTraceException, "alloc failed");
620
+ return Qnil;
621
+ }
622
+
623
+ for (i = 0; i < len; i++)
624
+ argv[i] = strdup(RSTRING_PTR(rb_ary_entry(rbargv, i)));
625
+ argv[len] = NULL;
626
+
627
+ P = dtrace_proc_create(handle->hdl, argv[0], argv);
628
+
629
+ for (i = 0; i < len; i++)
630
+ free(argv[i]);
631
+ free(argv);
632
+
633
+ if (P == NULL)
634
+ rb_raise(eDTraceException, "%s",
635
+ dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
636
+
637
+ process = ALLOC(dtrace_process_t);
638
+ if (!process) {
639
+ rb_raise(eDTraceException, "alloc failed");
640
+ return Qnil;
641
+ }
642
+
643
+ process->handle = handle;
644
+ process->proc = P;
645
+
646
+ rb_process = Data_Wrap_Struct(cDTraceProcess, 0, dtrace_process_free,
647
+ (dtrace_process_t *)process);
648
+
649
+ _push_proc(handle, rb_process);
650
+ return rb_process;
651
+ }
652
+
653
+ /*
654
+ * Grab a currently-running process by pid.
655
+ *
656
+ * Returns a Rb_Process object which is used to start the process
657
+ * once tracing is set up.
658
+ */
659
+ VALUE dtrace_hdl_grabprocess(VALUE self, VALUE pid)
660
+ {
661
+ dtrace_handle_t *handle;
662
+ struct ps_prochandle *P;
663
+ dtrace_process_t *process;
664
+ VALUE rb_process;
665
+
666
+ Data_Get_Struct(self, dtrace_handle_t, handle);
667
+
668
+ P = dtrace_proc_grab(handle->hdl, FIX2INT(pid), 0);
669
+
670
+ if (P == NULL) {
671
+ rb_raise(eDTraceException, "%s",
672
+ dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
673
+ }
674
+
675
+ process = ALLOC(dtrace_process_t);
676
+ if (!process) {
677
+ rb_raise(eDTraceException, "alloc failed");
678
+ return Qnil;
679
+ }
680
+
681
+ process->handle = handle;
682
+ process->proc = P;
683
+
684
+ rb_process = Data_Wrap_Struct(cDTraceProcess, 0, dtrace_process_free,
685
+ (dtrace_process_t *)process);
686
+
687
+ _push_proc(handle, rb_process);
688
+ return rb_process;
689
+ }