empathy 0.0.1.RC0

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 (112) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.rdoc +135 -0
  5. data/Rakefile +33 -0
  6. data/TESTING.rdoc +11 -0
  7. data/empathy.gemspec +23 -0
  8. data/empathy.mspec +34 -0
  9. data/lib/empathy.rb +162 -0
  10. data/lib/empathy/em/condition_variable.rb +57 -0
  11. data/lib/empathy/em/mutex.rb +70 -0
  12. data/lib/empathy/em/queue.rb +84 -0
  13. data/lib/empathy/em/thread.rb +363 -0
  14. data/lib/empathy/object.rb +19 -0
  15. data/lib/empathy/thread.rb +8 -0
  16. data/lib/empathy/version.rb +3 -0
  17. data/mspec/lib/mspec/empathy.rb +19 -0
  18. data/mspec/lib/mspec/guards/empathy.rb +10 -0
  19. data/rubyspec/core/kernel/fixtures/__method__.rb +25 -0
  20. data/rubyspec/core/kernel/fixtures/autoload_b.rb +5 -0
  21. data/rubyspec/core/kernel/fixtures/autoload_c.rb +5 -0
  22. data/rubyspec/core/kernel/fixtures/autoload_d.rb +5 -0
  23. data/rubyspec/core/kernel/fixtures/caller_fixture1.rb +42 -0
  24. data/rubyspec/core/kernel/fixtures/caller_fixture2.rb +26 -0
  25. data/rubyspec/core/kernel/fixtures/chomp.rb +4 -0
  26. data/rubyspec/core/kernel/fixtures/chomp_f.rb +4 -0
  27. data/rubyspec/core/kernel/fixtures/chop.rb +4 -0
  28. data/rubyspec/core/kernel/fixtures/chop_f.rb +4 -0
  29. data/rubyspec/core/kernel/fixtures/classes.rb +410 -0
  30. data/rubyspec/core/kernel/fixtures/eval_locals.rb +6 -0
  31. data/rubyspec/core/kernel/fixtures/eval_return_with_lambda.rb +12 -0
  32. data/rubyspec/core/kernel/fixtures/eval_return_without_lambda.rb +14 -0
  33. data/rubyspec/core/kernel/fixtures/test.rb +362 -0
  34. data/rubyspec/core/kernel/sleep_spec.rb +43 -0
  35. data/rubyspec/core/mutex/lock_spec.rb +8 -0
  36. data/rubyspec/core/mutex/locked_spec.rb +8 -0
  37. data/rubyspec/core/mutex/sleep_spec.rb +56 -0
  38. data/rubyspec/core/mutex/synchronize_spec.rb +8 -0
  39. data/rubyspec/core/mutex/try_lock_spec.rb +8 -0
  40. data/rubyspec/core/mutex/unlock_spec.rb +8 -0
  41. data/rubyspec/core/thread/abort_on_exception_spec.rb +126 -0
  42. data/rubyspec/core/thread/add_trace_func_spec.rb +7 -0
  43. data/rubyspec/core/thread/alive_spec.rb +60 -0
  44. data/rubyspec/core/thread/allocate_spec.rb +9 -0
  45. data/rubyspec/core/thread/backtrace_spec.rb +7 -0
  46. data/rubyspec/core/thread/critical_spec.rb +96 -0
  47. data/rubyspec/core/thread/current_spec.rb +15 -0
  48. data/rubyspec/core/thread/element_reference_spec.rb +53 -0
  49. data/rubyspec/core/thread/element_set_spec.rb +46 -0
  50. data/rubyspec/core/thread/exclusive_spec.rb +20 -0
  51. data/rubyspec/core/thread/exit_spec.rb +21 -0
  52. data/rubyspec/core/thread/fixtures/classes.rb +291 -0
  53. data/rubyspec/core/thread/fork_spec.rb +9 -0
  54. data/rubyspec/core/thread/group_spec.rb +5 -0
  55. data/rubyspec/core/thread/initialize_spec.rb +26 -0
  56. data/rubyspec/core/thread/inspect_spec.rb +48 -0
  57. data/rubyspec/core/thread/join_spec.rb +63 -0
  58. data/rubyspec/core/thread/key_spec.rb +64 -0
  59. data/rubyspec/core/thread/keys_spec.rb +47 -0
  60. data/rubyspec/core/thread/kill_spec.rb +21 -0
  61. data/rubyspec/core/thread/list_spec.rb +38 -0
  62. data/rubyspec/core/thread/main_spec.rb +10 -0
  63. data/rubyspec/core/thread/new_spec.rb +56 -0
  64. data/rubyspec/core/thread/pass_spec.rb +8 -0
  65. data/rubyspec/core/thread/priority_spec.rb +9 -0
  66. data/rubyspec/core/thread/raise_spec.rb +225 -0
  67. data/rubyspec/core/thread/run_spec.rb +9 -0
  68. data/rubyspec/core/thread/safe_level_spec.rb +6 -0
  69. data/rubyspec/core/thread/set_trace_func_spec.rb +7 -0
  70. data/rubyspec/core/thread/shared/exit.rb +173 -0
  71. data/rubyspec/core/thread/shared/start.rb +51 -0
  72. data/rubyspec/core/thread/shared/wakeup.rb +59 -0
  73. data/rubyspec/core/thread/start_spec.rb +9 -0
  74. data/rubyspec/core/thread/status_spec.rb +48 -0
  75. data/rubyspec/core/thread/stop_spec.rb +66 -0
  76. data/rubyspec/core/thread/terminate_spec.rb +11 -0
  77. data/rubyspec/core/thread/value_spec.rb +36 -0
  78. data/rubyspec/core/thread/wakeup_spec.rb +7 -0
  79. data/rubyspec/empathy_spec.rb +26 -0
  80. data/rubyspec/library/conditionvariable/broadcast_spec.rb +62 -0
  81. data/rubyspec/library/conditionvariable/signal_spec.rb +64 -0
  82. data/rubyspec/library/conditionvariable/wait_spec.rb +21 -0
  83. data/rubyspec/library/mutex/lock_spec.rb +10 -0
  84. data/rubyspec/library/mutex/locked_spec.rb +10 -0
  85. data/rubyspec/library/mutex/synchronize_spec.rb +10 -0
  86. data/rubyspec/library/mutex/try_lock_spec.rb +10 -0
  87. data/rubyspec/library/mutex/unlock_spec.rb +10 -0
  88. data/rubyspec/library/queue/append_spec.rb +7 -0
  89. data/rubyspec/library/queue/clear_spec.rb +15 -0
  90. data/rubyspec/library/queue/deq_spec.rb +7 -0
  91. data/rubyspec/library/queue/empty_spec.rb +15 -0
  92. data/rubyspec/library/queue/enq_spec.rb +7 -0
  93. data/rubyspec/library/queue/length_spec.rb +7 -0
  94. data/rubyspec/library/queue/num_waiting_spec.rb +19 -0
  95. data/rubyspec/library/queue/pop_spec.rb +7 -0
  96. data/rubyspec/library/queue/push_spec.rb +7 -0
  97. data/rubyspec/library/queue/shared/deque.rb +37 -0
  98. data/rubyspec/library/queue/shared/enque.rb +10 -0
  99. data/rubyspec/library/queue/shared/length.rb +9 -0
  100. data/rubyspec/library/queue/shift_spec.rb +7 -0
  101. data/rubyspec/library/queue/size_spec.rb +7 -0
  102. data/rubyspec/shared/kernel/raise.rb +68 -0
  103. data/rubyspec/shared/mutex/lock.rb +52 -0
  104. data/rubyspec/shared/mutex/locked.rb +31 -0
  105. data/rubyspec/shared/mutex/synchronize.rb +23 -0
  106. data/rubyspec/shared/mutex/try_lock.rb +30 -0
  107. data/rubyspec/shared/mutex/unlock.rb +35 -0
  108. data/rubyspec/spec_helper.rb +48 -0
  109. data/spec/empathy_spec.rb +129 -0
  110. data/spec/library_spec.rb +79 -0
  111. data/spec/spec_helper.rb +6 -0
  112. metadata +222 -0
