byebug 1.8.2 → 2.0.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.
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
  }