ruby-dtrace 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,11 @@
1
+ == 0.0.4 / 2008-01-24
2
+
3
+ * Add DtraceErrData and DtraceDropData for access to error
4
+ and drop information
5
+ * Fix interaction with Ruby's GC
6
+
1
7
  == 0.0.4 / 2008-01-14
8
+
2
9
  * Fix the very basic Rails plugin.
3
10
 
4
11
  == 0.0.3 / 2008-01-06
data/Manifest.txt CHANGED
@@ -7,6 +7,8 @@ ext/dtrace_aggdata.c
7
7
  ext/dtrace_api.c
8
8
  ext/dtrace_api.h
9
9
  ext/dtrace_bufdata.c
10
+ ext/dtrace_dropdata.c
11
+ ext/dtrace_errdata.c
10
12
  ext/dtrace_hdl.c
11
13
  ext/dtrace_probe.c
12
14
  ext/dtrace_probedata.c
@@ -42,7 +44,9 @@ plugin/dtrace/test/dtrace_test.rb
42
44
  plugin/dtrace/views/dtrace/_report.rhtml
43
45
  test/test_dtrace.rb
44
46
  test/test_dtrace_aggregates.rb
47
+ test/test_dtrace_drops_errors.rb
45
48
  test/test_dtrace_processes.rb
46
49
  test/test_dtrace_profile.rb
47
50
  test/test_dtrace_repeat.rb
48
51
  test/test_dtrace_rubyprobe.rb
52
+ test/test_dtrace_typefilter.rb
data/ext/dtrace_api.c CHANGED
@@ -13,6 +13,8 @@ VALUE cDtraceRecDesc;
13
13
  VALUE cDtraceProbeData;
14
14
  VALUE cDtraceBufData;
15
15
  VALUE cDtraceProcess;
16
+ VALUE cDtraceDropData;
17
+ VALUE cDtraceErrData;
16
18
 
17
19
  VALUE eDtraceException;
18
20
 