@@ -0,0 +1,9 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ require File.expand_path('../shared/wakeup', __FILE__)
5
+
6
+ describe "Thread#run" do
7
+ it_behaves_like :thread_wakeup, :run
8
+ end
9
+
@@ -0,0 +1,6 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#safe_level" do
5
+ it "needs to be reviewed for spec completeness"
6
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ ruby_version_is "1.9" do
4
+ describe "Thread#set_trace_func" do
5
+ it "needs to be reviewed for spec completeness"
6
+ end
7
+ end
@@ -0,0 +1,173 @@
1
+ describe :thread_exit, :shared => true do
2
+ before(:each) do
3
+ ScratchPad.clear
4
+ end
5
+
6
+ it "kills sleeping thread" do
7
+ sleeping_thread = Thread.new do
8
+ sleep
9
+ ScratchPad.record :after_sleep
10
+ end
11
+ Thread.pass while sleeping_thread.status and sleeping_thread.status != "sleep"
12
+ sleeping_thread.send(@method)
13
+ sleeping_thread.join
14
+ ScratchPad.recorded.should == nil
15
+ end
16
+
17
+ it "kills current thread" do
18
+ thread = Thread.new do
19
+ Thread.current.send(@method)
20
+ ScratchPad.record :after_sleep
21
+ end
22
+ thread.join
23
+ ScratchPad.recorded.should == nil
24
+ end
25
+
26
+ it "runs ensure clause" do
27
+ thread = ThreadSpecs.dying_thread_ensures(@method) { ScratchPad.record :in_ensure_clause }
28
+ thread.join
29
+ ScratchPad.recorded.should == :in_ensure_clause
30
+ end
31
+
32
+ it "runs nested ensure clauses" do
33
+ ScratchPad.record []
34
+ outer = Thread.new do
35
+ begin
36
+ inner = Thread.new do
37
+ begin
38
+ sleep
39
+ ensure
40
+ ScratchPad << :inner_ensure_clause
41
+ end
42
+ end
43
+ sleep
44
+ ensure
45
+ ScratchPad << :outer_ensure_clause
46
+ Thread.pass while inner.status and inner.status != "sleep"
47
+ inner.send(@method)
48
+ inner.join
49
+ end
50
+ end
51
+ Thread.pass while outer.status and outer.status != "sleep"
52
+ outer.send(@method)
53
+ outer.join
54
+ ScratchPad.recorded.should include(:inner_ensure_clause)
55
+ ScratchPad.recorded.should include(:outer_ensure_clause)
56
+ end
57
+
58
+ it "does not set $!" do
59
+ thread = ThreadSpecs.dying_thread_ensures(@method) { ScratchPad.record $! }
60
+ thread.join
61
+ ScratchPad.recorded.should == nil
62
+ end
63
+
64
+ it "cannot be rescued" do
65
+ thread = Thread.new do
66
+ begin
67
+ Thread.current.send(@method)
68
+ rescue Exception
69
+ ScratchPad.record :in_rescue
70
+ end
71
+ ScratchPad.record :end_of_thread_block
72
+ end
73
+
74
+ thread.join
75
+ ScratchPad.recorded.should == nil
76
+ end
77
+
78
+ ruby_version_is "" ... "1.9" do
79
+ it "killing dying sleeping thread wakes up thread" do
80
+ t = ThreadSpecs.dying_thread_ensures { Thread.stop; ScratchPad.record :after_stop }
81
+ Thread.pass while t.status and t.status != "sleep"
82
+ t.send(@method)
83
+ t.join
84
+ ScratchPad.recorded.should == :after_stop
85
+ end
86
+ end
87
+
88
+ # This spec is a mess. It fails randomly, it hangs on MRI, it needs to be removed
89
+ quarantine! do
90
+ it "killing dying running does nothing" do
91
+ in_ensure_clause = false
92
+ exit_loop = true
93
+ t = ThreadSpecs.dying_thread_ensures do
94
+ in_ensure_clause = true
95
+ loop { if exit_loop then break end }
96
+ ScratchPad.record :after_stop
97
+ end
98
+
99
+ Thread.pass until in_ensure_clause == true
100
+ 10.times { t.send(@method); Thread.pass }
101
+ exit_loop = true
102
+ t.join
103
+ ScratchPad.recorded.should == :after_stop
104
+ end
105
+ end
106
+
107
+ quarantine! do
108
+
109
+ it "propogates inner exception to Thread.join if there is an outer ensure clause" do
110
+ thread = ThreadSpecs.dying_thread_with_outer_ensure(@method) { }
111
+ lambda { thread.join }.should raise_error(RuntimeError, "In dying thread")
112
+ end
113
+
114
+ it "runs all outer ensure clauses even if inner ensure clause raises exception" do
115
+ thread = ThreadSpecs.join_dying_thread_with_outer_ensure(@method) { ScratchPad.record :in_outer_ensure_clause }
116
+ ScratchPad.recorded.should == :in_outer_ensure_clause
117
+ end
118
+
119
+ it "sets $! in outer ensure clause if inner ensure clause raises exception" do
120
+ thread = ThreadSpecs.join_dying_thread_with_outer_ensure(@method) { ScratchPad.record $! }
121
+ ScratchPad.recorded.to_s.should == "In dying thread"
122
+ end
123
+ end
124
+
125
+ it "can be rescued by outer rescue clause when inner ensure clause raises exception" do
126
+ thread = Thread.new do
127
+ begin
128
+ begin
129
+ Thread.current.send(@method)
130
+ ensure
131
+ raise "In dying thread"
132
+ end
133
+ rescue Exception
134
+ ScratchPad.record $!
135
+ end
136
+ :end_of_thread_block
137
+ end
138
+
139
+ thread.value.should == :end_of_thread_block
140
+ ScratchPad.recorded.to_s.should == "In dying thread"
141
+ end
142
+
143
+ it "is deferred if ensure clause does Thread.stop" do
144
+ ThreadSpecs.wakeup_dying_sleeping_thread(@method) { Thread.stop; ScratchPad.record :after_sleep }
145
+ ScratchPad.recorded.should == :after_sleep
146
+ end
147
+
148
+ # Hangs on 1.8.6.114 OS X, possibly also on Linux
149
+ # FIX: There is no such thing as not_compliant_on(:ruby)!!!
150
+ quarantine! do
151
+ not_compliant_on(:ruby) do # Doing a sleep in the ensure block hangs the process
152
+ it "is deferred if ensure clause sleeps" do
153
+ ThreadSpecs.wakeup_dying_sleeping_thread(@method) { sleep; ScratchPad.record :after_sleep }
154
+ ScratchPad.recorded.should == :after_sleep
155
+ end
156
+ end
157
+ end
158
+
159
+ # This case occurred in JRuby where native threads are used to provide
160
+ # the same behavior as MRI green threads. Key to this issue was the fact
161
+ # that the thread which called #exit in its block was also being explicitly
162
+ # sent #join from outside the thread. The 100.times provides a certain
163
+ # probability that the deadlock will occur. It was sufficient to reliably
164
+ # reproduce the deadlock in JRuby.
165
+ it "does not deadlock when called from within the thread while being joined from without" do
166
+ 100.times do
167
+ t = Thread.new { Thread.stop; Thread.current.send(@method) }
168
+ Thread.pass while t.status and t.status != "sleep"
169
+ t.wakeup.should == t
170
+ t.join.should == t
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,51 @@
1
+ describe :thread_start, :shared => true do
2
+ before(:each) do
3
+ ScratchPad.clear
4
+ end
5
+
6
+ ruby_version_is '' ... '1.9' do
7
+ it "raises a ThreadError if not passed a block" do
8
+ lambda {
9
+ Thread.send(@method)
10
+ }.should raise_error(ThreadError)
11
+ end
12
+ end
13
+
14
+ ruby_version_is '1.9' do
15
+ it "raises a ArgumentError if not passed a block" do
16
+ lambda {
17
+ Thread.send(@method)
18
+ }.should raise_error(ArgumentError)
19
+ end
20
+ end
21
+
22
+ it "spawns a new Thread running the block" do
23
+ run = false
24
+ t = Thread.send(@method) { run = true }
25
+ t.should be_kind_of(Thread)
26
+ t.join
27
+
28
+ run.should be_true
29
+ end
30
+
31
+ it "respects Thread subclasses" do
32
+ c = Class.new(Thread)
33
+ t = c.send(@method) { }
34
+ t.should be_kind_of(c)
35
+
36
+ t.join
37
+ end
38
+
39
+ it "does not call #initialize" do
40
+ c = Class.new(Thread) do
41
+ def initialize
42
+ ScratchPad.record :bad
43
+ end
44
+ end
45
+
46
+ t = c.send(@method) { }
47
+ t.join
48
+
49
+ ScratchPad.recorded.should == nil
50
+ end
51
+ end
@@ -0,0 +1,59 @@
1
+ describe :thread_wakeup, :shared => true do
2
+ it "can interrupt Kernel#sleep" do
3
+ exit_loop = false
4
+ after_sleep1 = false
5
+ after_sleep2 = false
6
+
7
+ t = Thread.new do
8
+ while true
9
+ break if exit_loop == true
10
+ end
11
+
12
+ sleep
13
+ after_sleep1 = true
14
+
15
+ sleep
16
+ after_sleep2 = true
17
+ end
18
+
19
+ 10.times { t.send(@method); Thread.pass }
20
+ t.status.should_not == "sleep"
21
+
22
+ exit_loop = true
23
+
24
+ 10.times { sleep 0.1 if t.status and t.status != "sleep" }
25
+ after_sleep1.should == false # t should be blocked on the first sleep
26
+ t.send(@method)
27
+
28
+ 10.times { sleep 0.1 if after_sleep1 != true }
29
+ 10.times { sleep 0.1 if t.status and t.status != "sleep" }
30
+ after_sleep2.should == false # t should be blocked on the second sleep
31
+ t.send(@method)
32
+
33
+ t.join
34
+ end
35
+
36
+ it "does not result in a deadlock" do
37
+ t = Thread.new do
38
+ 1000.times {Thread.stop }
39
+ end
40
+
41
+ while(t.status != false) do
42
+ begin
43
+ t.send(@method)
44
+ rescue ThreadError
45
+ # The thread might die right after.
46
+ t.status.should == false
47
+ end
48
+ Thread.pass
49
+ end
50
+
51
+ 1.should == 1 # test succeeds if we reach here
52
+ end
53
+
54
+ it "raises a ThreadError when trying to wake up a dead thread" do
55
+ t = Thread.new { 1 }
56
+ t.join
57
+ lambda { t.wakeup }.should raise_error(ThreadError)
58
+ end
59
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+ require File.expand_path('../shared/start', __FILE__)
4
+
5
+ describe "Thread.start" do
6
+ describe "Thread.start" do
7
+ it_behaves_like :thread_start, :start
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#status" do
5
+ it "can check it's own status" do
6
+ ThreadSpecs.status_of_current_thread.status.should == 'run'
7
+ end
8
+
9
+ it "describes a running thread" do
10
+ ThreadSpecs.status_of_running_thread.status.should == 'run'
11
+ end
12
+
13
+ it "describes a sleeping thread" do
14
+ ThreadSpecs.status_of_sleeping_thread.status.should == 'sleep'
15
+ end
16
+
17
+ it "describes a blocked thread" do
18
+ ThreadSpecs.status_of_blocked_thread.status.should == 'sleep'
19
+ end
20
+
21
+ it "describes a completed thread" do
22
+ ThreadSpecs.status_of_completed_thread.status.should == false
23
+ end
24
+
25
+ it "describes a killed thread" do
26
+ ThreadSpecs.status_of_killed_thread.status.should == false
27
+ end
28
+
29
+ it "describes a thread with an uncaught exception" do
30
+ ThreadSpecs.status_of_thread_with_uncaught_exception.status.should == nil
31
+ end
32
+
33
+ ruby_version_is ""..."1.9" do
34
+ it "describes a dying running thread" do
35
+ ThreadSpecs.status_of_dying_running_thread.status.should == 'aborting'
36
+ end
37
+ end
38
+
39
+ it "describes a dying sleeping thread" do
40
+ ThreadSpecs.status_of_dying_sleeping_thread.status.should == 'sleep'
41
+ end
42
+
43
+ quarantine! do
44
+ it "reports aborting on a killed thread" do
45
+ ThreadSpecs.status_of_aborting_thread.status.should == 'aborting'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread.stop" do
5
+ it "causes the current thread to sleep indefinitely" do
6
+ t = Thread.new { Thread.stop; 5 }
7
+ Thread.pass while t.status and t.status != 'sleep'
8
+ t.status.should == 'sleep'
9
+ t.run
10
+ t.value.should == 5
11
+ end
12
+
13
+ ruby_version_is ""..."1.9" do
14
+ it "resets Thread.critical to false" do
15
+ t = Thread.new { Thread.critical = true; Thread.stop }
16
+ Thread.pass while t.status and t.status != 'sleep'
17
+ Thread.critical.should == false
18
+ t.run
19
+ t.join
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "Thread#stop?" do
25
+ it "can check it's own status" do
26
+ ThreadSpecs.status_of_current_thread.stop?.should == false
27
+ end
28
+
29
+ it "describes a running thread" do
30
+ ThreadSpecs.status_of_running_thread.stop?.should == false
31
+ end
32
+
33
+ it "describes a sleeping thread" do
34
+ ThreadSpecs.status_of_sleeping_thread.stop?.should == true
35
+ end
36
+
37
+ it "describes a blocked thread" do
38
+ ThreadSpecs.status_of_blocked_thread.stop?.should == true
39
+ end
40
+
41
+ it "describes a completed thread" do
42
+ ThreadSpecs.status_of_completed_thread.stop?.should == true
43
+ end
44
+
45
+ it "describes a killed thread" do
46
+ ThreadSpecs.status_of_killed_thread.stop?.should == true
47
+ end
48
+
49
+ it "describes a thread with an uncaught exception" do
50
+ ThreadSpecs.status_of_thread_with_uncaught_exception.stop?.should == true
51
+ end
52
+
53
+ it "describes a dying running thread" do
54
+ ThreadSpecs.status_of_dying_running_thread.stop?.should == false
55
+ end
56
+
57
+ it "describes a dying sleeping thread" do
58
+ ThreadSpecs.status_of_dying_sleeping_thread.stop?.should == true
59
+ end
60
+
61
+ quarantine! do
62
+ it "reports aborting on a killed thread" do
63
+ ThreadSpecs.status_of_aborting_thread.stop?.should == false
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+ require File.expand_path('../shared/exit', __FILE__)
4
+
5
+ describe "Thread#terminate" do
6
+ it_behaves_like :thread_exit, :terminate
7
+ end
8
+
9
+ describe "Thread#terminate!" do
10
+ it "needs to be reviewed for spec completeness"
11
+ end