byebug 1.8.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/GUIDE.md +14 -22
  4. data/README.md +69 -6
  5. data/bin/byebug +3 -20
  6. data/ext/byebug/breakpoint.c +185 -101
  7. data/ext/byebug/byebug.c +393 -214
  8. data/ext/byebug/byebug.h +34 -15
  9. data/ext/byebug/context.c +327 -102
  10. data/ext/byebug/extconf.rb +1 -1
  11. data/ext/byebug/locker.c +54 -0
  12. data/ext/byebug/threads.c +113 -0
  13. data/lib/byebug.rb +19 -58
  14. data/lib/byebug/command.rb +18 -19
  15. data/lib/byebug/commands/breakpoints.rb +1 -4
  16. data/lib/byebug/commands/catchpoint.rb +1 -1
  17. data/lib/byebug/commands/condition.rb +1 -1
  18. data/lib/byebug/commands/control.rb +2 -3
  19. data/lib/byebug/commands/display.rb +2 -7
  20. data/lib/byebug/commands/edit.rb +1 -1
  21. data/lib/byebug/commands/enable.rb +12 -12
  22. data/lib/byebug/commands/eval.rb +4 -4
  23. data/lib/byebug/commands/finish.rb +1 -1
  24. data/lib/byebug/commands/frame.rb +12 -8
  25. data/lib/byebug/commands/info.rb +20 -52
  26. data/lib/byebug/commands/kill.rb +1 -5
  27. data/lib/byebug/commands/list.rb +2 -1
  28. data/lib/byebug/commands/quit.rb +1 -1
  29. data/lib/byebug/commands/repl.rb +2 -2
  30. data/lib/byebug/commands/save.rb +1 -1
  31. data/lib/byebug/commands/set.rb +84 -90
  32. data/lib/byebug/commands/show.rb +44 -53
  33. data/lib/byebug/commands/skip.rb +1 -1
  34. data/lib/byebug/commands/stepping.rb +5 -4
  35. data/lib/byebug/commands/threads.rb +202 -0
  36. data/lib/byebug/commands/trace.rb +1 -1
  37. data/lib/byebug/helper.rb +3 -3
  38. data/lib/byebug/interface.rb +2 -20
  39. data/lib/byebug/processor.rb +21 -100
  40. data/lib/byebug/remote.rb +3 -3
  41. data/lib/byebug/version.rb +1 -1
  42. data/old_doc/byebug.1 +0 -6
  43. data/old_doc/byebug.texi +29 -46
  44. data/test/breakpoints_test.rb +44 -65
  45. data/test/conditions_test.rb +0 -9
  46. data/test/continue_test.rb +2 -2
  47. data/test/display_test.rb +4 -23
  48. data/test/edit_test.rb +2 -16
  49. data/test/eval_test.rb +4 -13
  50. data/test/examples/thread.rb +32 -0
  51. data/test/finish_test.rb +1 -13
  52. data/test/frame_test.rb +5 -12
  53. data/test/help_test.rb +2 -12
  54. data/test/info_test.rb +8 -18
  55. data/test/kill_test.rb +1 -10
  56. data/test/list_test.rb +5 -14
  57. data/test/method_test.rb +1 -10
  58. data/test/post_mortem_test.rb +247 -14
  59. data/test/quit_test.rb +0 -9
  60. data/test/reload_test.rb +1 -15
  61. data/test/repl_test.rb +1 -9
  62. data/test/restart_test.rb +3 -18
  63. data/test/save_test.rb +1 -13
  64. data/test/set_test.rb +35 -32
  65. data/test/show_test.rb +8 -27
  66. data/test/source_test.rb +1 -8
  67. data/test/stepping_test.rb +65 -96
  68. data/test/support/test_dsl.rb +12 -17
  69. data/test/test_helper.rb +1 -1
  70. data/test/thread_test.rb +106 -0
  71. data/test/trace_test.rb +5 -17
  72. data/test/variables_test.rb +1 -10
  73. metadata +9 -7
  74. data/lib/byebug/commands/jump.rb +0 -52
  75. data/test/jump_test.rb +0 -77
  76. data/test/support/context.rb +0 -15
@@ -5,13 +5,15 @@
5
5
  #include <ruby/debug.h>
6
6
 
7
7
  /* flags */
