ruby-dtrace 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/dtrace_aggdata.c CHANGED
@@ -15,7 +15,8 @@ VALUE dtraceaggdata_init(VALUE self)
15
15
  return self;
16
16
  }
17
17
 
18
-
18
+ /* Returns the value of this aggregate, be it the aggregation value,
19
+ or a member of an aggregation key tuple. */
19
20
  VALUE dtraceaggdata_value(VALUE self)
20
21
  {
21
22
  dtrace_bufdata_t *bufdata;
@@ -118,6 +119,8 @@ VALUE dtraceaggdata_value(VALUE self)
118
119
  return v;
119
120
  }
120
121
 
122
+ /* Return the type of this DtraceAggData: tuple, value or last. Used
123
+ to form tuples and values into DtraceAggregate objects. */
121
124
  VALUE dtraceaggdata_aggtype(VALUE self)
122
125
  {
123
126
  dtrace_bufdata_t *bufdata;
data/ext/dtrace_api.c CHANGED
@@ -12,6 +12,7 @@ VALUE cDtraceAggData;
12
12
  VALUE cDtraceRecDesc;
13
13
  VALUE cDtraceProbeData;
14
14
  VALUE cDtraceBufData;
15
+ VALUE cDtraceProcess;
15
16
 
16
17
  VALUE eDtraceException;
17
18
 
@@ -24,17 +25,19 @@ void Init_dtrace_api() {
24
25
  rb_define_method(cDtrace, "stop", dtrace_hdl_stop, 0); // in dtrace_hdl.c
25
26
  rb_define_method(cDtrace, "status", dtrace_hdl_status, 0); // in dtrace_hdl.c
26
27
  rb_define_method(cDtrace, "go", dtrace_hdl_go, 0); // in dtrace_hdl.c
27
- rb_define_method(cDtrace, "each_aggregate", dtrace_hdl_each_aggregate, 0); // in dtrace_hdl.c
28
- rb_define_method(cDtrace, "aggregate_print", dtrace_hdl_aggregate_print, 0); // in dtrace_hdl.c
29
- rb_define_method(cDtrace, "aggregate_snap", dtrace_hdl_aggregate_snap, 0); // in dtrace_hdl.c
30
- rb_define_method(cDtrace, "aggregate_clear", dtrace_hdl_aggregate_clear, 0); // in dtrace_hdl.c
31
28
  rb_define_method(cDtrace, "error", dtrace_hdl_error, 0); // in dtrace_hdl.c
32
29
  rb_define_method(cDtrace, "setopt", dtrace_hdl_setopt, 2); // in dtrace_hdl.c
33
30
  rb_define_method(cDtrace, "sleep", dtrace_hdl_sleep, 0); // in dtrace_hdl.c
34
- rb_define_method(cDtrace, "work", dtrace_hdl_work, 2); // in dtrace_hdl.c
31
+ rb_define_method(cDtrace, "work", dtrace_hdl_work, -1); // in dtrace_hdl.c
35
32
  rb_define_method(cDtrace, "buf_consumer", dtrace_hdl_buf_consumer, 1); // in dtrace_hdl.c
33
+ rb_define_method(cDtrace, "createprocess", dtrace_hdl_createprocess, 1); // in dtrace_hdl.c
34
+ rb_define_method(cDtrace, "grabprocess", dtrace_hdl_grabprocess, 1); // in dtrace_hdl.c
36
35
  rb_define_alloc_func(cDtrace, dtrace_hdl_alloc);
37
36
 
37
+ cDtraceProcess = rb_define_class("DtraceProcess", rb_cObject);
38
+ rb_define_method(cDtraceProcess, "initialize", dtrace_process_init, 0); // in dtrace_process.c
39
+ rb_define_method(cDtraceProcess, "continue", dtrace_process_continue, 0); // in dtrace_process.c
40
+
38
41
  cDtraceProbe = rb_define_class("DtraceProbe", rb_cObject);
39
42
  rb_define_method(cDtraceProbe, "initialize", dtraceprobe_init, 0); // in dtrace_probe.c
40
43
  rb_define_method(cDtraceProbe, "probe_id", dtraceprobe_probe_id, 0); // in dtrace_probe.c
@@ -45,11 +48,18 @@ void Init_dtrace_api() {
45
48
 
46
49
  cDtraceProbeData = rb_define_class("DtraceProbeData", rb_cObject);
47
50
  rb_define_method(cDtraceProbeData, "initialize", dtraceprobedata_init, 0); // in dtrace_probedata.c
48
- rb_define_method(cDtraceProbeData, "probedesc", dtraceprobedata_probedesc, 0); // in dtrace_probedata.c
51
+ rb_define_method(cDtraceProbeData, "epid", dtraceprobedata_epid, 0); // in dtrace_probedata.c
52
+ rb_define_method(cDtraceProbeData, "probe", dtraceprobedata_probe, 0); // in dtrace_probedata.c
53
+ rb_define_method(cDtraceProbeData, "cpu", dtraceprobedata_cpu, 0); // in dtrace_probedata.c
54
+ rb_define_method(cDtraceProbeData, "indent", dtraceprobedata_indent, 0); // in dtrace_probedata.c
55
+ rb_define_method(cDtraceProbeData, "prefix", dtraceprobedata_prefix, 0); // in dtrace_probedata.c
56
+ rb_define_method(cDtraceProbeData, "flow", dtraceprobedata_flow, 0); // in dtrace_probedata.c
49
57
  rb_define_method(cDtraceProbeData, "each_record", dtraceprobedata_each_record, 0); // in dtrace_probedata.c
50
58
 
51
59
  cDtraceBufData = rb_define_class("DtraceBufData", rb_cObject);
52
60
  rb_define_method(cDtraceBufData, "initialize", dtracebufdata_init, 0); // in dtrace_bufdata.c
61
+ rb_define_method(cDtraceBufData, "epid", dtracebufdata_epid, 0); // in dtrace_bufdata.c
62
+ rb_define_method(cDtraceBufData, "probe", dtracebufdata_probe, 0); // in dtrace_bufdata.c
53
63
  rb_define_method(cDtraceBufData, "record", dtracebufdata_record, 0); // in dtrace_bufdata.c
54
64
 
55
65
  cDtraceProgram = rb_define_class("DtraceProgram", rb_cObject);
@@ -70,7 +80,8 @@ void Init_dtrace_api() {
70
80
  rb_define_method(cDtraceAggData, "aggtype", dtraceaggdata_aggtype, 0); // in dtrace_aggdata.c
71
81
 
72
82
  cDtraceRecDesc = rb_define_class("DtraceRecDesc", rb_cObject);
73
- rb_define_method(cDtraceRecDesc, "initialize", dtracerecdesc_init, 0); // in dtrace_recdesc.c
83
+ rb_define_method(cDtraceRecDesc, "initialize", dtracerecdesc_init, 0); // in dtrace_recdesc.c
84
+ rb_define_method(cDtraceRecDesc, "action", dtracerecdesc_action, 0); // in dtrace_recdesc.c
74
85
 
75
86
  eDtraceException = rb_define_class("DtraceException", rb_eStandardError);
76
87
  }
data/ext/dtrace_api.h CHANGED
@@ -8,31 +8,62 @@
8
8
  #include "/usr/include/dtrace.h"
9
9
  #include "ruby.h"
10
10
 
11
+ /* Used to pass three Ruby VALUEs as the void *arg of dtrace_work() to
12
+ its callbacks: the dtrace handle, a Proc for the probe callback,
13
+ and a Proc for the recdesc callback. */
14
+ typedef struct dtrace_work_handlers {
15
+ VALUE handle;
16
+ VALUE probe;
17
+ VALUE rec;
18
+ } dtrace_work_handlers_t;
19
+
20
+ /* Used to keep a reference to a struct ps_prochandle and a reference
21
+ to the DTrace handle in a DtraceProcess object: we need to be able
22
+ to call dtrace_proc_release() when the DtraceProcess goes away, and
23
+ that requires the DTrace handle. */
24
+ typedef struct dtrace_process {
25
+ dtrace_hdl_t *handle;
26
+ struct ps_prochandle *proc;
27
+ } dtrace_process_t;
28
+
29
+ /* Handle missing RARRAY_LEN etc */
30
+ #ifdef RARRAY_LEN
31
+ static inline long rb_str_len(VALUE s) {return RSTRING_LEN(s);}
32
+ static inline char *rb_str_ptr(VALUE s) {return RSTRING_PTR(s);}
33
+ static inline long rb_ary_len(VALUE s) {return RARRAY_LEN(s);}
34
+ static inline VALUE *rb_ary_ptr(VALUE s) {return RARRAY_PTR(s);}
35
+ #else
36
+ static inline long rb_str_len(VALUE s) {return RSTRING(s)->len;}
37
+ static inline char *rb_str_ptr(VALUE s) {return RSTRING(s)->ptr;}
38
+ static inline long rb_ary_len(VALUE s) {return RARRAY(s)->len;}
39
+ static inline VALUE *rb_ary_ptr(VALUE s) {return RARRAY(s)->ptr;}
40
+ #endif // RARRAY_LEN
41
+
11
42
  VALUE handle_bytedata(caddr_t addr, uint32_t nbytes);
12
43
 
44
+ VALUE dtrace_process_init(VALUE self);
45
+ void dtrace_process_release(dtrace_process_t *process);
46
+ VALUE dtrace_process_continue(VALUE self);
47
+
13
48
  VALUE dtraceaggdata_init(VALUE self);
14
49
  VALUE dtraceaggdata_value(VALUE self);
15
50
  VALUE dtraceaggdata_aggtype(VALUE self);
16
51
 
17
52
  void dtrace_hdl_free (void *handle);
18
- VALUE dtrace_hdl_alloc(VALUE klass);
19
53
  VALUE dtrace_init(VALUE self);
54
+ VALUE dtrace_hdl_alloc(VALUE klass);
20
55
  VALUE dtrace_each_probe(VALUE self);
21
56
  VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self);
22
57
  VALUE dtrace_hdl_go(VALUE self);
23
58
  VALUE dtrace_hdl_status(VALUE self);
24
59
  VALUE dtrace_hdl_setopt(VALUE self, VALUE key, VALUE value);
25
60
  VALUE dtrace_hdl_stop(VALUE self);
26
- VALUE dtrace_hdl_each_aggregate(VALUE self);
27
- VALUE dtrace_hdl_aggregate_print(VALUE self);
28
- VALUE dtrace_hdl_aggregate_snap(VALUE self);
29
- VALUE dtrace_hdl_aggregate_clear(VALUE self);
30
61
  VALUE dtrace_hdl_error(VALUE self);
31
62
  VALUE dtrace_hdl_sleep(VALUE self);
32
- VALUE dtrace_hdl_work(VALUE self,
33
- VALUE probe_consumer_proc,
34
- VALUE rec_consumer_proc);
63
+ VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self);
35
64
  VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer_proc);