@@ -30,6 +32,8 @@ void Init_dtrace_api() {
30
32
  rb_define_method(cDtrace, "sleep", dtrace_hdl_sleep, 0); // in dtrace_hdl.c
31
33
  rb_define_method(cDtrace, "work", dtrace_hdl_work, -1); // in dtrace_hdl.c
32
34
  rb_define_method(cDtrace, "buf_consumer", dtrace_hdl_buf_consumer, 1); // in dtrace_hdl.c
35
+ rb_define_method(cDtrace, "drop_consumer", dtrace_hdl_drop_consumer, 1); // in dtrace_hdl.c
36
+ rb_define_method(cDtrace, "err_consumer", dtrace_hdl_err_consumer, 1); // in dtrace_hdl.c
33
37
  rb_define_method(cDtrace, "createprocess", dtrace_hdl_createprocess, 1); // in dtrace_hdl.c
34
38
  rb_define_method(cDtrace, "grabprocess", dtrace_hdl_grabprocess, 1); // in dtrace_hdl.c
35
39
  rb_define_alloc_func(cDtrace, dtrace_hdl_alloc);
@@ -83,6 +87,23 @@ void Init_dtrace_api() {
83
87
  rb_define_method(cDtraceRecDesc, "initialize", dtracerecdesc_init, 0); // in dtrace_recdesc.c
84
88
  rb_define_method(cDtraceRecDesc, "action", dtracerecdesc_action, 0); // in dtrace_recdesc.c
85
89
 
90
+ cDtraceDropData = rb_define_class("DtraceDropData", rb_cObject);
91
+ rb_define_method(cDtraceDropData, "initialize", dtracedropdata_init, 0); // in dtrace_dropdata.c
92
+ rb_define_method(cDtraceDropData, "cpu", dtracedropdata_cpu, 0); // in dtrace_dropdata.c
93
+ rb_define_method(cDtraceDropData, "drops", dtracedropdata_drops, 0); // in dtrace_dropdata.c
94
+ rb_define_method(cDtraceDropData, "total", dtracedropdata_total, 0); // in dtrace_dropdata.c
95
+ rb_define_method(cDtraceDropData, "msg", dtracedropdata_msg, 0); // in dtrace_dropdata.c
96
+ rb_define_method(cDtraceDropData, "kind", dtracedropdata_kind, 0); // in dtrace_dropdata.c
97
+
98
+ cDtraceErrData = rb_define_class("DtraceErrData", rb_cObject);
99
+ rb_define_method(cDtraceErrData, "initialize", dtraceerrdata_init, 0); // in dtrace_errdata.c
100
+ rb_define_method(cDtraceErrData, "cpu", dtraceerrdata_cpu, 0); // in dtrace_errdata.c
101
+ rb_define_method(cDtraceErrData, "action", dtraceerrdata_action, 0); // in dtrace_errdata.c
102
+ rb_define_method(cDtraceErrData, "offset", dtraceerrdata_offset, 0); // in dtrace_errdata.c
103
+ rb_define_method(cDtraceErrData, "fault", dtraceerrdata_fault, 0); // in dtrace_errdata.c
104
+ rb_define_method(cDtraceErrData, "addr", dtraceerrdata_addr, 0); // in dtrace_errdata.c
105
+ rb_define_method(cDtraceErrData, "msg", dtraceerrdata_msg, 0); // in dtrace_errdata.c
106
+
86
107
  eDtraceException = rb_define_class("DtraceException", rb_eStandardError);
87
108
  }
88
109
 
data/ext/dtrace_api.h CHANGED
@@ -26,6 +26,18 @@ typedef struct dtrace_process {
26
26
  struct ps_prochandle *proc;
27
27
  } dtrace_process_t;
28
28
 
29
+ /* Used to wrap up the DTrace handle, so we can keep references to the
30
+ various callbacks: we must mark them from the dtrace_hdl_mark
31
+ routine, which only gets a pointer to this structure. */
32
+ typedef struct dtrace_handle {
33
+ dtrace_hdl_t *hdl;
34
+ VALUE probe;
35
+ VALUE rec;
36
+ VALUE buf;
37
+ VALUE err;
38
+ VALUE drop;
39
+ } dtrace_handle_t;
40
+
29
41
  /* Handle missing RARRAY_LEN etc */
30
42
  #ifdef RARRAY_LEN
31
43
  static inline long rb_str_len(VALUE s) {return RSTRING_LEN(s);}
@@ -49,7 +61,6 @@ VALUE dtraceaggdata_init(VALUE self);
49
61
  VALUE dtraceaggdata_value(VALUE self);
50
62
  VALUE dtraceaggdata_aggtype(VALUE self);
51
63
 
52
- void dtrace_hdl_free (void *handle);
53
64
  VALUE dtrace_init(VALUE self);
54
65
  VALUE dtrace_hdl_alloc(VALUE klass);
55
66
  VALUE dtrace_each_probe(VALUE self);
@@ -62,6 +73,8 @@ VALUE dtrace_hdl_error(VALUE self);
62
73
  VALUE dtrace_hdl_sleep(VALUE self);
63
74
  VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self);
64
75
  VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer_proc);
76
+ VALUE dtrace_hdl_drop_consumer(VALUE self, VALUE drop_consumer_proc);
77
+ VALUE dtrace_hdl_err_consumer(VALUE self, VALUE err_consumer_proc);
65
78
  VALUE dtrace_hdl_createprocess(VALUE self, VALUE argv);
66
79
  VALUE dtrace_hdl_grabprocess(VALUE self, VALUE pid);
67
80
 
@@ -98,3 +111,18 @@ VALUE dtraceprograminfo_speculations_count(VALUE self);
98
111
 
99
112
  VALUE dtracerecdesc_init(VALUE self);
100
113
  VALUE dtracerecdesc_action(VALUE self);