8
- #define CTX_FL_SUSPEND (1<<1)
9
- #define CTX_FL_TRACING (1<<2)
10
- #define CTX_FL_SKIPPED (1<<3)
11
- #define CTX_FL_DEAD (1<<4)
12
- #define CTX_FL_ENABLE_BKPT (1<<5)
13
- #define CTX_FL_FORCE_MOVE (1<<6)
14
- #define CTX_FL_CATCHING (1<<7)
8
+ #define CTX_FL_CATCHING (1<<1) /* catching of exceptions enabled */
9
+ #define CTX_FL_DEAD (1<<2) /* this context belonged to a dead thread */
10
+ #define CTX_FL_ENABLE_BKPT (1<<3) /* cab check for breakpoints */
11
+ #define CTX_FL_FORCE_MOVE (1<<4) /* don't stop unless we've changed line */
12
+ #define CTX_FL_IGNORE (1<<5) /* this context belongs to ignored thread */
13
+ #define CTX_FL_SKIPPED (1<<6) /* skip all events */
14
+ #define CTX_FL_SUSPEND (1<<7) /* thread currently suspended */
15
+ #define CTX_FL_TRACING (1<<8) /* call at_tracing method */
16
+ #define CTX_FL_WAS_RUNNING (1<<9) /* thread was previously running */
15
17
 
16
18
  /* macro functions */
17
19
  #define CTX_FL_TEST(c,f) ((c)->flags & (f))