65
+ VALUE dtrace_hdl_createprocess(VALUE self, VALUE argv);
66
+ VALUE dtrace_hdl_grabprocess(VALUE self, VALUE pid);
36
67
 
37
68
  VALUE dtraceprobe_init(VALUE self);
38
69
  VALUE dtraceprobe_probe_id(VALUE self);
@@ -42,10 +73,17 @@ VALUE dtraceprobe_func(VALUE self);
42
73
  VALUE dtraceprobe_name(VALUE self);
43
74
 
44
75
  VALUE dtraceprobedata_init(VALUE self);
45
- VALUE dtraceprobedata_probedesc(VALUE self);
76
+ VALUE dtraceprobedata_epid(VALUE self);
77
+ VALUE dtraceprobedata_probe(VALUE self);
78
+ VALUE dtraceprobedata_cpu(VALUE self);
79
+ VALUE dtraceprobedata_indent(VALUE self);
80
+ VALUE dtraceprobedata_prefix(VALUE self);
81
+ VALUE dtraceprobedata_flow(VALUE self);
46
82
  VALUE dtraceprobedata_each_record(VALUE self);
47
83
 
48
84
  VALUE dtracebufdata_init(VALUE self);
85
+ VALUE dtracebufdata_epid(VALUE self);
86
+ VALUE dtracebufdata_probe(VALUE self);
49
87
  VALUE dtracebufdata_record(VALUE self);