114
+
115
+ VALUE dtracedropdata_init(VALUE self);
116
+ VALUE dtracedropdata_cpu(VALUE self);
117
+ VALUE dtracedropdata_drops(VALUE self);
118
+ VALUE dtracedropdata_total(VALUE self);
119
+ VALUE dtracedropdata_msg(VALUE self);
120
+ VALUE dtracedropdata_kind(VALUE self);
121
+
122
+ VALUE dtraceerrdata_init(VALUE self);
123
+ VALUE dtraceerrdata_cpu(VALUE self);
124
+ VALUE dtraceerrdata_action(VALUE self);
125
+ VALUE dtraceerrdata_offset(VALUE self);
126
+ VALUE dtraceerrdata_fault(VALUE self);
127
+ VALUE dtraceerrdata_addr(VALUE self);
128
+ VALUE dtraceerrdata_msg(VALUE self);
@@ -0,0 +1,131 @@
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 dtracedropdata_init(VALUE self)
11
+ {
12
+ dtrace_dropdata_t *data;
13
+
14
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
15
+ return self;
16
+ }
17
+
18
+ /* Returns the CPU which generated this drop record */
19
+ VALUE dtracedropdata_cpu(VALUE self)
20
+ {
21
+ dtrace_dropdata_t *data;
22
+ processorid_t cpu;
23
+
24
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
25
+
26
+ if (data) {
27
+ cpu = data->dtdda_cpu;
28
+ return INT2FIX(cpu);
29
+ }
30
+ else {
31
+ return Qnil;
32
+ }
33
+ }
34
+
35
+ /* Returns the number of records dropped in this drop record */
36
+ VALUE dtracedropdata_drops(VALUE self)
37
+ {
38
+ dtrace_dropdata_t *data;
39
+
40
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
41
+
42
+ if (data) {
43
+ return INT2FIX(data->dtdda_drops);
44
+ }
45
+ else {
46
+ return Qnil;
47
+ }
48
+ }
49
+
50
+ /* Returns the number of records dropped in total */
51
+ VALUE dtracedropdata_total(VALUE self)
52
+ {
53
+ dtrace_dropdata_t *data;
54
+
55
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
56
+
57
+ if (data) {
58
+ return INT2FIX(data->dtdda_total);
59
+ }
60
+ else {
61
+ return Qnil;
62
+ }
63
+ }
64
+
65
+ /* Returns a message from the DTrace library describing this drop
66
+ record. */
67
+ VALUE dtracedropdata_msg(VALUE self)
68
+ {
69
+ dtrace_dropdata_t *data;
70
+
71
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
72
+
73
+ if (data) {
74
+ return rb_str_new2(data->dtdda_msg);
75
+ }
76
+ else {
77
+ return Qnil;
78
+ }
79
+ }
80
+
81
+ /* Returns the reason for the drop (the "drop kind") */
82
+ VALUE dtracedropdata_kind(VALUE self)
83
+ {
84
+ dtrace_dropdata_t *data;
85
+ VALUE kind;
86
+
87
+ Data_Get_Struct(self, dtrace_dropdata_t, data);
88
+
89
+ if (data) {
90
+ switch (data->dtdda_kind) {
91
+ case DTRACEDROP_PRINCIPAL:
92
+ kind = rb_str_new2("drop to principal buffer");
93
+ break;
94
+ case DTRACEDROP_AGGREGATION:
95
+ kind = rb_str_new2("drop to aggregation buffer");
96
+ break;
97
+ case DTRACEDROP_DYNAMIC:
98
+ kind = rb_str_new2("dynamic drop");
99
+ break;
100
+ case DTRACEDROP_DYNRINSE:
101
+ kind = rb_str_new2("dyn drop due to rinsing");
102
+ break;
103
+ case DTRACEDROP_DYNDIRTY:
104
+ kind = rb_str_new2("dyn drop due to dirty");
105
+ break;
106
+ case DTRACEDROP_SPEC:
107
+ kind = rb_str_new2("speculative drop");
108
+ break;
109
+ case DTRACEDROP_SPECBUSY:
110
+ kind = rb_str_new2("spec drop due to busy");
111
+ break;
112
+ case DTRACEDROP_SPECUNAVAIL:
113
+ kind = rb_str_new2("spec drop due to unavail");
114
+ break;
115
+ case DTRACEDROP_STKSTROVERFLOW:
116
+ kind = rb_str_new2("stack string tab overflow");
117
+ break;
118
+ case DTRACEDROP_DBLERROR:
119
+ kind = rb_str_new2("error in ERROR probe");
120
+ break;
121
+ default:
122
+ kind = rb_str_new2("unknown");
123
+ break;
124
+ }
125
+ return kind;
126
+ }
127
+ else {
128
+ return Qnil;
129
+ }
130
+ }
131
+
@@ -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
+
data/ext/dtrace_hdl.c CHANGED
@@ -13,34 +13,67 @@ RUBY_EXTERN VALUE cDtraceRecDesc;
13
13
  RUBY_EXTERN VALUE cDtraceProbeData;