@@ -31,6 +33,9 @@ typedef struct {
31
33
  int flags;
32
34
  ctx_stop_reason stop_reason;
33
35
 
36
+ VALUE thread;
37
+ int thnum;
38
+
34
39
  int dest_frame;
35
40
  int lines; /* # of lines in dest_frame before stopping */
36
41
  int steps; /* # of steps before stopping */
@@ -53,22 +58,36 @@ struct call_with_inspection_data {
53
58
  VALUE *argv;
54
59
  };
55
60
 
61
+ typedef struct {
62
+ st_table *tbl;
63
+ } threads_table_t;
64
+
65
+ /* functions from locker.c */
66
+ extern int is_in_locked(VALUE thread_id);
67
+ extern void add_to_locked(VALUE thread);
68
+ extern VALUE remove_from_locked();
69
+
70
+ /* functions from threads.c */
71
+ extern VALUE threads_create(void);
72
+ extern void threads_clear(VALUE table);
73
+ extern void check_thread_contexts(void);
74
+ extern void thread_context_lookup(VALUE thread, VALUE *context);
75
+ extern void halt_while_other_thread_is_active(debug_context_t *dc);
76
+
77
+ /* global variables */
78
+ extern VALUE locker;
79
+ extern VALUE threads;
80
+ extern VALUE cThreadsTable;
56
81
 
57
82
  /* functions */
58
- extern VALUE Init_context(VALUE mByebug);
59
-
60
- extern VALUE context_create();
61
-
83
+ extern void Init_context(VALUE mByebug);
84
+ extern VALUE context_create(VALUE thread);
62
85
  extern VALUE context_dup(debug_context_t *context);
63
-
64
86
  extern void reset_stepping_stop_points(debug_context_t *context);
65
-
66
87
  extern VALUE call_with_debug_inspector(struct call_with_inspection_data *data);
67
-
68
88
  extern VALUE context_backtrace_set(const rb_debug_inspector_t *inspector,
69
89
  void *data);
70
90
 
71
- /* utility functions */
72
91
  static inline int
73
92
  classname_cmp(VALUE name, VALUE klass)
74
93
  {
@@ -1,6 +1,8 @@
1
1
  #include <byebug.h>
2
2
 
3
3
  static VALUE cContext;
4
+ static VALUE cDebugThread;
5
+ static int thnum_max = 0;
4
6
 
5
7
  /* "Step", "Next" and "Finish" do their work by saving information about where
6
8
  * to stop next. reset_stepping_stop_points removes/resets this information. */
@@ -14,14 +16,13 @@ reset_stepping_stop_points(debug_context_t *context)
14
16
  context->before_frame = -1;
15
17
  }
16
18
 
17
- static inline VALUE
18
- Context_stack_size(VALUE self)
19
- {
20
- debug_context_t *context;
21
- Data_Get_Struct(self, debug_context_t, context);
22
- return INT2FIX(context->stack_size);
23
- }
24
-
19
+ /*
20
+ * call-seq:
21
+ * context.dead? -> bool
22
+ *
23
+ * Returns +true+ if context doesn't represent a live context and is created
24
+ * during post-mortem exception handling.
25
+ */
25
26
  static inline VALUE
26
27
  Context_dead(VALUE self)
27
28
  {
@@ -44,24 +45,31 @@ context_free(void *data)
44
45
  }
45
46
 
46
47
  static int
47
- real_stack_size()
48
+ real_stack_size(VALUE thread)
48
49
  {
49
- VALUE locs = rb_funcall(rb_cObject, rb_intern("caller_locations"), 1, INT2FIX(0));
50
+ VALUE locs = rb_funcall(thread, rb_intern("backtrace_locations"), 1, INT2FIX(1));
51
+ if (locs == Qnil)
52
+ return 0;
53
+
50
54
  return (int)RARRAY_LEN(locs);
51
55
  }
52
56
 
53
57
  extern VALUE
54
- context_create()
58
+ context_create(VALUE thread)
55
59
  {
56
60
  debug_context_t *context = ALLOC(debug_context_t);
57
61
 
58
- context->last_file = Qnil;
59
- context->last_line = Qnil;
60
- context->flags = 0;
61
- context->stack_size = real_stack_size();
62
+ context->last_file = Qnil;
63
+ context->last_line = Qnil;
64
+ context->flags = 0;
65
+ context->stack_size = real_stack_size(thread);
66
+ context->thnum = ++thnum_max;
67
+ context->thread = thread;
62
68
  reset_stepping_stop_points(context);
63
69
  context->stop_reason = CTX_STOP_NONE;
64
- context->backtrace = Qnil;
70
+ context->backtrace = Qnil;
71
+
72
+ if (rb_obj_class(thread) == cDebugThread) CTX_FL_SET(context, CTX_FL_IGNORE);
65
73
 
66
74
  return Data_Wrap_Struct(cContext, context_mark, context_free, context);
67
75
  }
@@ -82,9 +90,6 @@ context_dup(debug_context_t *context)
82
90
  static VALUE
83
91
  dc_backtrace(const debug_context_t *context)
84
92
  {
85
- if (NIL_P(context->backtrace))
86
- rb_raise(rb_eRuntimeError, "Backtrace information is not available");
87
-
88
93
  return context->backtrace;
89
94
  }
90
95
 
@@ -92,6 +97,9 @@ static VALUE
92
97
  dc_frame_get(const debug_context_t *context, int frame_index,
93
98
  enum frame_component type)
94
99
  {
100
+ if (NIL_P(dc_backtrace(context)))
101
+ rb_raise(rb_eRuntimeError, "Backtrace information is not available");
102
+
95
103
  if (frame_index >= RARRAY_LEN(dc_backtrace(context)))
96
104
  rb_raise(rb_eRuntimeError, "That frame doesn't exist!");
97
105
 
@@ -192,87 +200,170 @@ call_with_debug_inspector(struct call_with_inspection_data *data)
192
200
  frame_n = 0; \
193
201
  else \
194
202
  frame_n = FIX2INT(frame_no); \
195
- if (frame_n < 0 || frame_n >= context->stack_size) \
203
+ if (frame_n < 0 || frame_n >= real_stack_size(rb_thread_current())) \
196
204
  { \
197
205
  rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)", \
198
- frame_n, context->stack_size - 1); \
206
+ frame_n, real_stack_size(rb_thread_current() - 1)); \
199
207
  } \
200
208
 
209
+ /*
210
+ * call-seq:
211
+ * context.frame_binding(frame_position=0) -> binding
212
+ *
213
+ * Returns frame's binding.
214
+ */
215
+ static VALUE
216
+ Context_frame_binding(int argc, VALUE *argv, VALUE self)
217
+ {
218
+ FRAME_SETUP
219
+
220
+ return dc_frame_binding(context, frame_n);
221
+ }
222
+
223
+ /*
224
+ * call-seq:
225
+ * context.frame_class(frame_position=0) -> binding
226
+ *
227
+ * Returns frame's defined class.
228
+ */
229
+ static VALUE
230
+ Context_frame_class(int argc, VALUE *argv, VALUE self)
231
+ {
232
+ FRAME_SETUP
233
+
234
+ return dc_frame_class(context, frame_n);
235
+ }
236
+
237
+ /*
238
+ * call-seq:
239
+ * context.frame_file(frame_position=0) -> string
240
+ *
241
+ * Returns the name of the file in the frame.
242
+ */
201
243
  static VALUE
