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