50
88
 
51
89
  VALUE dtraceprogram_init(VALUE self);
@@ -59,3 +97,4 @@ VALUE dtraceprograminfo_matches_count(VALUE self);
59
97
  VALUE dtraceprograminfo_speculations_count(VALUE self);
60
98
 
61
99
  VALUE dtracerecdesc_init(VALUE self);
100
+ VALUE dtracerecdesc_action(VALUE self);
data/ext/dtrace_bufdata.c CHANGED
@@ -7,6 +7,7 @@
7
7
  RUBY_EXTERN VALUE eDtraceException;
8
8
  RUBY_EXTERN VALUE cDtraceAggData;
9
9
  RUBY_EXTERN VALUE cDtraceRecDesc;
10
+ RUBY_EXTERN VALUE cDtraceProbe;
10
11
 
11
12
  /* :nodoc: */
12
13
  VALUE dtracebufdata_init(VALUE self)
@@ -17,6 +18,46 @@ VALUE dtracebufdata_init(VALUE self)
17
18
  return self;
18
19
  }
19
20
 
21
+ /*
22
+ * Returns the enabled probe id which generated this data
23
+ */
24
+ VALUE dtracebufdata_epid(VALUE self)
25
+ {
26
+ dtrace_bufdata_t *bufdata;
27
+
28
+ Data_Get_Struct(self, dtrace_bufdata_t, bufdata);
29
+
30
+ if (bufdata->dtbda_probe) {
31
+ return INT2FIX(bufdata->dtbda_probe->dtpda_edesc->dtepd_epid);
32
+ }
33
+
34
+ return Qnil;
35
+ }
36
+
37
+
38
+ /*
39
+ * Returns the DtraceProbe for the probe which generated this data
40
+ */
41
+ VALUE dtracebufdata_probe(VALUE self)
42
+ {
43
+ dtrace_bufdata_t *bufdata;
44
+ VALUE dtraceprobe;
45
+
46
+ Data_Get_Struct(self, dtrace_bufdata_t, bufdata);
47
+
48
+ if (bufdata->dtbda_probe) {
49
+ dtraceprobe = Data_Wrap_Struct(cDtraceProbe, 0, NULL, (dtrace_probedesc_t *)bufdata->dtbda_probe->dtpda_pdesc);
50
+ return dtraceprobe;
51
+ }
52
+
53
+ return Qnil;
54
+ }
55
+
56
+ /*
57
+ * Returns the record in this DtraceBufdata. Records are returned as
58
+ * either DtraceRecords or DtraceStackRecords as appropriate for the
59
+ * type of action.
60
+ */
20
61
  VALUE dtracebufdata_record(VALUE self)