202
244
  Context_frame_file(int argc, VALUE *argv, VALUE self)
203
245
  {
204
- FRAME_SETUP;
205
- VALUE loc;
246
+ FRAME_SETUP
247
+
248
+ VALUE loc = dc_frame_location(context, frame_n);
206
249
 
207
- loc = dc_frame_location(context, frame_n);
208
250
  return rb_funcall(loc, rb_intern("path"), 0);
209
251
  }
210
252
 
253
+ /*
254
+ * call-seq:
255
+ * context.frame_line(frame_position) -> int
256
+ *
257
+ * Returns the line number in the file.
258
+ */
211
259
  static VALUE
212
260
  Context_frame_line(int argc, VALUE *argv, VALUE self)
213
261
  {
214
- FRAME_SETUP;
215
- VALUE loc;
262
+ FRAME_SETUP
263
+
264
+ VALUE loc = dc_frame_location(context, frame_n);
216
265
 
217
- loc = dc_frame_location(context, frame_n);
218
266
  return rb_funcall(loc, rb_intern("lineno"), 0);
219
267
  }
220
268
 
269
+ /*
270
+ * call-seq:
271
+ * context.frame_method(frame_position=0) -> sym
272
+ *
273
+ * Returns the sym of the called method.
274
+ */
221
275
  static VALUE
222
276
  Context_frame_method(int argc, VALUE *argv, VALUE self)
223
277
  {
224
- FRAME_SETUP;
225
- VALUE loc;
278
+ FRAME_SETUP
279
+
280
+ VALUE loc = dc_frame_location(context, frame_n);
226
281
 
227
- loc = dc_frame_location(context, frame_n);
228
282
  return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
229
283
  }
230
284
 
285
+ /*
286
+ * call-seq:
287
+ * context.frame_self(frame_postion=0) -> obj
288
+ *
289
+ * Returns self object of the frame.
290
+ */
231
291
  static VALUE
232
- Context_frame_binding(int argc, VALUE *argv, VALUE self)
292
+ Context_frame_self(int argc, VALUE *argv, VALUE self)
233
293
  {
234
- FRAME_SETUP;
294
+ FRAME_SETUP
235
295
 
236
- return dc_frame_binding(context, frame_n);
296
+ return dc_frame_self(context, frame_n);
237
297
  }
238
298
 
239
- static VALUE
240
- Context_frame_self(int argc, VALUE *argv, VALUE self)
299
+ /*
300
+ * call-seq:
301
+ * context.ignored? -> bool
302
+ *
303
+ * Returns the ignore flag for the context, which marks whether the associated
304
+ * thread is ignored while debugging.
305
+ */
306
+ static inline VALUE
307
+ Context_ignored(VALUE self)
241
308
  {
242
- FRAME_SETUP;
243
-
244
- return dc_frame_self(context, frame_n);
309
+ debug_context_t *context;
310
+ Data_Get_Struct(self, debug_context_t, context);
311
+ return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
245
312
  }
246
313
 
247
- static VALUE
248
- Context_frame_class(int argc, VALUE *argv, VALUE self)
314
+ static void
315
+ context_resume_0(debug_context_t *context)
249
316
  {
250
- FRAME_SETUP;
317
+ if (!CTX_FL_TEST(context, CTX_FL_SUSPEND)) return;
251
318
 
252
- return dc_frame_class(context, frame_n);
319
+ CTX_FL_UNSET(context, CTX_FL_SUSPEND);
320
+
321
+ if (CTX_FL_TEST(context, CTX_FL_WAS_RUNNING))
322
+ rb_thread_wakeup(context->thread);
253
323
  }
254
324
 
325
+ /*
326
+ * call-seq:
327
+ * context.resume -> nil
328
+ *
329
+ * Resumes thread from the suspended mode.
330
+ */
255
331
  static VALUE
