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.
@@ -0,0 +1,4 @@
1
+ Makefile
2
+ *.bundle
3
+ *.o
4
+ *.so
@@ -5,4 +5,7 @@ if RUBY_PLATFORM =~ /linux/
5
5
  $defs.push("-DBUF_SIZE=256")
6
6
  end
7
7
 
8
+ # warnings save lives
9
+ $CFLAGS << " -Wall "
10
+
8
11
  create_makefile('rbtrace')
@@ -17,8 +17,11 @@
17
17
  #include <ruby.h>
18
18
 
19
19
  #ifndef RUBY_VM
20
- #include <node.h>
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 MAX_EXPRS 10
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 (slow_tracer.enabled) {
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 (slow_tracer.num_calls < MAX_CALLS)
139
- slow_tracer.call_times[ slow_tracer.num_calls ] = usec;
160
+ if (rbtracer.num_calls < MAX_CALLS)
161
+ rbtracer.call_times[ rbtracer.num_calls ] = usec;
140
162
 
141
- slow_tracer.num_calls++;
163
+ rbtracer.num_calls++;
142
164
  break;
143
165
 
144
166
  case RUBY_EVENT_C_RETURN:
145
167
  case RUBY_EVENT_RETURN:
146
- if (slow_tracer.num_calls > 0) {
147
- slow_tracer.num_calls--;
168
+ if (rbtracer.num_calls > 0) {
169
+ rbtracer.num_calls--;
148
170
 
149
- if (slow_tracer.num_calls < MAX_CALLS)
150
- diff = usec - slow_tracer.call_times[ slow_tracer.num_calls ];
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 > slow_tracer.threshold * 1e3) {
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
- slow_tracer.num_calls,
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
- for (i=0, n=0; i<MAX_TRACERS && n<num_tracers; i++) {
177
- if (tracers[i].query) {
178
- n++;
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
- if (!tracers[i].mid || tracers[i].mid == mid) {
181
- if (!tracers[i].klass || tracers[i].klass == klass) {
182
- if (!tracers[i].self || tracers[i].self == self) {
183
- tracer = &tracers[i];
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
- // no matching method tracer found, so bail!
191
- if (!tracer) goto out;
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
- VALUE str = Qnil, val = Qnil;
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
- char code[len+50];
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(code);
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
- char *result = RSTRING_PTR(val);
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 (!event_hook_installed) {
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
- event_hook_installed = true;
298
+ rbtracer.installed = true;
263
299
  }
264
300
  }
265
301
 
266
302
  static void
267
303
  event_hook_remove()
268
304
  {
269
- if (event_hook_installed) {
305
+ if (rbtracer.installed) {
270
306
  rb_remove_event_hook(event_hook);
271
- event_hook_installed = false;
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 (tracers[i].query) {
285
- if (0 == strcmp(query, tracers[i].query)) {
286
- tracer = &tracers[i];
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 = &tracers[id];
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
- num_tracers--;
312
- if (num_tracers == 0)
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 (tracers[i].query) {
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 (num_tracers >= MAX_TRACERS) goto out;
382
+ if (rbtracer.num >= MAX_TRACERS) goto out;
344
383
 
345
384
  for (i=0; i<MAX_TRACERS; i++) {
346
- if (!tracers[i].query) {
347
- tracer = &tracers[i];
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 (num_tracers == 0)
431
+ if (rbtracer.num == 0)
393
432
  event_hook_install();
394
433
 
395
- num_tracers++;
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 = &tracers[id];
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 (!slow_tracer.enabled) {
438
- slow_tracer.num_calls = 0;
439
- slow_tracer.threshold = threshold;
440
- slow_tracer.enabled = true;
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 (slow_tracer.enabled) {
489
+ if (rbtracer.slow) {
450
490
  event_hook_remove();
451
491
 
452
- slow_tracer.enabled = false;
492
+ rbtracer.firehose = false;
493
+ rbtracer.slow = false;
453
494
  }
454
495
  }
455
496
 
456
- static VALUE
457
- rbtrace(VALUE self, VALUE query)
497
+ static void
498
+ msgq_teardown()
458
499
  {
459
- Check_Type(query, T_STRING);
460
-
461
- char *str = RSTRING_PTR(query);
462
- int tracer_id = -1;
463
-
464
- tracer_id = rbtracer_add(str);
465
- return tracer_id == -1 ? Qfalse : Qtrue;
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 VALUE
469
- untrace(VALUE self, VALUE query)
512
+ static void
513
+ ruby_teardown(VALUE data)
470
514
  {
471
- Check_Type(query, T_STRING);
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
- cleanup()
519
+ msgq_setup()
482
520
  {
483
- if (mqo_id != -1) {
484
- msgctl(mqo_id, IPC_RMID, NULL);
485
- mqo_id = -1;
486
- }
487
- if (mqi_id != -1) {
488
- msgctl(mqi_id, IPC_RMID, NULL);
489
- mqi_id = -1;
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
- static void
494
- cleanup_ruby(VALUE data)
495
- {
496
- cleanup();
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
- if (mqi_id == -1) return;
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("delall", msg.buf, 6)) {
532
- rbtracer_remove_all();
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
- atexit(cleanup);
559
- rb_set_end_proc(cleanup_ruby, 0);
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
- memset(&tracers, 0, sizeof(tracers));
564
-
565
- mqo_key = (key_t) getpid();
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
  }