21
62
  {
22
63
  dtrace_bufdata_t *bufdata;
@@ -50,17 +91,22 @@ VALUE dtracebufdata_record(VALUE self)
50
91
  /* trace() action */
51
92
  break;
52
93
  case DTRACEACT_PRINTF:
53
- /*
54
- * Only the formatted string was not available to dtj_chewrec(),
55
- * so we attach that now.
56
- */
94
+ /* printf action, not available in probedata */
57
95
  v = rb_str_new2(s);
96
+ dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtracePrintfRecord"));
97
+ rb_iv_set(dtracerecord, "@from", rb_str_new2("bufdata"));
98
+ rb_iv_set(dtracerecord, "@value", v);
99
+ return (dtracerecord);
58
100
  break;
59
101
  case DTRACEACT_STACK:
60
102
  case DTRACEACT_USTACK:
61
103
  case DTRACEACT_JSTACK:
62
104
  /* stand-alone stack(), ustack(), or jstack() action */
63
105
  v = rb_str_new2(s);
106
+ dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtraceStackRecord"));
107
+ rb_iv_set(dtracerecord, "@from", rb_str_new2("bufdata"));
108
+ rb_funcall(dtracerecord, rb_intern("parse"), 1, v);
109
+ return (dtracerecord);
64
110
  break;
65
111
  case DTRACEACT_USYM:
66
112
  case DTRACEACT_UADDR:
@@ -83,6 +129,8 @@ VALUE dtracebufdata_record(VALUE self)
83
129
  if (!NIL_P(v)) {
84
130
  dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtraceRecord"));
85
131
  rb_iv_set(dtracerecord, "@value", v);
132
+ rb_iv_set(dtracerecord, "@action", INT2FIX(act));
133
+ rb_iv_set(dtracerecord, "@from", rb_str_new2("bufdata"));
86
134
  return (dtracerecord);
87
135
  }
88
136
  else {
data/ext/dtrace_hdl.c CHANGED
@@ -5,16 +5,19 @@
5
5
  #include "dtrace_api.h"
6
6
 
7
7
  RUBY_EXTERN VALUE eDtraceException;
8
+
9
+ RUBY_EXTERN VALUE cDtrace;
8
10
  RUBY_EXTERN VALUE cDtraceProbe;
9
11
  RUBY_EXTERN VALUE cDtraceProgram;
10
- RUBY_EXTERN VALUE cDtraceAggData;
11
12
  RUBY_EXTERN VALUE cDtraceRecDesc;
12
13
  RUBY_EXTERN VALUE cDtraceProbeData;
13
14
  RUBY_EXTERN VALUE cDtraceBufData;
15
+ RUBY_EXTERN VALUE cDtraceProcess;
14
16
 
15
17
  void dtrace_hdl_free (void *handle)
16
18
  {
17
- dtrace_close(handle);
19
+ if (handle)
20
+ dtrace_close(handle);
18
21
  }
19
22
 
20
23
  VALUE dtrace_hdl_alloc(VALUE klass)
@@ -26,6 +29,17 @@ VALUE dtrace_hdl_alloc(VALUE klass)
26
29
  handle = dtrace_open(DTRACE_VERSION, 0, &err);
27
30
 
28
31
  if (handle) {
32
+ /*
33
+ * Leopard's DTrace requires symbol resolution to be
34
+ * switched on explicitly
35
+ */
36
+ #ifdef __APPLE__
37
+ (void) dtrace_setopt(handle, "stacksymbols", "enabled");
38
+ #endif
39
+
40
+ /* always request flowindent information */
41
+ (void) dtrace_setopt(handle, "flowindent", 0);
42
+
29
43
  obj = Data_Wrap_Struct(klass, 0, dtrace_hdl_free, handle);
30
44
  return obj;
31
45
  }
@@ -96,7 +110,7 @@ VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
96
110
 
97
111
  rb_scan_args(argc, argv, "1*", &dtrace_text, &dtrace_argv_array);
98
112
 
99
- dtrace_argc = FIX2INT(rb_funcall(dtrace_argv_array, rb_intern("length"), 0));
113
+ dtrace_argc = rb_ary_len(dtrace_argv_array);
100
114
  dtrace_argv = ALLOC_N(char *, dtrace_argc + 1);
101
115
  for (i = 0; i < dtrace_argc; i++) {
102
116
  dtrace_argv[i + 1] = STR2CSTR(rb_ary_entry(dtrace_argv_array, i));
@@ -202,72 +216,6 @@ VALUE dtrace_hdl_stop(VALUE self)
202
216
  return Qnil;
203
217
  }
204
218
 
205
- int _agg_walk_yield(const dtrace_aggdata_t *data, void *arg)
206
- {
207
- VALUE aggdata;
208
-
209
- aggdata = Data_Wrap_Struct(cDtraceAggData, 0, NULL, (dtrace_aggdata_t *)data);
210
-
211
- rb_yield(aggdata);
212
- return (DTRACE_AGGWALK_NEXT);
213
- }
214
-
215
- /*
216
- * Yields each aggregate in turn.
217
- *
218
- * Aggregates are represented by a DtraceAggregate object.
219
- */
220
- VALUE dtrace_hdl_each_aggregate(VALUE self)
221
- {
222
- dtrace_hdl_t *handle;
223
-
224
- Data_Get_Struct(self, dtrace_hdl_t, handle);
225
- if (dtrace_aggregate_walk_keyvarsorted(handle, _agg_walk_yield, NULL) < 0)
226
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
227
-
228
- return Qnil;
229
- }
230
-
231
- /*
232
- * Uses libdtrace to print a summary of aggregates to STDERR.
233
- */
234
- VALUE dtrace_hdl_aggregate_print(VALUE self)
235
- {
236
- dtrace_hdl_t *handle;
237
-
238
- Data_Get_Struct(self, dtrace_hdl_t, handle);
239
- if (dtrace_aggregate_print(handle, stderr, NULL) < 0)
240
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
241
-
242
- return Qnil;
243
- }
244
-
245
- /*
246
- * Take a snapshot of the current aggregate values.
247
- */
248
- VALUE dtrace_hdl_aggregate_snap(VALUE self)
249
- {
250
- dtrace_hdl_t *handle;
251
-
252
- Data_Get_Struct(self, dtrace_hdl_t, handle);
253
- if (dtrace_aggregate_snap(handle) < 0)
254
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
255
-
256
- return Qnil;
257
- }
258
-
259
- /*
260
- * Clear the current aggregate snapshot.
261
- */
262
- VALUE dtrace_hdl_aggregate_clear(VALUE self)
263
- {
264
- dtrace_hdl_t *handle;
265
-
266
- Data_Get_Struct(self, dtrace_hdl_t, handle);
267
- dtrace_aggregate_clear(handle);
268
- return Qnil;
269
- }
270
-
271
219
  /*
272
220
  * Return the most recent DTrace error.
273
221
  */
@@ -294,11 +242,6 @@ VALUE dtrace_hdl_sleep(VALUE self)
294
242
  return Qnil;
295
243
  }
296
244
 
297
- typedef struct dtrace_work_handlers {
298
- VALUE probe;
299
- VALUE rec;
300
- } dtrace_work_handlers_t;
301
-
302
245
  static int _probe_consumer(const dtrace_probedata_t *data, void *arg)
303
246
  {
304
247
  VALUE proc;
@@ -308,9 +251,12 @@ static int _probe_consumer(const dtrace_probedata_t *data, void *arg)
308
251
  handlers = *(dtrace_work_handlers_t *) arg;
309
252
  proc = handlers.probe;
310
253
 
311
- probedata = Data_Wrap_Struct(cDtraceProbeData, 0, NULL, (dtrace_probedata_t *)data);
312
- rb_funcall(proc, rb_intern("call"), 1, probedata);
313
-
254
+ if (!NIL_P(proc)) {
255
+ probedata = Data_Wrap_Struct(cDtraceProbeData, 0, NULL, (dtrace_probedata_t *)data);
256
+ rb_iv_set(probedata, "@handle", handlers.handle);
257
+ rb_funcall(proc, rb_intern("call"), 1, probedata);
258
+ }
259
+
314
260
  return (DTRACE_CONSUME_THIS);
315
261
  }
316
262
 
@@ -319,12 +265,29 @@ static int _rec_consumer(const dtrace_probedata_t *data, const dtrace_recdesc_t
319
265
  VALUE proc;
320
266
  dtrace_work_handlers_t handlers;
321
267
  VALUE recdesc;
268
+ VALUE probedata;
269
+
270
+ dtrace_actkind_t act;
322
271
 
323
272
  handlers = *(dtrace_work_handlers_t *) arg;
324
273
  proc = handlers.rec;
274
+ if (!NIL_P(proc)) {
275
+ if (rec) {
276
+ recdesc = Data_Wrap_Struct(cDtraceRecDesc, 0, NULL, (dtrace_recdesc_t *)rec);
277
+ rb_iv_set(recdesc, "@handle", handlers.handle);
278
+ rb_funcall(proc, rb_intern("call"), 1, recdesc);
279
+ }
280
+ else {
281
+ rb_funcall(proc, rb_intern("call"), 1, Qnil);
282
+ return (DTRACE_CONSUME_NEXT);
283
+ }
284
+ }
325
285
 
326
- recdesc = Data_Wrap_Struct(cDtraceRecDesc, 0, NULL, (dtrace_recdesc_t *)rec);
327
- rb_funcall(proc, rb_intern("call"), 1, recdesc);
286
+ if (rec) {
287
+ act = rec->dtrd_action;
288
+ if (act == DTRACEACT_EXIT)
289
+ return (DTRACE_CONSUME_NEXT);
290
+ }
328
291
 
329
292
  return (DTRACE_CONSUME_THIS);
330
293
  }
@@ -336,30 +299,44 @@ static int _buf_consumer(const dtrace_bufdata_t *bufdata, void *arg)
336
299
 
337
300
  proc = (VALUE)arg;
338
301
 
339
- dtracebufdata = Data_Wrap_Struct(cDtraceBufData, 0, NULL, (dtrace_bufdata_t *)bufdata);
340
- rb_funcall(proc, rb_intern("call"), 1, dtracebufdata);
302
+ if (!NIL_P(proc)) {
303
+ dtracebufdata = Data_Wrap_Struct(cDtraceBufData, 0, NULL, (dtrace_bufdata_t *)bufdata);
304
+ rb_funcall(proc, rb_intern("call"), 1, dtracebufdata);
305
+ }
341
306
 
342
307
  return (DTRACE_HANDLE_OK);
343
308
  }