14
14
  RUBY_EXTERN VALUE cDtraceBufData;
15
15
  RUBY_EXTERN VALUE cDtraceProcess;
16
+ RUBY_EXTERN VALUE cDtraceDropData;
17
+ RUBY_EXTERN VALUE cDtraceErrData;
16
18
 
17
- void dtrace_hdl_free (void *handle)
19
+ static void dtrace_hdl_free(void *arg)
18
20
  {
19
- if (handle)
20
- dtrace_close(handle);
21
+ dtrace_handle_t *handle = (dtrace_handle_t *)arg;
22
+
23
+ if (handle) {
24
+ dtrace_close(handle->hdl);
25
+ free(handle);
26
+ }
27
+ }
28
+
29
+ static void dtrace_hdl_mark(void *arg)
30
+ {
31
+ dtrace_handle_t *handle = (dtrace_handle_t *)arg;
32
+
33
+ if (handle) {
34
+ rb_gc_mark(handle->probe);
35
+ rb_gc_mark(handle->rec);
36
+ rb_gc_mark(handle->buf);
37
+ rb_gc_mark(handle->err);
38
+ rb_gc_mark(handle->drop);
39
+ }
21
40
  }
22
41
 
23
42
  VALUE dtrace_hdl_alloc(VALUE klass)