256
- Context_tracing(VALUE self)
332
+ Context_resume(VALUE self)
257
333
  {
258
- debug_context_t *context;
334
+ debug_context_t *context;
259
335
 
260
- Data_Get_Struct(self, debug_context_t, context);
261
- return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
336
+ Data_Get_Struct(self, debug_context_t, context);
337
+
338
+ if (!CTX_FL_TEST(context, CTX_FL_SUSPEND))
339
+ rb_raise(rb_eRuntimeError, "Thread is not suspended.");
340
+
341
+ context_resume_0(context);
342
+
343
+ return Qnil;
262
344
  }
263
345
 
264
- static VALUE
265
- Context_set_tracing(VALUE self, VALUE value)
346
+ /*
347
+ * call-seq:
348
+ * context.stack_size-> int
349
+ *
350
+ * Returns the size of the context stack.
351
+ */
352
+ static inline VALUE
353
+ Context_stack_size(VALUE self)
266
354
  {
267
355
  debug_context_t *context;
268
-
269
356
  Data_Get_Struct(self, debug_context_t, context);
357
+ VALUE backtrace = dc_backtrace(context);
270
358
 
271
- if (RTEST(value))
272
- CTX_FL_SET(context, CTX_FL_TRACING);
273
- else
274
- CTX_FL_UNSET(context, CTX_FL_TRACING);
275
- return value;
359
+ if (NIL_P(backtrace))
360
+ return INT2FIX(context->stack_size);
361
+
362
+ if (context->stack_size != RARRAY_LEN(backtrace))
363
+ rb_warn("Calculated stack size is %d but there are actually %ld frames",
364
+ context->stack_size, RARRAY_LEN(backtrace));
365
+
366
+ return INT2FIX(RARRAY_LEN(backtrace));
276
367
  }
277
368
 
278
369
  static VALUE
@@ -303,30 +394,14 @@ Context_stop_reason(VALUE self)
303
394
  return ID2SYM(rb_intern(symbol));
304
395
  }
305
396
 
306
- #if 0
307
-
308
- static VALUE
309
- Context_jump(VALUE self, VALUE line, VALUE file)
310
- {
311
- debug_context_t *context;
312
- debug_frame_t *frame;
313
- int i, lineno;
314
-
315
- Data_Get_Struct(self, debug_context_t, context);
316
-
317
- frame = context->stack;
318
- lineno = FIX2INT(line);
319
-
320
- for (i = 0; i < context->stack_size; i++) {
321
- if (strcmp(frame->file, RSTRING_PTR(file))) {
322
- /* And now? */
323
- }
324
- frame = frame->prev;
325
- }
326
- }
327
-
328
- #endif
329
-
397
+ /*
398
+ * call-seq:
399
+ * context.step_into(steps, force = false)
400
+ *
401
+ * Stops the current context after a number of +steps+ are made.
402
+ * +force+ parameter (if true) ensures that the cursor moves away from the
403
+ * current line.
404
+ */
330
405
  static VALUE
331
406
  Context_step_into(int argc, VALUE *argv, VALUE self)
332
407
  {
@@ -349,6 +424,36 @@ Context_step_into(int argc, VALUE *argv, VALUE self)
349
424
  return steps;
350
425
  }
351
426
 
427
+ /*
428
+ * call-seq:
429
+ * context.step_out(frame)
430
+ *
431
+ * Stops after frame number +frame+ is activated. Implements +finish+ and
432
+ * +next+ commands.
433
+ */
434
+ static VALUE
435
+ Context_step_out(VALUE self, VALUE frame)
436
+ {
437
+ debug_context_t *context;
438
+ Data_Get_Struct(self, debug_context_t, context);
439
+
440
+ if (FIX2INT(frame) < 0 || FIX2INT(frame) >= context->stack_size)
441
+ rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
442
+
443
+ context->after_frame = context->stack_size - FIX2INT(frame);
444
+
445
+ return frame;
446
+ }
447
+
448
+ /*
449
+ * call-seq:
450
+ * context.step_over(lines, frame = nil, force = false)
451
+ *
452
+ * Steps over +lines+ lines.
453
+ * Make step over operation on +frame+, by default the current frame.
454
+ * +force+ parameter (if true) ensures that the cursor moves away from the
455
+ * current line.
456
+ */
352
457
  static VALUE
353
458
  Context_step_over(int argc, VALUE *argv, VALUE self)
354
459
  {
@@ -375,8 +480,15 @@ Context_step_over(int argc, VALUE *argv, VALUE self)
375
480
  return Qnil;
376
481
  }
377
482
 