344
309
 
345
310
  /*
346
311
  * Process any data waiting from the D program.
312
+ *
313
+ * Takes a Proc to which DtraceProbeData objects will be yielded, and
314
+ * an optional second Proc to which DtraceRecDesc objects will be
315
+ * yielded.
316
+ *
347
317
  */
348
- VALUE dtrace_hdl_work(VALUE self,
349
- VALUE probe_consumer_proc,
350
- VALUE rec_consumer_proc)
318
+ VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self)
351
319
  {
352
320
  dtrace_hdl_t *handle;
353
321
  dtrace_workstatus_t status;
354
322
  dtrace_work_handlers_t handlers;
323
+ VALUE probe_consumer_proc;
324
+ VALUE rec_consumer_proc;
355
325
 
356
326
  Data_Get_Struct(self, dtrace_hdl_t, handle);
357
327
 
328
+ /* handle args - probe_consumer_proc is mandatory, rec_consumer_proc
329
+ is optional */
330
+ rb_scan_args(argc, argv, "11", &probe_consumer_proc, &rec_consumer_proc);
331
+
358
332
  /* fill out the handlers struct */
359
- handlers.probe = probe_consumer_proc;
360
- handlers.rec = rec_consumer_proc;
333
+ handlers.probe = probe_consumer_proc;
334
+ handlers.rec = rec_consumer_proc;
335
+ handlers.handle = self;
361
336
 
362
337
  status = dtrace_work(handle, NULL, _probe_consumer, _rec_consumer, &handlers);
338
+ if (status < 0)
339
+ rb_raise(eDtraceException, (dtrace_errmsg(handle, dtrace_errno(handle))));
363
340
 
364
341
  return INT2FIX(status);
365
342
  }
