rbtrace 0.1.0 → 0.2.0
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/Gemfile +1 -0
- data/README.md +110 -61
- data/bin/rbtrace +350 -135
- data/ext/.gitignore +4 -0
- data/ext/extconf.rb +3 -0
- data/ext/rbtrace.c +191 -151
- data/rbtrace.gemspec +3 -1
- data/server.rb +1 -0
- data/test.sh +32 -0
- metadata +21 -6
- data/ext/test.rb +0 -57
data/ext/.gitignore
ADDED
data/ext/extconf.rb
CHANGED
data/ext/rbtrace.c
CHANGED
@@ -17,8 +17,11 @@
|
|
17
17
|
#include <ruby.h>
|
18
18
|
|
19
19
|
#ifndef RUBY_VM
|
20
|
-
#include <
|
20
|
+
#include <env.h>
|
21
21
|
#include <intern.h>
|
22
|
+
#include <node.h>
|
23
|
+
#define rb_sourcefile() (ruby_current_node ? ruby_current_node->nd_file : 0)
|
24
|
+
#define rb_sourceline() (ruby_current_node ? nd_line(ruby_current_node) : 0)
|
22
25
|
#endif
|
23
26
|
|
24
27
|
#ifndef RSTRING_PTR
|
@@ -36,7 +39,13 @@ timeofday_usec()
|
|
36
39
|
return (uint64_t)tv.tv_sec*1e6 + (uint64_t)tv.tv_usec;
|
37
40
|
}
|
38
41
|
|
39
|
-
#define
|
42
|
+
#define MAX_CALLS 32768 // up to this many stack frames examined in slow watch mode
|
43
|
+
#define MAX_TRACERS 100 // max method tracers
|
44
|
+
#define MAX_EXPRS 10 // max expressions per tracer
|
45
|
+
#ifndef BUF_SIZE // msgq buffer size
|
46
|
+
#define BUF_SIZE 120
|
47
|
+
#endif
|
48
|
+
|
40
49
|
struct rbtracer_t {
|
41
50
|
int id;
|
42
51
|
|
@@ -50,28 +59,54 @@ struct rbtracer_t {
|
|
50
59
|
};
|
51
60
|
typedef struct rbtracer_t rbtracer_t;
|
52
61
|
|
53
|
-
#define MAX_TRACERS 100
|
54
|
-
static rbtracer_t tracers[MAX_TRACERS];
|
55
|
-
static unsigned int num_tracers = 0;
|
56
|
-
|
57
|
-
key_t mqi_key, mqo_key;
|
58
|
-
int mqi_id = -1, mqo_id = -1;
|
59
|
-
|
60
|
-
#ifndef BUF_SIZE
|
61
|
-
#define BUF_SIZE 120
|
62
|
-
#endif
|
63
62
|
|
64
63
|
struct event_msg {
|
65
64
|
long mtype;
|
66
65
|
char buf[BUF_SIZE];
|
67
66
|
};
|
68
67
|
|
68
|
+
|
69
|
+
static struct {
|
70
|
+
bool installed;
|
71
|
+
|
72
|
+
bool firehose;
|
73
|
+
|
74
|
+
bool slow;
|
75
|
+
uint64_t call_times[MAX_CALLS];
|
76
|
+
int num_calls;
|
77
|
+
uint32_t threshold;
|
78
|
+
|
79
|
+
unsigned int num;
|
80
|
+
rbtracer_t list[MAX_TRACERS];
|
81
|
+
|
82
|
+
key_t mqo_key;
|
83
|
+
key_t mqi_key;
|
84
|
+
int mqo_id;
|
85
|
+
int mqi_id;
|
86
|
+
}
|
87
|
+
rbtracer = {
|
88
|
+
.installed = false,
|
89
|
+
|
90
|
+
.firehose = false,
|
91
|
+
|
92
|
+
.slow = false,
|
93
|
+
.num_calls = 0,
|
94
|
+
.threshold = 250,
|
95
|
+
|
96
|
+
.num = 0,
|
97
|
+
|
98
|
+
.mqo_key = 0,
|
99
|
+
.mqi_key = 0,
|
100
|
+
.mqo_id = -1,
|
101
|
+
.mqi_id = -1
|
102
|
+
};
|
103
|
+
|
69
104
|
#define SEND_EVENT(format, ...) do {\
|
70
105
|
uint64_t usec = timeofday_usec();\
|
71
106
|
if (false) {\
|
72
107
|
fprintf(stderr, "%" PRIu64 "," format, usec, __VA_ARGS__);\
|
73
108
|
fprintf(stderr, "\n");\
|
74
|
-
} else {\
|
109
|
+
} else if (rbtracer.mqo_id != -1) {\
|
75
110
|
struct event_msg msg;\
|
76
111
|
int ret = -1, n = 0;\
|
77
112
|
\
|
@@ -79,31 +114,16 @@ struct event_msg {
|
|
79
114
|
snprintf(msg.buf, sizeof(msg.buf), "%" PRIu64 "," format, usec, __VA_ARGS__);\
|
80
115
|
\
|
81
116
|
for (n=0; n<10 && ret==-1; n++)\
|
82
|
-
ret = msgsnd(mqo_id, &msg, sizeof(msg)-sizeof(long), IPC_NOWAIT);\
|
117
|
+
ret = msgsnd(rbtracer.mqo_id, &msg, sizeof(msg)-sizeof(long), IPC_NOWAIT);\
|
83
118
|
if (ret == -1) {\
|
84
119
|
fprintf(stderr, "msgsnd(): %s\n", strerror(errno));\
|
85
120
|
struct msqid_ds stat;\
|
86
|
-
msgctl(mqo_id, IPC_STAT, &stat);\
|
121
|
+
msgctl(rbtracer.mqo_id, IPC_STAT, &stat);\
|
87
122
|
fprintf(stderr, "cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);\
|
88
123
|
}\
|
89
124
|
}\
|
90
125
|
} while (0)
|
91
126
|
|
92
|
-
static int in_event_hook = 0;
|
93
|
-
static bool event_hook_installed = false;
|
94
|
-
|
95
|
-
#define MAX_CALLS 32768
|
96
|
-
static struct {
|
97
|
-
bool enabled;
|
98
|
-
uint64_t call_times[ MAX_CALLS ];
|
99
|
-
int num_calls;
|
100
|
-
uint32_t threshold;
|
101
|
-
} slow_tracer = {
|
102
|
-
.enabled = false,
|
103
|
-
.num_calls = 0,
|
104
|
-
.threshold = 250
|
105
|
-
};
|
106
|
-
|
107
127
|
static void
|
108
128
|
#ifdef RUBY_VM
|
109
129
|
event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE klass)
|
@@ -111,6 +131,8 @@ event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE klass)
|
|
111
131
|
event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
112
132
|
#endif
|
113
133
|
{
|
134
|
+
static int in_event_hook = 0;
|
135
|
+
|
114
136
|
// do not re-enter this function
|
115
137
|
// after this, must `goto out` instead of `return`
|
116
138
|
if (in_event_hook) return;
|
@@ -129,35 +151,35 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
129
151
|
}
|
130
152
|
|
131
153
|
// are we watching for any slow methods?
|
132
|
-
if (
|
154
|
+
if (rbtracer.slow) {
|
133
155
|
uint64_t usec = timeofday_usec(), diff = 0;
|
134
156
|
|
135
157
|
switch (event) {
|
136
158
|
case RUBY_EVENT_C_CALL:
|
137
159
|
case RUBY_EVENT_CALL:
|
138
|
-
if (
|
139
|
-
|
160
|
+
if (rbtracer.num_calls < MAX_CALLS)
|
161
|
+
rbtracer.call_times[ rbtracer.num_calls ] = usec;
|
140
162
|
|
141
|
-
|
163
|
+
rbtracer.num_calls++;
|
142
164
|
break;
|
143
165
|
|
144
166
|
case RUBY_EVENT_C_RETURN:
|
145
167
|
case RUBY_EVENT_RETURN:
|
146
|
-
if (
|
147
|
-
|
168
|
+
if (rbtracer.num_calls > 0) {
|
169
|
+
rbtracer.num_calls--;
|
148
170
|
|
149
|
-
if (
|
150
|
-
diff = usec -
|
171
|
+
if (rbtracer.num_calls < MAX_CALLS)
|
172
|
+
diff = usec - rbtracer.call_times[ rbtracer.num_calls ];
|
151
173
|
}
|
152
174
|
break;
|
153
175
|
}
|
154
176
|
|
155
|
-
if (diff >
|
177
|
+
if (diff > rbtracer.threshold * 1e3) {
|
156
178
|
SEND_EVENT(
|
157
179
|
"%s,-1,%" PRIu64 ",%d,%s,%d,%s",
|
158
180
|
event == RUBY_EVENT_RETURN ? "slow" : "cslow",
|
159
181
|
diff,
|
160
|
-
|
182
|
+
rbtracer.num_calls,
|
161
183
|
rb_id2name(mid),
|
162
184
|
singleton,
|
163
185
|
klass ? rb_class2name(singleton ? self : klass) : ""
|
@@ -167,28 +189,30 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
167
189
|
goto out;
|
168
190
|
}
|
169
191
|
|
170
|
-
// are there specific methods we're waiting for?
|
171
|
-
if (num_tracers == 0) goto out;
|
172
|
-
|
173
192
|
int i, n;
|
174
193
|
rbtracer_t *tracer = NULL;
|
175
194
|
|
176
|
-
|
177
|
-
|
178
|
-
|
195
|
+
if (!rbtracer.firehose) {
|
196
|
+
// are there specific methods we're waiting for?
|
197
|
+
if (rbtracer.num == 0) goto out;
|
198
|
+
|
199
|
+
for (i=0, n=0; i<MAX_TRACERS && n<rbtracer.num; i++) {
|
200
|
+
if (rbtracer.list[i].query) {
|
201
|
+
n++;
|
179
202
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
203
|
+
if (!rbtracer.list[i].mid || rbtracer.list[i].mid == mid) {
|
204
|
+
if (!rbtracer.list[i].klass || rbtracer.list[i].klass == klass) {
|
205
|
+
if (!rbtracer.list[i].self || rbtracer.list[i].self == self) {
|
206
|
+
tracer = &rbtracer.list[i];
|
207
|
+
}
|
184
208
|
}
|
185
209
|
}
|
186
210
|
}
|
187
211
|
}
|
188
|
-
}
|
189
212
|
|
190
|
-
|
191
|
-
|
213
|
+
// no matching method tracer found, so bail!
|
214
|
+
if (!tracer) goto out;
|
215
|
+
}
|
192
216
|
|
193
217
|
switch (event) {
|
194
218
|
case RUBY_EVENT_C_CALL:
|
@@ -196,31 +220,43 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
196
220
|
SEND_EVENT(
|
197
221
|
"%s,%d,%s,%d,%s",
|
198
222
|
event == RUBY_EVENT_CALL ? "call" : "ccall",
|
199
|
-
tracer->id,
|
223
|
+
tracer ? tracer->id : 255, // hax
|
200
224
|
rb_id2name(mid),
|
201
225
|
singleton,
|
202
226
|
klass ? rb_class2name(singleton ? self : klass) : ""
|
203
227
|
);
|
204
228
|
|
205
|
-
if (tracer->num_exprs) {
|
229
|
+
if (tracer && tracer->num_exprs) {
|
206
230
|
for (i=0; i<tracer->num_exprs; i++) {
|
207
231
|
char *expr = tracer->exprs[i];
|
208
232
|
size_t len = strlen(expr);
|
209
|
-
|
233
|
+
|
234
|
+
VALUE val = Qnil;
|
235
|
+
char buffer[len+50];
|
236
|
+
char *result = NULL;
|
210
237
|
|
211
238
|
if (len == 4 && strcmp("self", expr) == 0) {
|
212
239
|
val = rb_inspect(self);
|
213
240
|
|
241
|
+
} else if (len == 10 && strcmp("__source__", expr) == 0) {
|
242
|
+
snprintf(buffer, len+50, "\"%s:%d\"", rb_sourcefile(), rb_sourceline());
|
243
|
+
result = buffer;
|
244
|
+
|
245
|
+
} else if (len > 1 && expr[0] == '@') {
|
246
|
+
val = rb_inspect(rb_ivar_get(self, rb_intern(expr)));
|
247
|
+
|
214
248
|
} else if (event == RUBY_EVENT_CALL) {
|
215
|
-
|
216
|
-
snprintf(code, len+50, "(begin; %s; rescue Exception => e; e; end).inspect", expr);
|
249
|
+
snprintf(buffer, len+50, "(begin; %s; rescue Exception => e; e; end).inspect", expr);
|
217
250
|
|
218
|
-
str = rb_str_new2(
|
251
|
+
VALUE str = rb_str_new2(buffer);
|
219
252
|
val = rb_obj_instance_eval(1, &str, self);
|
220
253
|
}
|
221
254
|
|
222
255
|
if (RTEST(val) && TYPE(val) == T_STRING) {
|
223
|
-
|
256
|
+
result = RSTRING_PTR(val);
|
257
|
+
}
|
258
|
+
|
259
|
+
if (result) {
|
224
260
|
SEND_EVENT(
|
225
261
|
"%s,%d,%d,%s",
|
226
262
|
"exprval",
|
@@ -238,7 +274,7 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
238
274
|
SEND_EVENT(
|
239
275
|
"%s,%d",
|
240
276
|
event == RUBY_EVENT_RETURN ? "return" : "creturn",
|
241
|
-
tracer->id
|
277
|
+
tracer ? tracer->id : 255 // hax
|
242
278
|
);
|
243
279
|
break;
|
244
280
|
}
|
@@ -250,7 +286,7 @@ out:
|
|
250
286
|
static void
|
251
287
|
event_hook_install()
|
252
288
|
{
|
253
|
-
if (!
|
289
|
+
if (!rbtracer.installed) {
|
254
290
|
rb_add_event_hook(
|
255
291
|
event_hook,
|
256
292
|
RUBY_EVENT_CALL | RUBY_EVENT_C_CALL |
|
@@ -259,16 +295,16 @@ event_hook_install()
|
|
259
295
|
, 0
|
260
296
|
#endif
|
261
297
|
);
|
262
|
-
|
298
|
+
rbtracer.installed = true;
|
263
299
|
}
|
264
300
|
}
|
265
301
|
|
266
302
|
static void
|
267
303
|
event_hook_remove()
|
268
304
|
{
|
269
|
-
if (
|
305
|
+
if (rbtracer.installed) {
|
270
306
|
rb_remove_event_hook(event_hook);
|
271
|
-
|
307
|
+
rbtracer.installed = false;
|
272
308
|
}
|
273
309
|
}
|
274
310
|
|
@@ -281,16 +317,16 @@ rbtracer_remove(char *query, int id)
|
|
281
317
|
|
282
318
|
if (query) {
|
283
319
|
for (i=0; i<MAX_TRACERS; i++) {
|
284
|
-
if (
|
285
|
-
if (0 == strcmp(query,
|
286
|
-
tracer = &
|
320
|
+
if (rbtracer.list[i].query) {
|
321
|
+
if (0 == strcmp(query, rbtracer.list[i].query)) {
|
322
|
+
tracer = &rbtracer.list[i];
|
287
323
|
break;
|
288
324
|
}
|
289
325
|
}
|
290
326
|
}
|
291
327
|
} else {
|
292
328
|
if (id >= MAX_TRACERS) goto out;
|
293
|
-
tracer = &
|
329
|
+
tracer = &rbtracer.list[id];
|
294
330
|
}
|
295
331
|
|
296
332
|
if (tracer->query) {
|
@@ -308,8 +344,8 @@ rbtracer_remove(char *query, int id)
|
|
308
344
|
tracer->num_exprs = 0;
|
309
345
|
}
|
310
346
|
|
311
|
-
|
312
|
-
if (
|
347
|
+
rbtracer.num--;
|
348
|
+
if (rbtracer.num == 0)
|
313
349
|
event_hook_remove();
|
314
350
|
}
|
315
351
|
|
@@ -325,9 +361,12 @@ out:
|
|
325
361
|
static void
|
326
362
|
rbtracer_remove_all()
|
327
363
|
{
|
364
|
+
rbtracer.firehose = false;
|
365
|
+
rbtracer.slow = false;
|
366
|
+
|
328
367
|
int i;
|
329
368
|
for (i=0; i<MAX_TRACERS; i++) {
|
330
|
-
if (
|
369
|
+
if (rbtracer.list[i].query) {
|
331
370
|
rbtracer_remove(NULL, i);
|
332
371
|
}
|
333
372
|
}
|
@@ -340,11 +379,11 @@ rbtracer_add(char *query)
|
|
340
379
|
int tracer_id = -1;
|
341
380
|
rbtracer_t *tracer = NULL;
|
342
381
|
|
343
|
-
if (
|
382
|
+
if (rbtracer.num >= MAX_TRACERS) goto out;
|
344
383
|
|
345
384
|
for (i=0; i<MAX_TRACERS; i++) {
|
346
|
-
if (!
|
347
|
-
tracer = &
|
385
|
+
if (!rbtracer.list[i].query) {
|
386
|
+
tracer = &rbtracer.list[i];
|
348
387
|
tracer_id = i;
|
349
388
|
break;
|
350
389
|
}
|
@@ -389,10 +428,10 @@ rbtracer_add(char *query)
|
|
389
428
|
tracer->query = strdup(query);
|
390
429
|
tracer->num_exprs = 0;
|
391
430
|
|
392
|
-
if (
|
431
|
+
if (rbtracer.num == 0)
|
393
432
|
event_hook_install();
|
394
433
|
|
395
|
-
|
434
|
+
rbtracer.num++;
|
396
435
|
|
397
436
|
out:
|
398
437
|
SEND_EVENT(
|
@@ -411,7 +450,7 @@ rbtracer_add_expr(int id, char *expr)
|
|
411
450
|
rbtracer_t *tracer = NULL;
|
412
451
|
|
413
452
|
if (id >= MAX_TRACERS) goto out;
|
414
|
-
tracer = &
|
453
|
+
tracer = &rbtracer.list[id];
|
415
454
|
|
416
455
|
if (tracer->query) {
|
417
456
|
tracer_id = tracer->id;
|
@@ -434,10 +473,11 @@ out:
|
|
434
473
|
static void
|
435
474
|
rbtracer_watch(uint32_t threshold)
|
436
475
|
{
|
437
|
-
if (!
|
438
|
-
|
439
|
-
|
440
|
-
|
476
|
+
if (!rbtracer.slow) {
|
477
|
+
rbtracer.num_calls = 0;
|
478
|
+
rbtracer.threshold = threshold;
|
479
|
+
rbtracer.firehose = false;
|
480
|
+
rbtracer.slow = true;
|
441
481
|
|
442
482
|
event_hook_install();
|
443
483
|
}
|
@@ -446,61 +486,83 @@ rbtracer_watch(uint32_t threshold)
|
|
446
486
|
static void
|
447
487
|
rbtracer_unwatch()
|
448
488
|
{
|
449
|
-
if (
|
489
|
+
if (rbtracer.slow) {
|
450
490
|
event_hook_remove();
|
451
491
|
|
452
|
-
|
492
|
+
rbtracer.firehose = false;
|
493
|
+
rbtracer.slow = false;
|
453
494
|
}
|
454
495
|
}
|
455
496
|
|
456
|
-
static
|
457
|
-
|
497
|
+
static void
|
498
|
+
msgq_teardown()
|
458
499
|
{
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
500
|
+
if (rbtracer.mqo_id != -1) {
|
501
|
+
msgctl(rbtracer.mqo_id, IPC_RMID, NULL);
|
502
|
+
rbtracer.mqo_id = -1;
|
503
|
+
rbtracer.mqo_key = 0;
|
504
|
+
}
|
505
|
+
if (rbtracer.mqi_id != -1) {
|
506
|
+
msgctl(rbtracer.mqi_id, IPC_RMID, NULL);
|
507
|
+
rbtracer.mqi_id = -1;
|
508
|
+
rbtracer.mqi_key = 0;
|
509
|
+
}
|
466
510
|
}
|
467
511
|
|
468
|
-
static
|
469
|
-
|
512
|
+
static void
|
513
|
+
ruby_teardown(VALUE data)
|
470
514
|
{
|
471
|
-
|
472
|
-
|
473
|
-
char *str = RSTRING_PTR(query);
|
474
|
-
int tracer_id = -1;
|
475
|
-
|
476
|
-
tracer_id = rbtracer_remove(str, -1);
|
477
|
-
return tracer_id == -1 ? Qfalse : Qtrue;
|
515
|
+
msgq_teardown();
|
478
516
|
}
|
479
517
|
|
480
518
|
static void
|
481
|
-
|
519
|
+
msgq_setup()
|
482
520
|
{
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
521
|
+
pid_t pid = getpid();
|
522
|
+
|
523
|
+
if (rbtracer.mqo_key != (key_t)pid ||
|
524
|
+
rbtracer.mqi_key != (key_t)-pid) {
|
525
|
+
msgq_teardown();
|
526
|
+
} else {
|
527
|
+
return;
|
490
528
|
}
|
491
|
-
}
|
492
529
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
530
|
+
rbtracer.mqo_key = (key_t) pid;
|
531
|
+
rbtracer.mqo_id = msgget(rbtracer.mqo_key, 0666 | IPC_CREAT);
|
532
|
+
|
533
|
+
if (rbtracer.mqo_id == -1)
|
534
|
+
fprintf(stderr, "msgget() failed to create msgq\n");
|
535
|
+
|
536
|
+
|
537
|
+
rbtracer.mqi_key = (key_t) -pid;
|
538
|
+
rbtracer.mqi_id = msgget(rbtracer.mqi_key, 0666 | IPC_CREAT);
|
539
|
+
|
540
|
+
if (rbtracer.mqi_id == -1)
|
541
|
+
fprintf(stderr, "msgget() failed to create msgq\n");
|
542
|
+
|
543
|
+
/*
|
544
|
+
struct msqid_ds stat;
|
545
|
+
int ret;
|
546
|
+
|
547
|
+
msgctl(rbtracer.mqo_id, IPC_STAT, &stat);
|
548
|
+
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
549
|
+
|
550
|
+
stat.msg_qbytes += 10;
|
551
|
+
ret = msgctl(rbtracer.mqo_id, IPC_SET, &stat);
|
552
|
+
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
553
|
+
printf("ret: %d, errno: %d\n", ret, errno);
|
554
|
+
|
555
|
+
msgctl(rbtracer.mqo_id, IPC_STAT, &stat);
|
556
|
+
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
557
|
+
*/
|
497
558
|
}
|
498
559
|
|
499
560
|
static void
|
500
561
|
sigurg(int signal)
|
501
562
|
{
|
502
563
|
static int last_tracer_id = -1; // hax
|
503
|
-
|
564
|
+
msgq_setup();
|
565
|
+
if (rbtracer.mqi_id == -1) return;
|
504
566
|
|
505
567
|
struct event_msg msg;
|
506
568
|
char *query = NULL;
|
@@ -511,7 +573,7 @@ sigurg(int signal)
|
|
511
573
|
int ret = -1;
|
512
574
|
|
513
575
|
for (n=0; n<10 && ret==-1; n++)
|
514
|
-
ret = msgrcv(mqi_id, &msg, sizeof(msg)-sizeof(long), 0, IPC_NOWAIT);
|
576
|
+
ret = msgrcv(rbtracer.mqi_id, &msg, sizeof(msg)-sizeof(long), 0, IPC_NOWAIT);
|
515
577
|
|
516
578
|
if (ret == -1) {
|
517
579
|
break;
|
@@ -528,8 +590,9 @@ sigurg(int signal)
|
|
528
590
|
query = msg.buf + 4;
|
529
591
|
rbtracer_remove(query, -1);
|
530
592
|
|
531
|
-
} else if (0 == strncmp("
|
532
|
-
|
593
|
+
} else if (0 == strncmp("firehose", msg.buf, 8)) {
|
594
|
+
rbtracer.firehose = true;
|
595
|
+
event_hook_install();
|
533
596
|
|
534
597
|
} else if (0 == strncmp("addexpr,", msg.buf, 8)) {
|
535
598
|
query = msg.buf + 8;
|
@@ -547,6 +610,9 @@ sigurg(int signal)
|
|
547
610
|
} else if (0 == strncmp("unwatch", msg.buf, 7)) {
|
548
611
|
rbtracer_unwatch();
|
549
612
|
|
613
|
+
} else if (0 == strncmp("detach", msg.buf, 6)) {
|
614
|
+
rbtracer_remove_all();
|
615
|
+
|
550
616
|
}
|
551
617
|
}
|
552
618
|
}
|
@@ -555,39 +621,13 @@ sigurg(int signal)
|
|
555
621
|
void
|
556
622
|
Init_rbtrace()
|
557
623
|
{
|
558
|
-
|
559
|
-
|
624
|
+
// zero out tracer
|
625
|
+
memset(&rbtracer.list, 0, sizeof(rbtracer.list));
|
560
626
|
|
627
|
+
// catch signal telling us to read from the msgq
|
561
628
|
signal(SIGURG, sigurg);
|
562
629
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
mqo_id = msgget(mqo_key, 0666 | IPC_CREAT);
|
567
|
-
if (mqo_id == -1)
|
568
|
-
rb_sys_fail("msgget");
|
569
|
-
|
570
|
-
mqi_key = (key_t) -getpid();
|
571
|
-
mqi_id = msgget(mqi_key, 0666 | IPC_CREAT);
|
572
|
-
if (mqi_id == -1)
|
573
|
-
rb_sys_fail("msgget");
|
574
|
-
|
575
|
-
/*
|
576
|
-
struct msqid_ds stat;
|
577
|
-
int ret;
|
578
|
-
|
579
|
-
msgctl(mqo_id, IPC_STAT, &stat);
|
580
|
-
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
581
|
-
|
582
|
-
stat.msg_qbytes += 10;
|
583
|
-
ret = msgctl(mqo_id, IPC_SET, &stat);
|
584
|
-
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
585
|
-
printf("ret: %d, errno: %d\n", ret, errno);
|
586
|
-
|
587
|
-
msgctl(mqo_id, IPC_STAT, &stat);
|
588
|
-
printf("cbytes: %lu, qbytes: %lu, qnum: %lu\n", stat.msg_cbytes, stat.msg_qbytes, stat.msg_qnum);
|
589
|
-
*/
|
590
|
-
|
591
|
-
rb_define_method(rb_cObject, "rbtrace", rbtrace, 1);
|
592
|
-
rb_define_method(rb_cObject, "untrace", untrace, 1);
|
630
|
+
// cleanup the msgq on exit
|
631
|
+
atexit(msgq_teardown);
|
632
|
+
rb_set_end_proc(ruby_teardown, 0);
|
593
633
|
}
|