483
+ /*
484
+ * call-seq:
485
+ * context.stop_return(frame)
486
+ *
487
+ * Stops before frame number +frame+ is activated. Useful when you enter the
488
+ * debugger after the last statement in a method.
489
+ */
378
490
  static VALUE
379
- Context_step_out(VALUE self, VALUE frame)
491
+ Context_stop_return(VALUE self, VALUE frame)
380
492
  {
381
493
  debug_context_t *context;
382
494
  Data_Get_Struct(self, debug_context_t, context);
@@ -384,23 +496,128 @@ Context_step_out(VALUE self, VALUE frame)
384
496
  if (FIX2INT(frame) < 0 || FIX2INT(frame) >= context->stack_size)
385
497
  rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
386
498
 
387
- context->after_frame = context->stack_size - FIX2INT(frame);
499
+ context->before_frame = context->stack_size - FIX2INT(frame);
388
500
 
389
501
  return frame;
390
502
  }
391
503
 
504
+ static void
505
+ context_suspend_0(debug_context_t *context)
506
+ {
507
+ VALUE status = rb_funcall(context->thread, rb_intern("status"), 0);
508
+
509
+ if (rb_str_cmp(status, rb_str_new2("run")) == 0)
510
+ CTX_FL_SET(context, CTX_FL_WAS_RUNNING);
511
+ else if (rb_str_cmp(status, rb_str_new2("sleep")) == 0)
512
+ CTX_FL_UNSET(context, CTX_FL_WAS_RUNNING);
513
+ else
514
+ return;
515
+
516
+ CTX_FL_SET(context, CTX_FL_SUSPEND);
517
+ }
518
+
519
+ /*
520
+ * call-seq:
521
+ * context.suspend -> nil
522
+ *
523
+ * Suspends the thread when it is running.
524
+ */
392
525
  static VALUE
393
- Context_stop_return(VALUE self, VALUE frame)
526
+ Context_suspend(VALUE self)
394
527
  {
395
528
  debug_context_t *context;
396
529
  Data_Get_Struct(self, debug_context_t, context);
397
530
 
398
- if (FIX2INT(frame) < 0 || FIX2INT(frame) >= context->stack_size)
399
- rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
531
+ if (CTX_FL_TEST(context, CTX_FL_SUSPEND))
532
+ rb_raise(rb_eRuntimeError, "Already suspended.");
400
533
 
401
- context->before_frame = context->stack_size - FIX2INT(frame);
534
+ context_suspend_0(context);
535
+ return Qnil;
536
+ }
402
537
 