24
43
  {
25
- dtrace_hdl_t *handle;
44
+ dtrace_hdl_t *hdl;
45
+ dtrace_handle_t *handle;
26
46
  int err;
27
47
  VALUE obj;
28
48
 
29
- handle = dtrace_open(DTRACE_VERSION, 0, &err);
49
+ hdl = dtrace_open(DTRACE_VERSION, 0, &err);
30
50
 
31
- if (handle) {
51
+ if (hdl) {
32
52
  /*
33
53
  * Leopard's DTrace requires symbol resolution to be
34
54
  * switched on explicitly
35
55
  */
36
56
  #ifdef __APPLE__
37
- (void) dtrace_setopt(handle, "stacksymbols", "enabled");
57
+ (void) dtrace_setopt(hdl, "stacksymbols", "enabled");
38
58
  #endif
39
59
 
40
60
  /* always request flowindent information */
41
- (void) dtrace_setopt(handle, "flowindent", 0);
61
+ (void) dtrace_setopt(hdl, "flowindent", 0);
62
+
63
+ handle = ALLOC(dtrace_handle_t);
64
+ if (!handle) {
65
+ rb_raise(eDtraceException, "alloc failed");
66
+ return Qnil;
67
+ }
42
68
 
43
- obj = Data_Wrap_Struct(klass, 0, dtrace_hdl_free, handle);
69
+ handle->hdl = hdl;
70
+ handle->probe = Qnil;
71
+ handle->rec = Qnil;
72
+ handle->buf = Qnil;
73
+ handle->err = Qnil;
74
+ handle->drop = Qnil;
75
+
76
+ obj = Data_Wrap_Struct(klass, dtrace_hdl_mark, dtrace_hdl_free, handle);
44
77
  return obj;
45
78
  }
46
79
  else {
@@ -51,16 +84,16 @@ VALUE dtrace_hdl_alloc(VALUE klass)
51
84
  /* :nodoc: */
52
85
  VALUE dtrace_init(VALUE self)
53
86
  {
54
- dtrace_hdl_t *handle;
87
+ dtrace_handle_t *handle;
55
88
 
56
- Data_Get_Struct(self, dtrace_hdl_t, handle);
89
+ Data_Get_Struct(self, dtrace_handle_t, handle);
57
90
  if (handle)
58
91
  return self;
59
92
  else
60
93
  return Qnil;
61
94
  }
62
95
 
63
- int _dtrace_next_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
96
+ int _dtrace_next_probe(dtrace_hdl_t *hdl, const dtrace_probedesc_t *pdp, void *arg)
64
97
  {
65
98
  VALUE probe;
66
99
 
@@ -78,10 +111,10 @@ int _dtrace_next_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *a
78
111
  */
79
112
  VALUE dtrace_each_probe(VALUE self)
80
113
  {
81
- dtrace_hdl_t *handle;
114
+ dtrace_handle_t *handle;
82
115
 
83
- Data_Get_Struct(self, dtrace_hdl_t, handle);
84
- (void) dtrace_probe_iter(handle, NULL, _dtrace_next_probe, NULL);
116
+ Data_Get_Struct(self, dtrace_handle_t, handle);
117
+ (void) dtrace_probe_iter(handle->hdl, NULL, _dtrace_next_probe, NULL);
85
118
 
86
119
  return self;
87
120
  }
@@ -97,7 +130,7 @@ VALUE dtrace_each_probe(VALUE self)
97
130
  */
98
131
  VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
99
132
  {
100
- dtrace_hdl_t *handle;
133
+ dtrace_handle_t *handle;
101
134
  dtrace_prog_t *program;
102
135
  VALUE dtrace_program;
103
136
 
@@ -112,6 +145,11 @@ VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
112
145
 
113
146
  dtrace_argc = rb_ary_len(dtrace_argv_array);
114
147
  dtrace_argv = ALLOC_N(char *, dtrace_argc + 1);
148
+ if (!dtrace_argv) {
149
+ rb_raise(eDtraceException, "alloc failed");
150
+ return Qnil;
151
+ }
152
+
115
153
  for (i = 0; i < dtrace_argc; i++) {
116
154
  dtrace_argv[i + 1] = STR2CSTR(rb_ary_entry(dtrace_argv_array, i));
117
155
  }
@@ -119,18 +157,18 @@ VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
119
157
  dtrace_argv[0] = "ruby";
120
158
  dtrace_argc++;
121
159
 
122
- Data_Get_Struct(self, dtrace_hdl_t, handle);
123
- program = dtrace_program_strcompile(handle, STR2CSTR(dtrace_text),
160
+ Data_Get_Struct(self, dtrace_handle_t, handle);
161
+ program = dtrace_program_strcompile(handle->hdl, STR2CSTR(dtrace_text),
124
162
  DTRACE_PROBESPEC_NAME, DTRACE_C_PSPEC,
125
163
  dtrace_argc, dtrace_argv);
126
164
 
127
165
  if (!program) {
128
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
166
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
129
167
  return Qnil;
130
168
  }
131
169
  else {
132
170
  dtrace_program = Data_Wrap_Struct(cDtraceProgram, 0, NULL, program);
133
- rb_iv_set(dtrace_program, "@dtrace", self);
171
+ rb_iv_set(dtrace_program, "@handle", self);
134
172
  return dtrace_program;
135
173
  }
136
174
  }
@@ -143,11 +181,11 @@ VALUE dtrace_strcompile(int argc, VALUE *argv, VALUE self)
143
181
  */
144
182
  VALUE dtrace_hdl_go(VALUE self)
145
183
  {
146
- dtrace_hdl_t *handle;
184
+ dtrace_handle_t *handle;
147
185
 
148
- Data_Get_Struct(self, dtrace_hdl_t, handle);
149
- if (dtrace_go(handle) < 0)
150
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
186
+ Data_Get_Struct(self, dtrace_handle_t, handle);
187
+ if (dtrace_go(handle->hdl) < 0)
188
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
151
189
 
152
190
  return Qnil;
153
191
  }
@@ -163,12 +201,12 @@ VALUE dtrace_hdl_go(VALUE self)
163
201
  */
164
202
  VALUE dtrace_hdl_status(VALUE self)
165
203
  {
166
- dtrace_hdl_t *handle;
204
+ dtrace_handle_t *handle;
167
205
  int status;
168
206
 
169
- Data_Get_Struct(self, dtrace_hdl_t, handle);
170
- if ((status = dtrace_status(handle)) < 0)
171
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
207
+ Data_Get_Struct(self, dtrace_handle_t, handle);
208
+ if ((status = dtrace_status(handle->hdl)) < 0)
209
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
172
210
 
173
211
  return INT2FIX(status);
174
212
  }
@@ -183,20 +221,20 @@ VALUE dtrace_hdl_status(VALUE self)
183
221
  */
184
222
  VALUE dtrace_hdl_setopt(VALUE self, VALUE key, VALUE value)
185
223
  {
186
- dtrace_hdl_t *handle;
224
+ dtrace_handle_t *handle;
187
225
  int ret;
188
226
 
189
- Data_Get_Struct(self, dtrace_hdl_t, handle);
190
-
227
+ Data_Get_Struct(self, dtrace_handle_t, handle);
228
+
191
229
  if (NIL_P(value)) {
192
- ret = dtrace_setopt(handle, STR2CSTR(key), 0);
230
+ ret = dtrace_setopt(handle->hdl, STR2CSTR(key), 0);
193
231
  }
194
232
  else {
195
- ret = dtrace_setopt(handle, STR2CSTR(key), STR2CSTR(value));
233
+ ret = dtrace_setopt(handle->hdl, STR2CSTR(key), STR2CSTR(value));
196
234
  }
197
235
 
198
236
  if (ret < 0)
199
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
237
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
200
238
 
201
239
  return Qnil;
202
240
  }
@@ -207,11 +245,11 @@ VALUE dtrace_hdl_setopt(VALUE self, VALUE key, VALUE value)
207
245
  */
208
246
  VALUE dtrace_hdl_stop(VALUE self)
209
247
  {
210
- dtrace_hdl_t *handle;
248
+ dtrace_handle_t *handle;
211
249
 
212
- Data_Get_Struct(self, dtrace_hdl_t, handle);
213
- if (dtrace_stop(handle) < 0)
214
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
250
+ Data_Get_Struct(self, dtrace_handle_t, handle);
251
+ if (dtrace_stop(handle->hdl) < 0)
252
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
215
253
 
216
254
  return Qnil;
217
255
  }
@@ -221,11 +259,11 @@ VALUE dtrace_hdl_stop(VALUE self)
221
259
  */
222
260
  VALUE dtrace_hdl_error(VALUE self)
223
261
  {
224
- dtrace_hdl_t *handle;
262
+ dtrace_handle_t *handle;
225
263
  const char *error_string;
226
264
 
227
- Data_Get_Struct(self, dtrace_hdl_t, handle);
228
- error_string = dtrace_errmsg(handle, dtrace_errno(handle));
265
+ Data_Get_Struct(self, dtrace_handle_t, handle);
266
+ error_string = dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl));
229
267
  return rb_str_new2(error_string);
230
268
  }
231
269
 
@@ -235,10 +273,10 @@ VALUE dtrace_hdl_error(VALUE self)
235
273
  */
236
274
  VALUE dtrace_hdl_sleep(VALUE self)
237
275
  {
238
- dtrace_hdl_t *handle;
276
+ dtrace_handle_t *handle;
239
277
 
240
- Data_Get_Struct(self, dtrace_hdl_t, handle);
241
- dtrace_sleep(handle);
278
+ Data_Get_Struct(self, dtrace_handle_t, handle);
279
+ dtrace_sleep(handle->hdl);
242
280
  return Qnil;
243
281
  }
244
282
 
@@ -317,26 +355,31 @@ static int _buf_consumer(const dtrace_bufdata_t *bufdata, void *arg)
317
355
  */
318
356
  VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self)
319
357
  {
320
- dtrace_hdl_t *handle;
358
+ dtrace_handle_t *handle;
321
359
  dtrace_workstatus_t status;
322
360
  dtrace_work_handlers_t handlers;
323
- VALUE probe_consumer_proc;
324
- VALUE rec_consumer_proc;
361
+ VALUE probe_consumer;
362
+ VALUE rec_consumer;
325
363
 
326
- Data_Get_Struct(self, dtrace_hdl_t, handle);
364
+ Data_Get_Struct(self, dtrace_handle_t, handle);
327
365
 
328
366
  /* handle args - probe_consumer_proc is mandatory, rec_consumer_proc
329
367
  is optional */
330
- rb_scan_args(argc, argv, "11", &probe_consumer_proc, &rec_consumer_proc);
368
+ rb_scan_args(argc, argv, "11", &probe_consumer, &rec_consumer);
369
+
370
+ /* to mark during GC */
371
+ handle->probe = probe_consumer;
372
+ if (!NIL_P(rec_consumer))
373
+ handle->rec = rec_consumer;
331
374
 
332
375
  /* fill out the handlers struct */
333
- handlers.probe = probe_consumer_proc;
334
- handlers.rec = rec_consumer_proc;
376
+ handlers.probe = probe_consumer;
377
+ handlers.rec = rec_consumer;
335
378
  handlers.handle = self;
336
379
 
337
- status = dtrace_work(handle, NULL, _probe_consumer, _rec_consumer, &handlers);
380
+ status = dtrace_work(handle->hdl, NULL, _probe_consumer, _rec_consumer, &handlers);
338
381
  if (status < 0)
339
- rb_raise(eDtraceException, (dtrace_errmsg(handle, dtrace_errno(handle))));
382
+ rb_raise(eDtraceException, (dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl))));
340
383
 
341
384
  return INT2FIX(status);
342
385
  }