@@ -379,3 +356,77 @@ VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer)
379
356
 
380
357
  return Qnil;
381
358
  }
359
+
360
+ /*
361
+ * Start a process which will be traced. The pid of the started
362
+ * process will be available in D as $target.
363
+ *
364
+ * Pass an array, where the first element is the full path to the
365
+ * program to start, and subsequent elements are its arguments.
366
+ *
367
+ * Returns a DtraceProcess object which is used to start the process
368
+ * once tracing is set up.
369
+ */
370
+ VALUE dtrace_hdl_createprocess(VALUE self, VALUE rb_argv)
371
+ {
372
+ dtrace_hdl_t *handle;
373
+ struct ps_prochandle *P;
374
+ char **argv;
375
+ long len;
376
+ int i;
377
+ VALUE dtraceprocess;
378
+ dtrace_process_t *process;
379
+
380
+ Data_Get_Struct(self, dtrace_hdl_t, handle);
381
+
382
+ len = rb_ary_len(rb_argv);
383
+ argv = ALLOC_N(char *, len + 1);
384
+
385
+ for (i = 0; i < len; i++) {
386
+ argv[i] = STR2CSTR(rb_ary_entry(rb_argv, i));
387
+ }
388
+ argv[len] = NULL;
389
+
390
+ P = dtrace_proc_create(handle, argv[0], argv);
391
+ free(argv);
392
+
393
+ if (P == NULL) {
394
+ rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
395
+ }
396
+
397
+ process = ALLOC(dtrace_process_t);
398
+ process->handle = handle;
399
+ process->proc = P;
400
+
401
+ dtraceprocess = Data_Wrap_Struct(cDtraceProcess, 0, dtrace_process_release, (dtrace_process_t *)process);
402
+ return dtraceprocess;
403
+ }
404
+
405
+ /*
406
+ * Grab a currently-running process by pid.
407
+ *
408
+ * Returns a DtraceProcess object which is used to start the process
409
+ * once tracing is set up.
410
+ */
411
+ VALUE dtrace_hdl_grabprocess(VALUE self, VALUE pid)
412
+ {
413
+ dtrace_hdl_t *handle;
414
+ struct ps_prochandle *P;
415
+ dtrace_process_t *process;
416
+ VALUE dtraceprocess;
417
+
418
+ Data_Get_Struct(self, dtrace_hdl_t, handle);
419
+
420
+ P = dtrace_proc_grab(handle, FIX2INT(pid), 0);
421
+
422
+ if (P == NULL) {
423
+ rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
424
+ }
425
+
426
+ process = ALLOC(dtrace_process_t);
427
+ process->handle = handle;
428
+ process->proc = P;
429
+
430
+ dtraceprocess = Data_Wrap_Struct(cDtraceProcess, 0, dtrace_process_release, (dtrace_process_t *)process);
431
+ return dtraceprocess;
432
+ }