rbtrace 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|