ruby-debug 0.4.3-mswin32 → 0.4.4-mswin32
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.
- data/CHANGES +5 -0
- data/Rakefile +1 -1
- data/bin/rdebug +3 -0
- data/ext/ruby_debug.c +239 -99
- data/lib/ruby-debug.rb +2 -5
- data/lib/ruby-debug/commands/display.rb +0 -4
- data/lib/ruby-debug/commands/threads.rb +2 -2
- data/lib/ruby_debug.so +0 -0
- metadata +2 -3
- data/lib/ruby-debug/lock.rb +0 -41
data/CHANGES
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
0.4.4
|
2
|
+
- Renamed Context#set_suspend and Context#clear_suspend methods to Context#suspend and Context#resume respectively.
|
3
|
+
- Context#resume method not only clears suspend flag, but also resumes the thread execution.
|
4
|
+
- Bugfixes.
|
5
|
+
|
1
6
|
0.4.3
|
2
7
|
- Added Debugger.skip method which allows escaping a block from the debugger reach.
|
3
8
|
- Bugfixes.
|
data/Rakefile
CHANGED
data/bin/rdebug
CHANGED
@@ -29,6 +29,9 @@ EOB
|
|
29
29
|
opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
|
30
30
|
opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
|
31
31
|
opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
|
32
|
+
opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path|
|
33
|
+
$LOAD_PATH.unshift(path)
|
34
|
+
end
|
32
35
|
opts.on("--script FILE", String, "Name of the script file to run") do |options.script|
|
33
36
|
unless File.exists?(options.script)
|
34
37
|
puts "Script file '#{options.script}' is not found"
|
data/ext/ruby_debug.c
CHANGED
@@ -4,21 +4,35 @@
|
|
4
4
|
#include <rubysig.h>
|
5
5
|
#include <st.h>
|
6
6
|
|
7
|
-
#define DEBUG_VERSION "0.4.
|
7
|
+
#define DEBUG_VERSION "0.4.4"
|
8
|
+
|
9
|
+
#define CTX_FL_MOVED (1<<1)
|
10
|
+
#define CTX_FL_SUSPEND (1<<2)
|
11
|
+
#define CTX_FL_TRACING (1<<3)
|
12
|
+
#define CTX_FL_SKIPPED (1<<4)
|
13
|
+
#define CTX_FL_IGNORE (1<<5)
|
14
|
+
|
15
|
+
#define CTX_FL_TEST(c,f) ((c)->flags & (f))
|
16
|
+
#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
|
17
|
+
#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
|
18
|
+
|
19
|
+
#define DID_MOVED (debug_context->last_line != line || \
|
20
|
+
debug_context->last_file == Qnil || \
|
21
|
+
rb_str_cmp(debug_context->last_file, file) != 0)
|
22
|
+
|
23
|
+
#define IS_STARTED (threads_tbl != Qnil)
|
8
24
|
|
9
25
|
typedef struct {
|
10
26
|
int thnum;
|
11
|
-
|
12
|
-
VALUE last_line;
|
13
|
-
int moved;
|
27
|
+
int flags;
|
14
28
|
int stop_next;
|
15
29
|
int dest_frame;
|
16
30
|
int stop_line;
|
17
31
|
int stop_frame;
|
18
|
-
int suspend;
|
19
|
-
int tracing;
|
20
32
|
VALUE frames;
|
21
33
|
VALUE thread;
|
34
|
+
VALUE last_file;
|
35
|
+
VALUE last_line;
|
22
36
|
} debug_context_t;
|
23
37
|
|
24
38
|
typedef struct {
|
@@ -34,14 +48,18 @@ typedef struct {
|
|
34
48
|
VALUE expr;
|
35
49
|
} debug_breakpoint_t;
|
36
50
|
|
51
|
+
typedef struct {
|
52
|
+
st_table *tbl;
|
53
|
+
} threads_table_t;
|
54
|
+
|
37
55
|
static VALUE threads_tbl = Qnil;
|
38
56
|
static VALUE breakpoints = Qnil;
|
39
57
|
static VALUE catchpoint = Qnil;
|
40
|
-
static VALUE waiting = Qnil;
|
41
58
|
static VALUE tracing = Qfalse;
|
42
59
|
static VALUE locker = Qnil;
|
43
60
|
|
44
61
|
static VALUE mDebugger;
|
62
|
+
static VALUE cThreadsTable;
|
45
63
|
static VALUE cContext;
|
46
64
|
static VALUE cFrame;
|
47
65
|
static VALUE cBreakpoint;
|
@@ -64,7 +82,6 @@ static int start_count = 0;
|
|
64
82
|
static int thnum_max = 0;
|
65
83
|
static int last_debugged_thnum = -1;
|
66
84
|
|
67
|
-
static VALUE debug_suspend(VALUE);
|
68
85
|
static VALUE create_binding(VALUE);
|
69
86
|
static VALUE debug_stop(VALUE);
|
70
87
|
|
@@ -126,7 +143,72 @@ remove_from_locked()
|
|
126
143
|
return thread;
|
127
144
|
}
|
128
145
|
|
129
|
-
|
146
|
+
static int
|
147
|
+
thread_hash(VALUE thread)
|
148
|
+
{
|
149
|
+
return (int)FIX2LONG(rb_obj_id(thread));
|
150
|
+
}
|
151
|
+
|
152
|
+
static int
|
153
|
+
thread_cmp(VALUE a, VALUE b)
|
154
|
+
{
|
155
|
+
if(a == b) return 0;
|
156
|
+
if(a < b) return -1;
|
157
|
+
return 1;
|
158
|
+
}
|
159
|
+
|
160
|
+
static struct st_hash_type st_thread_hash = {
|
161
|
+
thread_cmp,
|
162
|
+
thread_hash
|
163
|
+
};
|
164
|
+
|
165
|
+
static int
|
166
|
+
threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy)
|
167
|
+
{
|
168
|
+
rb_gc_mark(key);
|
169
|
+
rb_gc_mark(value);
|
170
|
+
return ST_CONTINUE;
|
171
|
+
}
|
172
|
+
|
173
|
+
static void
|
174
|
+
threads_table_mark(void* data)
|
175
|
+
{
|
176
|
+
threads_table_t *threads_table = (threads_table_t*)data;
|
177
|
+
st_foreach(threads_table->tbl, threads_table_mark_keyvalue, 0);
|
178
|
+
}
|
179
|
+
|
180
|
+
static void
|
181
|
+
threads_table_free(void* data)
|
182
|
+
{
|
183
|
+
threads_table_t *threads_table = (threads_table_t*)data;
|
184
|
+
st_free_table(threads_table->tbl);
|
185
|
+
xfree(threads_table);
|
186
|
+
}
|
187
|
+
|
188
|
+
static VALUE
|
189
|
+
threads_table_create()
|
190
|
+
{
|
191
|
+
threads_table_t *threads_table;
|
192
|
+
|
193
|
+
threads_table = ALLOC(threads_table_t);
|
194
|
+
threads_table->tbl = st_init_table(&st_thread_hash);
|
195
|
+
return Data_Wrap_Struct(cThreadsTable, threads_table_mark, threads_table_free, threads_table);
|
196
|
+
}
|
197
|
+
|
198
|
+
static int
|
199
|
+
threads_table_clear_i(VALUE key, VALUE value, VALUE dummy)
|
200
|
+
{
|
201
|
+
return ST_DELETE;
|
202
|
+
}
|
203
|
+
|
204
|
+
static void
|
205
|
+
threads_table_clear(VALUE table)
|
206
|
+
{
|
207
|
+
threads_table_t *threads_table;
|
208
|
+
|
209
|
+
Data_Get_Struct(table, threads_table_t, threads_table);
|
210
|
+
st_foreach(threads_table->tbl, threads_table_clear_i, 0);
|
211
|
+
}
|
130
212
|
|
131
213
|
/*
|
132
214
|
* call-seq:
|
@@ -170,14 +252,12 @@ debug_context_create(VALUE thread)
|
|
170
252
|
|
171
253
|
debug_context->last_file = Qnil;
|
172
254
|
debug_context->last_line = Qnil;
|
173
|
-
debug_context->
|
255
|
+
debug_context->flags = 0;
|
174
256
|
|
175
257
|
debug_context->stop_next = -1;
|
176
258
|
debug_context->dest_frame = -1;
|
177
259
|
debug_context->stop_line = -1;
|
178
260
|
debug_context->stop_frame = -1;
|
179
|
-
debug_context->suspend = 0;
|
180
|
-
debug_context->tracing = 0;
|
181
261
|
debug_context->frames = rb_ary_new();
|
182
262
|
debug_context->thread = thread;
|
183
263
|
result = Data_Wrap_Struct(cContext, debug_context_mark, xfree, debug_context);
|
@@ -188,14 +268,15 @@ static VALUE
|
|
188
268
|
thread_context_lookup(VALUE thread)
|
189
269
|
{
|
190
270
|
VALUE context;
|
271
|
+
threads_table_t *threads_table;
|
191
272
|
|
192
273
|
debug_check_started();
|
193
274
|
|
194
|
-
|
195
|
-
if(
|
275
|
+
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
276
|
+
if(!st_lookup(threads_table->tbl, thread, &context))
|
196
277
|
{
|
197
|
-
|
198
|
-
|
278
|
+
context = debug_context_create(thread);
|
279
|
+
st_insert(threads_table->tbl, thread, context);
|
199
280
|
}
|
200
281
|
return context;
|
201
282
|
}
|
@@ -241,13 +322,9 @@ save_current_position(VALUE context)
|
|
241
322
|
|
242
323
|
debug_context->last_file = debug_frame->file;
|
243
324
|
debug_context->last_line = debug_frame->line;
|
244
|
-
debug_context
|
325
|
+
CTX_FL_UNSET(debug_context, CTX_FL_MOVED);
|
245
326
|
}
|
246
327
|
|
247
|
-
#define did_moved() (debug_context->last_line != line || \
|
248
|
-
debug_context->last_file == Qnil || \
|
249
|
-
rb_str_cmp(debug_context->last_file, file) != 0)
|
250
|
-
|
251
328
|
static VALUE
|
252
329
|
call_at_line_unprotected(VALUE args)
|
253
330
|
{
|
@@ -263,7 +340,6 @@ call_at_line(VALUE context, int thnum, VALUE binding, VALUE file, VALUE line)
|
|
263
340
|
|
264
341
|
last_debugged_thnum = thnum;
|
265
342
|
save_current_position(context);
|
266
|
-
debug_suspend(mDebugger);
|
267
343
|
|
268
344
|
args = rb_ary_new3(4, context, file, line, binding);
|
269
345
|
return rb_protect(call_at_line_unprotected, args, 0);
|
@@ -330,7 +406,7 @@ check_breakpoints(debug_context_t *debug_context, VALUE file, VALUE klass, VALUE
|
|
330
406
|
|
331
407
|
if(RARRAY(breakpoints)->len == 0)
|
332
408
|
return -1;
|
333
|
-
if(!debug_context
|
409
|
+
if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
|
334
410
|
return -1;
|
335
411
|
|
336
412
|
for(i = 0; i < RARRAY(breakpoints)->len; i++)
|
@@ -366,23 +442,6 @@ create_binding(VALUE self)
|
|
366
442
|
return f_binding(self);
|
367
443
|
}
|
368
444
|
|
369
|
-
static void
|
370
|
-
check_suspend(debug_context_t *debug_context)
|
371
|
-
{
|
372
|
-
if(rb_thread_critical == Qtrue)
|
373
|
-
return;
|
374
|
-
while(1)
|
375
|
-
{
|
376
|
-
rb_thread_critical = Qtrue;
|
377
|
-
if(!debug_context->suspend)
|
378
|
-
break;
|
379
|
-
rb_ary_push(waiting, rb_thread_current());
|
380
|
-
debug_context->suspend = 0;
|
381
|
-
rb_thread_stop();
|
382
|
-
}
|
383
|
-
rb_thread_critical = Qfalse;
|
384
|
-
}
|
385
|
-
|
386
445
|
static VALUE
|
387
446
|
get_breakpoint_at(int index)
|
388
447
|
{
|
@@ -422,25 +481,45 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
422
481
|
if(!node) return;
|
423
482
|
|
424
483
|
thread = rb_thread_current();
|
425
|
-
|
484
|
+
context = thread_context_lookup(thread);
|
485
|
+
Data_Get_Struct(context, debug_context_t, debug_context);
|
486
|
+
|
487
|
+
/* return if thread is marked as 'ignored'.
|
488
|
+
debugger's threads are marked this way
|
489
|
+
*/
|
490
|
+
if(CTX_FL_TEST(debug_context, CTX_FL_IGNORE)) return;
|
491
|
+
|
492
|
+
while(1)
|
426
493
|
{
|
427
|
-
|
428
|
-
|
494
|
+
/* halt execution of the current thread if the debugger
|
495
|
+
is activated in another
|
496
|
+
*/
|
497
|
+
while(locker != Qnil && locker != thread)
|
498
|
+
{
|
499
|
+
add_to_locked(thread);
|
500
|
+
rb_thread_stop();
|
501
|
+
}
|
502
|
+
|
503
|
+
/* stop the current thread if it's marked as suspended */
|
504
|
+
if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
505
|
+
rb_thread_stop();
|
506
|
+
else break;
|
429
507
|
}
|
430
508
|
|
509
|
+
/* return if the current thread is the locker */
|
431
510
|
if(locker != Qnil) return;
|
511
|
+
|
512
|
+
/* only the current thread can proceed */
|
513
|
+
locker = thread;
|
432
514
|
|
433
|
-
|
434
|
-
|
435
|
-
context = thread_context_lookup(thread);
|
436
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
437
|
-
check_suspend(debug_context);
|
515
|
+
/* ignore a skipped section of code */
|
516
|
+
if(CTX_FL_TEST(debug_context, CTX_FL_SKIPPED)) goto cleanup;
|
438
517
|
|
439
518
|
file = rb_str_new2(node->nd_file);
|
440
519
|
line = INT2FIX(nd_line(node));
|
441
520
|
|
442
|
-
if(
|
443
|
-
debug_context
|
521
|
+
if(DID_MOVED)
|
522
|
+
CTX_FL_SET(debug_context, CTX_FL_MOVED);
|
444
523
|
|
445
524
|
switch(event)
|
446
525
|
{
|
@@ -448,7 +527,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
448
527
|
{
|
449
528
|
set_frame_source(debug_context, file, line);
|
450
529
|
|
451
|
-
if(RTEST(tracing) || debug_context
|
530
|
+
if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING))
|
452
531
|
{
|
453
532
|
rb_funcall(context, idAtTracing, 2, file, line);
|
454
533
|
}
|
@@ -460,7 +539,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
460
539
|
if(debug_context->stop_next < 0)
|
461
540
|
debug_context->stop_next = -1;
|
462
541
|
/* we check that we actualy moved to another line */
|
463
|
-
if(
|
542
|
+
if(DID_MOVED)
|
464
543
|
{
|
465
544
|
debug_context->stop_line--;
|
466
545
|
}
|
@@ -574,17 +653,21 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
574
653
|
}
|
575
654
|
}
|
576
655
|
|
656
|
+
cleanup:
|
657
|
+
|
658
|
+
/* release a lock */
|
577
659
|
locker = Qnil;
|
660
|
+
/* let the next thread to run */
|
578
661
|
thread = remove_from_locked();
|
579
662
|
if(thread != Qnil)
|
580
663
|
rb_thread_run(thread);
|
581
664
|
}
|
582
665
|
|
583
666
|
static VALUE
|
584
|
-
debug_stop_i(VALUE
|
667
|
+
debug_stop_i(VALUE self)
|
585
668
|
{
|
586
669
|
if(IS_STARTED)
|
587
|
-
debug_stop(
|
670
|
+
debug_stop(self);
|
588
671
|
return Qnil;
|
589
672
|
}
|
590
673
|
|
@@ -595,8 +678,8 @@ debug_stop_i(VALUE value)
|
|
595
678
|
*
|
596
679
|
* This method activates the debugger.
|
597
680
|
* If it's called without a block it returns +true+, unless debugger was already started.
|
598
|
-
* If a block is given, it starts debugger and yields to block.
|
599
|
-
* with Debugger.stop method.
|
681
|
+
* If a block is given, it starts debugger and yields to block. When the block is finished
|
682
|
+
* executing it stops the debugger with Debugger.stop method.
|
600
683
|
*
|
601
684
|
* <i>Note that if you want to stop debugger, you must call Debugger.stop as many time as you
|
602
685
|
* called Debugger.start method.</i>
|
@@ -604,22 +687,24 @@ debug_stop_i(VALUE value)
|
|
604
687
|
static VALUE
|
605
688
|
debug_start(VALUE self)
|
606
689
|
{
|
690
|
+
VALUE result;
|
607
691
|
start_count++;
|
608
692
|
|
609
693
|
if(IS_STARTED)
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
694
|
+
result = Qfalse;
|
695
|
+
else
|
696
|
+
{
|
697
|
+
breakpoints = rb_ary_new();
|
698
|
+
locker = Qnil;
|
699
|
+
threads_tbl = threads_table_create();
|
616
700
|
|
617
|
-
|
701
|
+
rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL);
|
702
|
+
result = Qtrue;
|
703
|
+
}
|
618
704
|
|
619
705
|
if(rb_block_given_p())
|
620
706
|
return rb_ensure(rb_yield, Qnil, debug_stop_i, self);
|
621
|
-
|
622
|
-
return Qtrue;
|
707
|
+
return result;
|
623
708
|
}
|
624
709
|
|
625
710
|
/*
|
@@ -643,7 +728,6 @@ debug_stop(VALUE self)
|
|
643
728
|
|
644
729
|
rb_remove_event_hook(debug_event_hook);
|
645
730
|
|
646
|
-
waiting = Qnil;
|
647
731
|
locker = Qnil;
|
648
732
|
breakpoints = Qnil;
|
649
733
|
threads_tbl = Qnil;
|
@@ -767,10 +851,13 @@ static VALUE
|
|
767
851
|
debug_last_interrupted(VALUE self)
|
768
852
|
{
|
769
853
|
VALUE result = Qnil;
|
854
|
+
threads_table_t *threads_table;
|
770
855
|
|
771
856
|
debug_check_started();
|
772
857
|
|
773
|
-
|
858
|
+
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
859
|
+
|
860
|
+
st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result);
|
774
861
|
return result;
|
775
862
|
}
|
776
863
|
|
@@ -806,6 +893,7 @@ debug_contexts(VALUE self)
|
|
806
893
|
volatile VALUE list;
|
807
894
|
volatile VALUE new_list;
|
808
895
|
VALUE thread, context;
|
896
|
+
threads_table_t *threads_table;
|
809
897
|
debug_context_t *debug_context;
|
810
898
|
int i;
|
811
899
|
|
@@ -819,15 +907,13 @@ debug_contexts(VALUE self)
|
|
819
907
|
context = thread_context_lookup(thread);
|
820
908
|
rb_ary_push(new_list, context);
|
821
909
|
}
|
822
|
-
|
823
|
-
|
824
|
-
*/
|
825
|
-
rb_funcall(threads_tbl, idClear, 0);
|
910
|
+
threads_table_clear(threads_tbl);
|
911
|
+
Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
|
826
912
|
for(i = 0; i < RARRAY(new_list)->len; i++)
|
827
913
|
{
|
828
914
|
context = rb_ary_entry(new_list, i);
|
829
915
|
Data_Get_Struct(context, debug_context_t, debug_context);
|
830
|
-
|
916
|
+
st_insert(threads_table->tbl, debug_context->thread, context);
|
831
917
|
}
|
832
918
|
|
833
919
|
return new_list;
|
@@ -861,7 +947,7 @@ debug_suspend(VALUE self)
|
|
861
947
|
if(current == context)
|
862
948
|
continue;
|
863
949
|
Data_Get_Struct(context, debug_context_t, debug_context);
|
864
|
-
debug_context
|
950
|
+
CTX_FL_SET(debug_context, CTX_FL_SUSPEND);
|
865
951
|
}
|
866
952
|
rb_thread_critical = saved_crit;
|
867
953
|
|
@@ -882,7 +968,6 @@ debug_resume(VALUE self)
|
|
882
968
|
{
|
883
969
|
VALUE current, context;
|
884
970
|
VALUE saved_crit;
|
885
|
-
VALUE thread;
|
886
971
|
VALUE context_list;
|
887
972
|
debug_context_t *debug_context;
|
888
973
|
int i;
|
@@ -900,14 +985,12 @@ debug_resume(VALUE self)
|
|
900
985
|
if(current == context)
|
901
986
|
continue;
|
902
987
|
Data_Get_Struct(context, debug_context_t, debug_context);
|
903
|
-
debug_context
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
rb_thread_run(thread);
|
988
|
+
if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
989
|
+
{
|
990
|
+
CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND);
|
991
|
+
rb_thread_run(debug_context->thread);
|
992
|
+
}
|
909
993
|
}
|
910
|
-
rb_ary_clear(waiting);
|
911
994
|
rb_thread_critical = saved_crit;
|
912
995
|
|
913
996
|
rb_thread_schedule();
|
@@ -965,9 +1048,17 @@ debug_debug_load(VALUE self, VALUE file)
|
|
965
1048
|
}
|
966
1049
|
|
967
1050
|
static VALUE
|
968
|
-
|
1051
|
+
set_current_skipped_status(VALUE status)
|
969
1052
|
{
|
970
|
-
|
1053
|
+
VALUE context;
|
1054
|
+
debug_context_t *debug_context;
|
1055
|
+
|
1056
|
+
context = debug_current_context(Qnil);
|
1057
|
+
Data_Get_Struct(context, debug_context_t, debug_context);
|
1058
|
+
if(status)
|
1059
|
+
CTX_FL_SET(debug_context, CTX_FL_SKIPPED);
|
1060
|
+
else
|
1061
|
+
CTX_FL_UNSET(debug_context, CTX_FL_SKIPPED);
|
971
1062
|
return Qnil;
|
972
1063
|
}
|
973
1064
|
|
@@ -985,8 +1076,8 @@ debug_skip(VALUE self)
|
|
985
1076
|
}
|
986
1077
|
if(!IS_STARTED)
|
987
1078
|
return rb_yield(Qnil);
|
988
|
-
|
989
|
-
return rb_ensure(rb_yield, Qnil,
|
1079
|
+
set_current_skipped_status(Qtrue);
|
1080
|
+
return rb_ensure(rb_yield, Qnil, set_current_skipped_status, Qfalse);
|
990
1081
|
}
|
991
1082
|
|
992
1083
|
static VALUE
|
@@ -1004,8 +1095,8 @@ debug_at_exit_i(VALUE proc)
|
|
1004
1095
|
}
|
1005
1096
|
else
|
1006
1097
|
{
|
1007
|
-
|
1008
|
-
rb_ensure(debug_at_exit_c, proc,
|
1098
|
+
set_current_skipped_status(Qtrue);
|
1099
|
+
rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse);
|
1009
1100
|
}
|
1010
1101
|
}
|
1011
1102
|
|
@@ -1151,37 +1242,42 @@ context_thnum(VALUE self)
|
|
1151
1242
|
|
1152
1243
|
/*
|
1153
1244
|
* call-seq:
|
1154
|
-
* context.
|
1245
|
+
* context.suspend -> nil
|
1155
1246
|
*
|
1156
1247
|
* Suspends the thread when it is running.
|
1157
1248
|
*/
|
1158
1249
|
static VALUE
|
1159
|
-
|
1250
|
+
context_suspend(VALUE self)
|
1160
1251
|
{
|
1161
1252
|
debug_context_t *debug_context;
|
1162
1253
|
|
1163
1254
|
debug_check_started();
|
1164
1255
|
|
1165
1256
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1166
|
-
debug_context
|
1257
|
+
if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
1258
|
+
rb_raise(rb_eRuntimeError, "Already suspended.");
|
1259
|
+
CTX_FL_SET(debug_context, CTX_FL_SUSPEND);
|
1167
1260
|
return Qnil;
|
1168
1261
|
}
|
1169
1262
|
|
1170
1263
|
/*
|
1171
1264
|
* call-seq:
|
1172
|
-
* context.
|
1265
|
+
* context.resume -> nil
|
1173
1266
|
*
|
1174
|
-
*
|
1267
|
+
* Resumes the thread from the suspended mode.
|
1175
1268
|
*/
|
1176
1269
|
static VALUE
|
1177
|
-
|
1270
|
+
context_resume(VALUE self)
|
1178
1271
|
{
|
1179
1272
|
debug_context_t *debug_context;
|
1180
1273
|
|
1181
1274
|
debug_check_started();
|
1182
1275
|
|
1183
1276
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1184
|
-
debug_context
|
1277
|
+
if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
|
1278
|
+
rb_raise(rb_eRuntimeError, "Thread is not suspended.");
|
1279
|
+
CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND);
|
1280
|
+
rb_thread_run(debug_context->thread);
|
1185
1281
|
return Qnil;
|
1186
1282
|
}
|
1187
1283
|
|
@@ -1199,7 +1295,7 @@ context_tracing(VALUE self)
|
|
1199
1295
|
debug_check_started();
|
1200
1296
|
|
1201
1297
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1202
|
-
return debug_context
|
1298
|
+
return CTX_FL_TEST(debug_context, CTX_FL_TRACING) ? Qtrue : Qfalse;
|
1203
1299
|
}
|
1204
1300
|
|
1205
1301
|
/*
|
@@ -1216,7 +1312,48 @@ context_set_tracing(VALUE self, VALUE value)
|
|
1216
1312
|
debug_check_started();
|
1217
1313
|
|
1218
1314
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1219
|
-
|
1315
|
+
if(RTEST(value))
|
1316
|
+
CTX_FL_SET(debug_context, CTX_FL_TRACING);
|
1317
|
+
else
|
1318
|
+
CTX_FL_UNSET(debug_context, CTX_FL_TRACING);
|
1319
|
+
return value;
|
1320
|
+
}
|
1321
|
+
|
1322
|
+
/*
|
1323
|
+
* call-seq:
|
1324
|
+
* context.ignore -> bool
|
1325
|
+
*
|
1326
|
+
* Returns the ignore flag for the current context.
|
1327
|
+
*/
|
1328
|
+
static VALUE
|
1329
|
+
context_ignore(VALUE self)
|
1330
|
+
{
|
1331
|
+
debug_context_t *debug_context;
|
1332
|
+
|
1333
|
+
debug_check_started();
|
1334
|
+
|
1335
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1336
|
+
return CTX_FL_TEST(debug_context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
/*
|
1340
|
+
* call-seq:
|
1341
|
+
* context.tracking = bool
|
1342
|
+
*
|
1343
|
+
* Controls the ignore flag for this context.
|
1344
|
+
*/
|
1345
|
+
static VALUE
|
1346
|
+
context_set_ignore(VALUE self, VALUE value)
|
1347
|
+
{
|
1348
|
+
debug_context_t *debug_context;
|
1349
|
+
|
1350
|
+
debug_check_started();
|
1351
|
+
|
1352
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1353
|
+
if(RTEST(value))
|
1354
|
+
CTX_FL_SET(debug_context, CTX_FL_IGNORE);
|
1355
|
+
else
|
1356
|
+
CTX_FL_UNSET(debug_context, CTX_FL_IGNORE);
|
1220
1357
|
return value;
|
1221
1358
|
}
|
1222
1359
|
|
@@ -1344,10 +1481,12 @@ Init_context()
|
|
1344
1481
|
rb_define_method(cContext, "frames", context_frames, 0);
|
1345
1482
|
rb_define_method(cContext, "thread", context_thread, 0);
|
1346
1483
|
rb_define_method(cContext, "thnum", context_thnum, 0);
|
1347
|
-
rb_define_method(cContext, "
|
1348
|
-
rb_define_method(cContext, "
|
1484
|
+
rb_define_method(cContext, "suspend", context_suspend, 0);
|
1485
|
+
rb_define_method(cContext, "resume", context_resume, 0);
|
1349
1486
|
rb_define_method(cContext, "tracing", context_tracing, 0);
|
1350
1487
|
rb_define_method(cContext, "tracing=", context_set_tracing, 1);
|
1488
|
+
rb_define_method(cContext, "ignore", context_ignore, 0);
|
1489
|
+
rb_define_method(cContext, "ignore=", context_set_ignore, 1);
|
1351
1490
|
}
|
1352
1491
|
|
1353
1492
|
/*
|
@@ -1418,6 +1557,8 @@ Init_ruby_debug()
|
|
1418
1557
|
rb_define_module_function(mDebugger, "skip", debug_skip, 0);
|
1419
1558
|
rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
|
1420
1559
|
|
1560
|
+
cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
|
1561
|
+
|
1421
1562
|
Init_context();
|
1422
1563
|
Init_frame();
|
1423
1564
|
Init_breakpoint();
|
@@ -1439,7 +1580,6 @@ Init_ruby_debug()
|
|
1439
1580
|
rb_global_variable(&threads_tbl);
|
1440
1581
|
rb_global_variable(&breakpoints);
|
1441
1582
|
rb_global_variable(&catchpoint);
|
1442
|
-
rb_global_variable(&waiting);
|
1443
1583
|
rb_global_variable(&locker);
|
1444
1584
|
rb_global_variable(&file_separator);
|
1445
1585
|
rb_global_variable(&alt_file_separator);
|
data/lib/ruby-debug.rb
CHANGED
@@ -2,13 +2,11 @@ require 'pp'
|
|
2
2
|
require 'stringio'
|
3
3
|
require 'thread'
|
4
4
|
require 'ruby_debug.so'
|
5
|
-
require 'ruby-debug/lock'
|
6
5
|
require 'ruby-debug/processor'
|
7
6
|
|
8
7
|
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
9
8
|
|
10
9
|
module Debugger
|
11
|
-
MUTEX = Lock.new
|
12
10
|
PORT = 8989
|
13
11
|
|
14
12
|
@processor = CommandProcessor.new
|
@@ -37,10 +35,7 @@ module Debugger
|
|
37
35
|
end
|
38
36
|
|
39
37
|
def at_line(file, line, binding)
|
40
|
-
MUTEX.lock
|
41
38
|
processor.at_line(self, file, line, binding)
|
42
|
-
MUTEX.unlock
|
43
|
-
Debugger.resume
|
44
39
|
end
|
45
40
|
end
|
46
41
|
|
@@ -97,6 +92,7 @@ module Debugger
|
|
97
92
|
end
|
98
93
|
|
99
94
|
@control_thread = Thread.start do
|
95
|
+
current_context.ignore = true
|
100
96
|
server = TCPServer.new(host, ctrl_port)
|
101
97
|
while (session = server.accept)
|
102
98
|
interface = RemoteInterface.new(session)
|
@@ -109,6 +105,7 @@ module Debugger
|
|
109
105
|
proceed = ConditionVariable.new
|
110
106
|
|
111
107
|
@thread = Thread.start do
|
108
|
+
current_context.ignore = true
|
112
109
|
server = TCPServer.new(host, cmd_port)
|
113
110
|
while (session = server.accept)
|
114
111
|
self.interface = RemoteInterface.new(session)
|
@@ -100,7 +100,7 @@ module Debugger
|
|
100
100
|
print "Already stopped.\n"
|
101
101
|
else
|
102
102
|
display_context(c)
|
103
|
-
c.
|
103
|
+
c.suspend
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
@@ -160,7 +160,7 @@ module Debugger
|
|
160
160
|
print "Already running."
|
161
161
|
else
|
162
162
|
display_context(c)
|
163
|
-
c.
|
163
|
+
c.resume
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
data/lib/ruby_debug.so
CHANGED
Binary file
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-debug
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.4.
|
7
|
-
date: 2006-10-
|
6
|
+
version: 0.4.4
|
7
|
+
date: 2006-10-15 18:27:41 -04:00
|
8
8
|
summary: Fast Ruby debugger
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -38,7 +38,6 @@ files:
|
|
38
38
|
- lib/ruby-debug/command.rb
|
39
39
|
- lib/ruby-debug/commands
|
40
40
|
- lib/ruby-debug/interface.rb
|
41
|
-
- lib/ruby-debug/lock.rb
|
42
41
|
- lib/ruby-debug/processor.rb
|
43
42
|
- lib/ruby-debug/commands/breakpoints.rb
|
44
43
|
- lib/ruby-debug/commands/catchpoint.rb
|
data/lib/ruby-debug/lock.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module Debugger
|
2
|
-
class Lock # :nodoc:
|
3
|
-
def initialize
|
4
|
-
@locker = nil
|
5
|
-
@waiting = []
|
6
|
-
@locked = false;
|
7
|
-
end
|
8
|
-
|
9
|
-
def locked?
|
10
|
-
@locked
|
11
|
-
end
|
12
|
-
|
13
|
-
def lock
|
14
|
-
return if Thread.critical
|
15
|
-
return if @locker == Thread.current
|
16
|
-
while (Thread.critical = true; @locked)
|
17
|
-
@waiting.push Thread.current
|
18
|
-
Thread.stop
|
19
|
-
end
|
20
|
-
@locked = true
|
21
|
-
@locker = Thread.current
|
22
|
-
Thread.critical = false
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def unlock
|
27
|
-
return if Thread.critical
|
28
|
-
return unless @locked
|
29
|
-
unless @locker == Thread.current
|
30
|
-
raise RuntimeError, "unlocked by other"
|
31
|
-
end
|
32
|
-
Thread.critical = true
|
33
|
-
t = @waiting.shift
|
34
|
-
@locked = false
|
35
|
-
@locker = nil
|
36
|
-
Thread.critical = false
|
37
|
-
t.run if t
|
38
|
-
self
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|