403
- return frame;
538
+ /*
539
+ * call-seq:
540
+ * context.suspended? -> bool
541
+ *
542
+ * Returns +true+ if the thread is suspended by debugger.
543
+ */
544
+ static VALUE
545
+ Context_is_suspended(VALUE self)
546
+ {
547
+ debug_context_t *context;
548
+ Data_Get_Struct(self, debug_context_t, context);
549
+
550
+ return CTX_FL_TEST(context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
551
+ }
552
+
553
+ /*
554
+ * call-seq:
555
+ * context.thnum -> int
556
+ *
557
+ * Returns the context's number.
558
+ */
559
+ static inline VALUE
560
+ Context_thnum(VALUE self) {
561
+ debug_context_t *context;
562
+ Data_Get_Struct(self, debug_context_t, context);
563
+ return INT2FIX(context->thnum);
564
+ }
565
+
566
+ /*
567
+ * call-seq:
568
+ * context.thread -> thread
569
+ *
570
+ * Returns the thread this context is associated with.
571
+ */
572
+ static inline VALUE
573
+ Context_thread(VALUE self)
574
+ {
575
+ debug_context_t *context;
576
+ Data_Get_Struct(self, debug_context_t, context);
577
+ return context->thread;
578
+ }
579
+
580
+ /*
581
+ * call-seq:
582
+ * context.tracing -> bool
583
+ *
584
+ * Returns the tracing flag for the current context.
585
+ */
586
+ static VALUE
587
+ Context_tracing(VALUE self)
588
+ {
589
+ debug_context_t *context;
590
+
591
+ Data_Get_Struct(self, debug_context_t, context);
592
+ return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
593
+ }
594
+
595
+ /*
596
+ * call-seq:
597
+ * context.tracing = bool
598
+ *
599
+ * Controls the tracing for this context.
600
+ */
601
+ static VALUE
602
+ Context_set_tracing(VALUE self, VALUE value)
603
+ {
604
+ debug_context_t *context;
605
+
606
+ Data_Get_Struct(self, debug_context_t, context);
607
+
608
+ if (RTEST(value))
609
+ CTX_FL_SET(context, CTX_FL_TRACING);
610
+ else
611
+ CTX_FL_UNSET(context, CTX_FL_TRACING);
612
+ return value;
613
+ }
614
+
615
+
616
+ /* :nodoc: */
617
+ static VALUE
618
+ DebugThread_inherited(VALUE klass)
619
+ {
620
+ rb_raise(rb_eRuntimeError, "Can't inherit Byebug::DebugThread class");
404
621
  }
405
622
 
406
623
  /*
@@ -410,25 +627,33 @@ Context_stop_return(VALUE self, VALUE frame)
410
627
  *
411
628
  * Byebug keeps a single instance of this class.
412
629
  */
413
- VALUE
630
+ void
414
631
  Init_context(VALUE mByebug)
415
632
  {
416
633
  cContext = rb_define_class_under(mByebug, "Context", rb_cObject);
417
- rb_define_method(cContext, "stack_size", Context_stack_size, 0);
418
- rb_define_method(cContext, "dead?", Context_dead, 0);
419
- rb_define_method(cContext, "stop_reason", Context_stop_reason, 0);
420
- rb_define_method(cContext, "tracing", Context_tracing, 0);
421
- rb_define_method(cContext, "tracing=", Context_set_tracing, 1);
422
- rb_define_method(cContext, "frame_file", Context_frame_file, -1);
423
- rb_define_method(cContext, "frame_line", Context_frame_line, -1);
424
- rb_define_method(cContext, "frame_method", Context_frame_method, -1);
634
+
635
+ rb_define_method(cContext, "dead?" , Context_dead , 0);
425
636
  rb_define_method(cContext, "frame_binding", Context_frame_binding, -1);
426
- rb_define_method(cContext, "frame_self", Context_frame_self, -1);
427
- rb_define_method(cContext, "frame_class", Context_frame_class, -1);
428
- rb_define_method(cContext, "step_into", Context_step_into, -1);
429
- rb_define_method(cContext, "step_over", Context_step_over, -1);
430
- rb_define_method(cContext, "step_out", Context_step_out, 1);
431
- rb_define_method(cContext, "stop_return", Context_stop_return, 1);
432
-
433
- return cContext;
637
+ rb_define_method(cContext, "frame_class" , Context_frame_class , -1);
638
+ rb_define_method(cContext, "frame_file" , Context_frame_file , -1);
639
+ rb_define_method(cContext, "frame_line" , Context_frame_line , -1);
640
+ rb_define_method(cContext, "frame_method" , Context_frame_method , -1);
641
+ rb_define_method(cContext, "frame_self" , Context_frame_self , -1);
642
+ rb_define_method(cContext, "ignored?" , Context_ignored , 0);
643
+ rb_define_method(cContext, "resume" , Context_resume , 0);
644
+ rb_define_method(cContext, "stack_size" , Context_stack_size , 0);
645
+ rb_define_method(cContext, "step_into" , Context_step_into , -1);
646
+ rb_define_method(cContext, "step_out" , Context_step_out , 1);
647
+ rb_define_method(cContext, "step_over" , Context_step_over , -1);
648
+ rb_define_method(cContext, "stop_return" , Context_stop_return , 1);
649
+ rb_define_method(cContext, "stop_reason" , Context_stop_reason , 0);
650
+ rb_define_method(cContext, "suspend" , Context_suspend , 0);
651
+ rb_define_method(cContext, "suspended?" , Context_is_suspended , 0);
652
+ rb_define_method(cContext, "thnum" , Context_thnum , 0);
653
+ rb_define_method(cContext, "thread" , Context_thread , 0);
654
+ rb_define_method(cContext, "tracing" , Context_tracing , 0);
655
+ rb_define_method(cContext, "tracing=" , Context_set_tracing , 1);
656
+
657
+ cDebugThread = rb_define_class_under(mByebug, "DebugThread", rb_cThread);
658
+ rb_define_singleton_method(cDebugThread, "inherited", DebugThread_inherited, 1);
434
659
  }