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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -1
- data/GUIDE.md +14 -22
- data/README.md +69 -6
- data/bin/byebug +3 -20
- data/ext/byebug/breakpoint.c +185 -101
- data/ext/byebug/byebug.c +393 -214
- data/ext/byebug/byebug.h +34 -15
- data/ext/byebug/context.c +327 -102
- data/ext/byebug/extconf.rb +1 -1
- data/ext/byebug/locker.c +54 -0
- data/ext/byebug/threads.c +113 -0
- data/lib/byebug.rb +19 -58
- data/lib/byebug/command.rb +18 -19
- data/lib/byebug/commands/breakpoints.rb +1 -4
- data/lib/byebug/commands/catchpoint.rb +1 -1
- data/lib/byebug/commands/condition.rb +1 -1
- data/lib/byebug/commands/control.rb +2 -3
- data/lib/byebug/commands/display.rb +2 -7
- data/lib/byebug/commands/edit.rb +1 -1
- data/lib/byebug/commands/enable.rb +12 -12
- data/lib/byebug/commands/eval.rb +4 -4
- data/lib/byebug/commands/finish.rb +1 -1
- data/lib/byebug/commands/frame.rb +12 -8
- data/lib/byebug/commands/info.rb +20 -52
- data/lib/byebug/commands/kill.rb +1 -5
- data/lib/byebug/commands/list.rb +2 -1
- data/lib/byebug/commands/quit.rb +1 -1
- data/lib/byebug/commands/repl.rb +2 -2
- data/lib/byebug/commands/save.rb +1 -1
- data/lib/byebug/commands/set.rb +84 -90
- data/lib/byebug/commands/show.rb +44 -53
- data/lib/byebug/commands/skip.rb +1 -1
- data/lib/byebug/commands/stepping.rb +5 -4
- data/lib/byebug/commands/threads.rb +202 -0
- data/lib/byebug/commands/trace.rb +1 -1
- data/lib/byebug/helper.rb +3 -3
- data/lib/byebug/interface.rb +2 -20
- data/lib/byebug/processor.rb +21 -100
- data/lib/byebug/remote.rb +3 -3
- data/lib/byebug/version.rb +1 -1
- data/old_doc/byebug.1 +0 -6
- data/old_doc/byebug.texi +29 -46
- data/test/breakpoints_test.rb +44 -65
- data/test/conditions_test.rb +0 -9
- data/test/continue_test.rb +2 -2
- data/test/display_test.rb +4 -23
- data/test/edit_test.rb +2 -16
- data/test/eval_test.rb +4 -13
- data/test/examples/thread.rb +32 -0
- data/test/finish_test.rb +1 -13
- data/test/frame_test.rb +5 -12
- data/test/help_test.rb +2 -12
- data/test/info_test.rb +8 -18
- data/test/kill_test.rb +1 -10
- data/test/list_test.rb +5 -14
- data/test/method_test.rb +1 -10
- data/test/post_mortem_test.rb +247 -14
- data/test/quit_test.rb +0 -9
- data/test/reload_test.rb +1 -15
- data/test/repl_test.rb +1 -9
- data/test/restart_test.rb +3 -18
- data/test/save_test.rb +1 -13
- data/test/set_test.rb +35 -32
- data/test/show_test.rb +8 -27
- data/test/source_test.rb +1 -8
- data/test/stepping_test.rb +65 -96
- data/test/support/test_dsl.rb +12 -17
- data/test/test_helper.rb +1 -1
- data/test/thread_test.rb +106 -0
- data/test/trace_test.rb +5 -17
- data/test/variables_test.rb +1 -10
- metadata +9 -7
- data/lib/byebug/commands/jump.rb +0 -52
- data/test/jump_test.rb +0 -77
- data/test/support/context.rb +0 -15
data/ext/byebug/byebug.h
CHANGED
@@ -5,13 +5,15 @@
|
|
5
5
|
#include <ruby/debug.h>
|
6
6
|
|
7
7
|
/* flags */
|
8
|
-
#define
|
9
|
-
#define
|
10
|
-
#define
|
11
|
-
#define
|
12
|
-
#define
|
13
|
-
#define
|
14
|
-
#define
|
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
|
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
|
{
|
data/ext/byebug/context.c
CHANGED
@@ -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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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(
|
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
|
59
|
-
context->last_line
|
60
|
-
context->flags
|
61
|
-
context->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
|
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 >=
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
292
|
+
Context_frame_self(int argc, VALUE *argv, VALUE self)
|
233
293
|
{
|
234
|
-
FRAME_SETUP
|
294
|
+
FRAME_SETUP
|
235
295
|
|
236
|
-
return
|
296
|
+
return dc_frame_self(context, frame_n);
|
237
297
|
}
|
238
298
|
|
239
|
-
|
240
|
-
|
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
|
-
|
243
|
-
|
244
|
-
return
|
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
|
248
|
-
|
314
|
+
static void
|
315
|
+
context_resume_0(debug_context_t *context)
|
249
316
|
{
|
250
|
-
|
317
|
+
if (!CTX_FL_TEST(context, CTX_FL_SUSPEND)) return;
|
251
318
|
|
252
|
-
|
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
|
-
|
332
|
+
Context_resume(VALUE self)
|
257
333
|
{
|
258
|
-
|
334
|
+
debug_context_t *context;
|
259
335
|
|
260
|
-
|
261
|
-
|
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
|
-
|
265
|
-
|
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 (
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
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
|
-
|
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->
|
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
|
-
|
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 (
|
399
|
-
rb_raise(rb_eRuntimeError, "
|
531
|
+
if (CTX_FL_TEST(context, CTX_FL_SUSPEND))
|
532
|
+
rb_raise(rb_eRuntimeError, "Already suspended.");
|
400
533
|
|
401
|
-
context
|
534
|
+
context_suspend_0(context);
|
535
|
+
return Qnil;
|
536
|
+
}
|
402
537
|
|
403
|
-
|
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
|
-
|
630
|
+
void
|
414
631
|
Init_context(VALUE mByebug)
|
415
632
|
{
|
416
633
|
cContext = rb_define_class_under(mByebug, "Context", rb_cObject);
|
417
|
-
|
418
|
-
rb_define_method(cContext, "dead?", Context_dead,
|
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, "
|
427
|
-
rb_define_method(cContext, "
|
428
|
-
rb_define_method(cContext, "
|
429
|
-
rb_define_method(cContext, "
|
430
|
-
rb_define_method(cContext, "
|
431
|
-
rb_define_method(cContext, "
|
432
|
-
|
433
|
-
|
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
|
}
|