@@ -346,12 +389,100 @@ VALUE dtrace_hdl_work(int argc, VALUE *argv, VALUE self)
346
389
  */
347
390
  VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer)
348
391
  {
349
- dtrace_hdl_t *handle;
350
- Data_Get_Struct(self, dtrace_hdl_t, handle);
392
+ dtrace_handle_t *handle;
393
+ Data_Get_Struct(self, dtrace_handle_t, handle);
394
+
395
+ /* to mark during GC */
396
+ handle->buf = buf_consumer;
351
397
 
352
398
  /* attach the buffered output handler */
353
- if (dtrace_handle_buffered(handle, &_buf_consumer, (void *)buf_consumer) == -1) {
354
- rb_raise(eDtraceException, "failed to establish buffered handler");
399
+ if (dtrace_handle_buffered(handle->hdl, &_buf_consumer, (void *)buf_consumer) == -1) {
400
+ rb_raise(eDtraceException, "failed to establish buffered handler: %s",
401
+ (dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl))));
402
+ }
403
+
404
+ return Qnil;
405
+ }
406
+
407
+ static int _drop_consumer(const dtrace_dropdata_t *dropdata, void *arg)
408
+ {
409
+ VALUE proc;
410
+ VALUE dtracedropdata;
411
+
412
+ proc = (VALUE)arg;
413
+
414
+ if (!NIL_P(proc)) {
415
+ dtracedropdata = Data_Wrap_Struct(cDtraceDropData, 0, NULL, (dtrace_dropdata_t *)dropdata);
416
+ rb_funcall(proc, rb_intern("call"), 1, dtracedropdata);
417
+ }
418
+
419
+ return (DTRACE_HANDLE_OK);
420
+ }
421
+
422
+ /*
423
+ * Set up the drop-record handler for this handle. Takes a block,
424
+ * which will be called with any drop records returned by DTrace,
425
+ * represented by DtraceDropData objects.
426
+ */
427
+ VALUE dtrace_hdl_drop_consumer(VALUE self, VALUE drop_consumer)
428
+ {
429
+ dtrace_handle_t *handle;
430
+ Data_Get_Struct(self, dtrace_handle_t, handle);
431
+
432
+ /* to mark during GC */
433
+ handle->drop = drop_consumer;
434
+
435
+ /* attach the drop-record handler */
436
+ if (dtrace_handle_drop(handle->hdl, &_drop_consumer, (void *)drop_consumer) == -1) {
437
+ rb_raise(eDtraceException, "failed to establish drop-record handler");
438
+ }
439
+
440
+ return Qnil;
441
+ }
442
+
443
+ static int _err_consumer(const dtrace_errdata_t *errdata, void *arg)
444
+ {
445
+ VALUE proc;
446
+ VALUE dtraceerrdata;
447
+
448
+ proc = (VALUE)arg;
449
+
450
+ /* guard against bad invocations where arg is not what we provided... */
451
+ if (TYPE(proc) == T_DATA) {
452
+ dtraceerrdata = Data_Wrap_Struct(cDtraceErrData, 0, NULL, (dtrace_errdata_t *)errdata);
453
+ rb_funcall(proc, rb_intern("call"), 1, dtraceerrdata);
454
+ }
455
+ else {
456
+ /* arg looked bad, throw an exception */
457
+ rb_raise(eDtraceException, "bad argument to _err_consumer: %p -> 0x%x type 0x%x\n", arg, proc, TYPE(proc));
458
+ }
459
+
460
+ return (DTRACE_HANDLE_OK);
461
+ }
462
+
463
+ /*
464
+ * Set up the err-record handler for this handle. Takes a block, which
465
+ * will be called with any error records returned by DTrace,
466
+ * represented by DTraceErrData records.
467
+ */
468
+ VALUE dtrace_hdl_err_consumer(VALUE self, VALUE err_consumer)
469
+ {
470
+ dtrace_handle_t *handle;
471
+ void *arg;
472
+ Data_Get_Struct(self, dtrace_handle_t, handle);
473
+
474
+ if (dtrace_status(handle->hdl) != 0) {
475
+ rb_raise(eDtraceException, "too late to add error handler");
476
+ return Qnil;
477
+ }
478
+
479
+ /* to mark during GC */
480
+ handle->err = err_consumer;
481
+
482
+ /* attach the err-record handler */
483
+ if (dtrace_handle_err(handle->hdl, &_err_consumer, (void *)err_consumer) == -1) {
484
+ rb_raise(eDtraceException, "failed to establish err-record handler: %s",
485
+ dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
355
486
  }
356
487
 
357
488
  return Qnil;
@@ -369,7 +500,7 @@ VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer)
369
500
  */
370
501
  VALUE dtrace_hdl_createprocess(VALUE self, VALUE rb_argv)
371
502
  {
372
- dtrace_hdl_t *handle;
503
+ dtrace_handle_t *handle;
373
504
  struct ps_prochandle *P;
374
505
  char **argv;
375
506
  long len;
@@ -377,25 +508,34 @@ VALUE dtrace_hdl_createprocess(VALUE self, VALUE rb_argv)
377
508
  VALUE dtraceprocess;
378
509
  dtrace_process_t *process;
379
510
 
380
- Data_Get_Struct(self, dtrace_hdl_t, handle);
511
+ Data_Get_Struct(self, dtrace_handle_t, handle);
381
512
 
382
513
  len = rb_ary_len(rb_argv);
383
514
  argv = ALLOC_N(char *, len + 1);
515
+ if (!argv) {
516
+ rb_raise(eDtraceException, "alloc failed");
517
+ return Qnil;
518
+ }
384
519
 
385
520
  for (i = 0; i < len; i++) {
386
521
  argv[i] = STR2CSTR(rb_ary_entry(rb_argv, i));
387
522
  }
388
523
  argv[len] = NULL;
389
524
 
390
- P = dtrace_proc_create(handle, argv[0], argv);
525
+ P = dtrace_proc_create(handle->hdl, argv[0], argv);
391
526
  free(argv);
392
527
 
393
528
  if (P == NULL) {
394
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
529
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
395
530
  }
396
531
 
397
532
  process = ALLOC(dtrace_process_t);
398
- process->handle = handle;
533
+ if (!process) {
534
+ rb_raise(eDtraceException, "alloc failed");
535
+ return Qnil;
536
+ }
537
+
538
+ process->handle = handle->hdl;
399
539
  process->proc = P;
400
540
 
401
541
  dtraceprocess = Data_Wrap_Struct(cDtraceProcess, 0, dtrace_process_release, (dtrace_process_t *)process);
@@ -410,21 +550,26 @@ VALUE dtrace_hdl_createprocess(VALUE self, VALUE rb_argv)
410
550
  */
411
551
  VALUE dtrace_hdl_grabprocess(VALUE self, VALUE pid)
412
552
  {
413
- dtrace_hdl_t *handle;
553
+ dtrace_handle_t *handle;
414
554
  struct ps_prochandle *P;
415
555
  dtrace_process_t *process;
416
556
  VALUE dtraceprocess;
417
557
 
418
- Data_Get_Struct(self, dtrace_hdl_t, handle);
558
+ Data_Get_Struct(self, dtrace_handle_t, handle);
419
559
 
420
- P = dtrace_proc_grab(handle, FIX2INT(pid), 0);
560
+ P = dtrace_proc_grab(handle->hdl, FIX2INT(pid), 0);
421
561
 
422
562
  if (P == NULL) {
423
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
563
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
424
564
  }
425
565
 
426
566
  process = ALLOC(dtrace_process_t);
427
- process->handle = handle;
567
+ if (!process) {
568
+ rb_raise(eDtraceException, "alloc failed");
569
+ return Qnil;
570
+ }
571
+
572
+ process->handle = handle->hdl;
428
573
  process->proc = P;
429
574
 
430
575
  dtraceprocess = Data_Wrap_Struct(cDtraceProcess, 0, dtrace_process_release, (dtrace_process_t *)process);