ruby-dtrace 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);