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,46 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#[]=" do
5
+ ruby_version_is ""..."1.9" do
6
+ it "raises exceptions on the wrong type of keys" do
7
+ lambda { Thread.current[nil] = true }.should raise_error(TypeError)
8
+ lambda { Thread.current[5] = true }.should raise_error(ArgumentError)
9
+ end
10
+ end
11
+
12
+ ruby_version_is "1.9" do
13
+ it "raises exceptions on the wrong type of keys" do
14
+ lambda { Thread.current[nil] = true }.should raise_error(TypeError)
15
+ lambda { Thread.current[5] = true }.should raise_error(TypeError)
16
+ end
17
+
18
+ it "is not shared across fibers" do
19
+ fib = Fiber.new do
20
+ Thread.current[:value] = 1
21
+ Fiber.yield
22
+ Thread.current[:value].should == 1
23
+ end
24
+ fib.resume
25
+ Thread.current[:value].should be_nil
26
+ Thread.current[:value] = 2
27
+ fib.resume
28
+ Thread.current[:value] = 2
29
+ end
30
+
31
+ it "stores a local in another thread when in a fiber" do
32
+ fib = Fiber.new do
33
+ t = Thread.new do
34
+ sleep
35
+ Thread.current[:value].should == 1
36
+ end
37
+
38
+ Thread.pass while t.status and t.status != "sleep"
39
+ t[:value] = 1
40
+ t.wakeup
41
+ t.join
42
+ end
43
+ fib.resume
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ ruby_version_is "1.9" do
4
+ describe "Thread.exclusive" do
5
+ before :each do
6
+ ScratchPad.clear
7
+ end
8
+
9
+ it "yields to the block" do
10
+ Thread.exclusive { ScratchPad.record true }
11
+ ScratchPad.recorded.should == true
12
+ end
13
+
14
+ it "returns the result of yielding" do
15
+ Thread.exclusive { :result }.should == :result
16
+ end
17
+
18
+ it "needs to be reviewed for spec completeness"
19
+ end
20
+ end
@@ -0,0 +1,21 @@
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
+ ruby_version_is ""..."1.9.1" do
6
+ describe "Thread#exit" do
7
+ it_behaves_like :thread_exit, :exit
8
+ end
9
+ end
10
+
11
+ describe "Thread#exit!" do
12
+ it "needs to be reviewed for spec completeness"
13
+ end
14
+
15
+ describe "Thread.exit" do
16
+ it "causes the current thread to exit" do
17
+ thread = Thread.new { Thread.exit; sleep }
18
+ thread.join
19
+ thread.status.should be_false
20
+ end
21
+ end
@@ -0,0 +1,291 @@
1
+ unless defined? Channel
2
+ require 'thread'
3
+ class Channel < Queue
4
+ alias receive shift
5
+ end
6
+ end
7
+
8
+ module ThreadSpecs
9
+
10
+ class SubThread < Thread
11
+ def initialize(*args)
12
+ super { args.first << 1 }
13
+ end
14
+ end
15
+
16
+ class Status
17
+ attr_reader :thread, :inspect, :status
18
+ def initialize(thread)
19
+ @thread = thread
20
+ @alive = thread.alive?
21
+ @inspect = thread.inspect
22
+ @status = thread.status
23
+ @stop = thread.stop?
24
+ end
25
+
26
+ def alive?
27
+ @alive
28
+ end
29
+
30
+ def stop?
31
+ @stop
32
+ end
33
+ end
34
+
35
+ # TODO: In the great Thread spec rewrite, abstract this
36
+ class << self
37
+ attr_accessor :state
38
+ end
39
+
40
+ def self.clear_state
41
+ @state = nil
42
+ end
43
+
44
+ def self.spin_until_sleeping(t)
45
+ Thread.pass while t.status and t.status != "sleep"
46
+ end
47
+
48
+ def self.sleeping_thread
49
+ Thread.new do
50
+ begin
51
+ sleep
52
+ ScratchPad.record :woken
53
+ rescue Object => e
54
+ ScratchPad.record e
55
+ end
56
+ end
57
+ end
58
+
59
+ def self.running_thread
60
+ Thread.new do
61
+ begin
62
+ ThreadSpecs.state = :running
63
+ loop { }
64
+ ScratchPad.record :woken
65
+ rescue Object => e
66
+ ScratchPad.record e
67
+ end
68
+ end
69
+ end
70
+
71
+ def self.completed_thread
72
+ Thread.new {}
73
+ end
74
+
75
+ def self.status_of_current_thread
76
+ Thread.new { Status.new(Thread.current) }.value
77
+ end
78
+
79
+ def self.status_of_running_thread
80
+ t = running_thread
81
+ Thread.pass while t.status and t.status != "run"
82
+ status = Status.new t
83
+ t.kill
84
+ t.join
85
+ status
86
+ end
87
+
88
+ def self.status_of_completed_thread
89
+ t = completed_thread
90
+ t.join
91
+ Status.new t
92
+ end
93
+
94
+ def self.status_of_sleeping_thread
95
+ t = sleeping_thread
96
+ Thread.pass while t.status and t.status != 'sleep'
97
+ status = Status.new t
98
+ t.run
99
+ t.join
100
+ status
101
+ end
102
+
103
+ def self.status_of_blocked_thread
104
+ m = Mutex.new
105
+ m.lock
106
+ t = Thread.new { m.lock }
107
+ Thread.pass while t.status and t.status != 'sleep'
108
+ status = Status.new t
109
+ m.unlock
110
+ t.join
111
+ status
112
+ end
113
+
114
+ def self.status_of_aborting_thread
115
+ end
116
+
117
+ def self.status_of_killed_thread
118
+ t = Thread.new { sleep }
119
+ Thread.pass while t.status and t.status != 'sleep'
120
+ t.kill
121
+ t.join
122
+ Status.new t
123
+ end
124
+
125
+ def self.status_of_thread_with_uncaught_exception
126
+ t = Thread.new { raise "error" }
127
+ begin
128
+ t.join
129
+ rescue RuntimeError
130
+ end
131
+ Status.new t
132
+ end
133
+
134
+ def self.status_of_dying_running_thread
135
+ status = nil
136
+ t = dying_thread_ensures { status = Status.new Thread.current }
137
+ t.join
138
+ status
139
+ end
140
+
141
+ def self.status_of_dying_sleeping_thread
142
+ t = dying_thread_ensures { Thread.stop; }
143
+ Thread.pass while t.status and t.status != 'sleep'
144
+ status = Status.new t
145
+ t.wakeup
146
+ t.join
147
+ status
148
+ end
149
+
150
+ def self.dying_thread_ensures(kill_method_name=:kill)
151
+ t = Thread.new do
152
+ begin
153
+ Thread.current.send(kill_method_name)
154
+ ensure
155
+ yield
156
+ end
157
+ end
158
+ end
159
+
160
+ def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
161
+ t = Thread.new do
162
+ begin
163
+ begin
164
+ Thread.current.send(kill_method_name)
165
+ ensure
166
+ raise "In dying thread"
167
+ end
168
+ ensure
169
+ yield
170
+ end
171
+ end
172
+ end
173
+
174
+ def self.join_dying_thread_with_outer_ensure(kill_method_name=:kill)
175
+ t = dying_thread_with_outer_ensure(kill_method_name) { yield }
176
+ lambda { t.join }.should raise_error(RuntimeError, "In dying thread")
177
+ return t
178
+ end
179
+
180
+ def self.wakeup_dying_sleeping_thread(kill_method_name=:kill)
181
+ t = ThreadSpecs.dying_thread_ensures(kill_method_name) { yield }
182
+ Thread.pass while t.status and t.status != 'sleep'
183
+ t.wakeup
184
+ t.join
185
+ end
186
+
187
+ def self.critical_is_reset
188
+ # Create another thread to verify that it can call Thread.critical=
189
+ t = Thread.new do
190
+ initial_critical = Thread.critical
191
+ Thread.critical = true
192
+ Thread.critical = false
193
+ initial_critical == false && Thread.critical == false
194
+ end
195
+ v = t.value
196
+ t.join
197
+ v
198
+ end
199
+
200
+ def self.counter
201
+ @@counter
202
+ end
203
+
204
+ def self.counter= c
205
+ @@counter = c
206
+ end
207
+
208
+ def self.increment_counter(incr)
209
+ incr.times do
210
+ begin
211
+ Thread.critical = true
212
+ @@counter += 1
213
+ ensure
214
+ Thread.critical = false
215
+ end
216
+ end
217
+ end
218
+
219
+ def self.critical_thread1()
220
+ Thread.critical = true
221
+ Thread.current.key?(:thread_specs).should == false
222
+ end
223
+
224
+ def self.critical_thread2(isThreadStop)
225
+ Thread.current[:thread_specs].should == 101
226
+ Thread.critical.should == !isThreadStop
227
+ if not isThreadStop
228
+ Thread.critical = false
229
+ end
230
+ end
231
+
232
+ def self.main_thread1(critical_thread, isThreadSleep, isThreadStop)
233
+ # Thread.stop resets Thread.critical. Also, with native threads, the Thread.Stop may not have executed yet
234
+ # since the main thread will race with the critical thread
235
+ if not isThreadStop
236
+ Thread.critical.should == true
237
+ end
238
+ critical_thread[:thread_specs] = 101
239
+ if isThreadSleep or isThreadStop
240
+ # Thread#wakeup calls are not queued up. So we need to ensure that the thread is sleeping before calling wakeup
241
+ Thread.pass while critical_thread.status and critical_thread.status != "sleep"
242
+ critical_thread.wakeup
243
+ end
244
+ end
245
+
246
+ def self.main_thread2(critical_thread)
247
+ Thread.pass # The join below seems to cause a deadlock with CRuby unless Thread.pass is called first
248
+ critical_thread.join
249
+ Thread.critical.should == false
250
+ end
251
+
252
+ def self.critical_thread_yields_to_main_thread(isThreadSleep=false, isThreadStop=false)
253
+ @@after_first_sleep = false
254
+
255
+ critical_thread = Thread.new do
256
+ Thread.pass while Thread.main.status and Thread.main.status != "sleep"
257
+ critical_thread1()
258
+ Thread.main.wakeup
259
+ yield
260
+ Thread.pass while @@after_first_sleep != true # Need to ensure that the next statement does not see the first sleep itself
261
+ Thread.pass while Thread.main.status and Thread.main.status != "sleep"
262
+ critical_thread2(isThreadStop)
263
+ Thread.main.wakeup
264
+ end
265
+
266
+ sleep 5
267
+ @@after_first_sleep = true
268
+ main_thread1(critical_thread, isThreadSleep, isThreadStop)
269
+ sleep 5
270
+ main_thread2(critical_thread)
271
+ end
272
+
273
+ def self.create_critical_thread()
274
+ critical_thread = Thread.new do
275
+ Thread.critical = true
276
+ yield
277
+ Thread.critical = false
278
+ end
279
+ return critical_thread
280
+ end
281
+
282
+ def self.create_and_kill_critical_thread(passAfterKill=false)
283
+ critical_thread = ThreadSpecs.create_critical_thread do
284
+ Thread.current.kill
285
+ if passAfterKill
286
+ Thread.pass
287
+ end
288
+ ScratchPad.record("status=" + Thread.current.status)
289
+ end
290
+ end
291
+ 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.fork" do
6
+ describe "Thread.start" do
7
+ it_behaves_like :thread_start, :fork
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+ describe "Thread#group" do
4
+ it "needs to be reviewed for spec completeness"
5
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#initialize" do
5
+
6
+ describe "already initialized" do
7
+
8
+ before do
9
+ @t = Thread.new { sleep }
10
+ end
11
+
12
+ after do
13
+ @t.kill
14
+ end
15
+
16
+ it "raises a ThreadError" do
17
+ lambda {
18
+ @t.instance_eval do
19
+ initialize {}
20
+ end
21
+ }.should raise_error(ThreadError)
22
+ end
23
+
24
+ end
25
+
26
+ 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#inspect" do
5
+ it "can check it's own status" do
6
+ ThreadSpecs.status_of_current_thread.inspect.should include('run')
7
+ end
8
+
9
+ it "describes a running thread" do
10
+ ThreadSpecs.status_of_running_thread.inspect.should include('run')
11
+ end
12
+
13
+ it "describes a sleeping thread" do
14
+ ThreadSpecs.status_of_sleeping_thread.inspect.should include('sleep')
15
+ end
16
+
17
+ it "describes a blocked thread" do
18
+ ThreadSpecs.status_of_blocked_thread.inspect.should include('sleep')
19
+ end
20
+
21
+ it "describes a completed thread" do
22
+ ThreadSpecs.status_of_completed_thread.inspect.should include('dead')
23
+ end
24
+
25
+ it "describes a killed thread" do
26
+ ThreadSpecs.status_of_killed_thread.inspect.should include('dead')
27
+ end
28
+
29
+ it "describes a thread with an uncaught exception" do
30
+ ThreadSpecs.status_of_thread_with_uncaught_exception.inspect.should include('dead')
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.inspect.should include('aborting')
36
+ end
37
+ end
38
+
39
+ it "describes a dying sleeping thread" do
40
+ ThreadSpecs.status_of_dying_sleeping_thread.status.should include('sleep')
41
+ end
42
+
43
+ quarantine! do
44
+ it "reports aborting on a killed thread" do
45
+ ThreadSpecs.status_of_aborting_thread.inspect.should include('aborting')
46
+ end
47
+ end
48
+ end