empathy 0.0.1.RC0

Sign up to get free protection for your applications and to get access to all the features.
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,8 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../../../shared/mutex/locked', __FILE__)
3
+
4
+ ruby_version_is "1.9" do
5
+ describe "Mutex#locked?" do
6
+ it_behaves_like :mutex_locked, :locked?
7
+ end
8
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ ruby_version_is "1.9" do
4
+ describe "Mutex#sleep" do
5
+ it "raises ThreadError if not locked by the current thread" do
6
+ m = Mutex.new
7
+ lambda { m.sleep }.should raise_error(ThreadError)
8
+ end
9
+
10
+ it "pauses execution for approximately the duration requested" do
11
+ m = Mutex.new
12
+ m.lock
13
+ duration = 0.1
14
+ start = Time.now
15
+ m.sleep duration
16
+ (Time.now - start).should be_close(duration, 0.1)
17
+ end
18
+
19
+ it "unlocks the mutex while sleeping" do
20
+ m = Mutex.new
21
+ th = Thread.new { m.lock; m.sleep }
22
+ Thread.pass while th.status and th.status != "sleep"
23
+ m.locked?.should be_false
24
+ th.run
25
+ th.join
26
+ end
27
+
28
+ it "relocks the mutex when woken" do
29
+ m = Mutex.new
30
+ m.lock
31
+ m.sleep(0.01)
32
+ m.locked?.should be_true
33
+ end
34
+
35
+ it "relocks the mutex when woken by an exception being raised" do
36
+ m = Mutex.new
37
+ th = Thread.new do
38
+ m.lock
39
+ begin
40
+ m.sleep
41
+ rescue Exception
42
+ m.locked?
43
+ end
44
+ end
45
+ Thread.pass while th.status and th.status != "sleep"
46
+ th.raise(Exception)
47
+ th.value.should be_true
48
+ end
49
+
50
+ it "returns the rounded number of seconds asleep" do
51
+ m = Mutex.new
52
+ m.lock
53
+ m.sleep(0.01).should be_kind_of(Integer)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../../../shared/mutex/synchronize', __FILE__)
3
+
4
+ ruby_version_is "1.9" do
5
+ describe "Mutex#synchronize" do
6
+ it_behaves_like :mutex_synchronize, :synchronize
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../../../shared/mutex/try_lock', __FILE__)
3
+
4
+ ruby_version_is "1.9" do
5
+ describe "Mutex#try_lock" do
6
+ it_behaves_like :mutex_try_lock, :try_lock
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../../../shared/mutex/unlock', __FILE__)
3
+
4
+ ruby_version_is "1.9" do
5
+ describe "Mutex#unlock" do
6
+ it_behaves_like :mutex_unlock, :unlock
7
+ end
8
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#abort_on_exception" do
5
+ before do
6
+ ThreadSpecs.clear_state
7
+ @thread = Thread.new { Thread.pass until ThreadSpecs.state == :exit }
8
+ end
9
+
10
+ after do
11
+ ThreadSpecs.state = :exit
12
+ end
13
+
14
+ it "is false by default" do
15
+ @thread.abort_on_exception.should be_false
16
+ end
17
+
18
+ it "returns true when #abort_on_exception= is passed true" do
19
+ @thread.abort_on_exception = true
20
+ @thread.abort_on_exception.should be_true
21
+ end
22
+ end
23
+
24
+ describe :thread_abort_on_exception, :shared => true do
25
+ before do
26
+ @thread = Thread.new do
27
+ Thread.pass until ThreadSpecs.state == :run
28
+ raise RuntimeError, "Thread#abort_on_exception= specs"
29
+ end
30
+ end
31
+
32
+ ruby_version_is ""..."1.9" do
33
+ it "causes the main thread to raise a SystemExit" do
34
+ begin
35
+ ScratchPad << :before
36
+
37
+ lambda do
38
+ @thread.abort_on_exception = true if @object
39
+ ThreadSpecs.state = :run
40
+ @thread.join
41
+ end.should raise_error(SystemExit)
42
+
43
+ ScratchPad << :after
44
+ rescue Object
45
+ ScratchPad << :rescue
46
+ end
47
+
48
+ ScratchPad.recorded.should == [:before, :after]
49
+ end
50
+ end
51
+
52
+ ruby_version_is "1.9" do
53
+ it "causes the main thread to raise the exception raised in the thread" do
54
+ begin
55
+ ScratchPad << :before
56
+
57
+ lambda do
58
+ @thread.abort_on_exception = true if @object
59
+ ThreadSpecs.state = :run
60
+ @thread.join
61
+ end.should raise_error(RuntimeError)
62
+
63
+ ScratchPad << :after
64
+ rescue Object
65
+ ScratchPad << :rescue
66
+ end
67
+
68
+ ScratchPad.recorded.should == [:before, :after]
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "Thread#abort_on_exception=" do
74
+ describe "when enabled and the thread dies due to an exception" do
75
+ before do
76
+ ScratchPad.record []
77
+ ThreadSpecs.clear_state
78
+ @stderr, $stderr = $stderr, IOStub.new
79
+ end
80
+
81
+ after do
82
+ $stderr = @stderr
83
+ end
84
+
85
+ it_behaves_like :thread_abort_on_exception, nil, true
86
+ end
87
+ end
88
+
89
+ describe "Thread.abort_on_exception" do
90
+ before do
91
+ @abort_on_exception = Thread.abort_on_exception
92
+ end
93
+
94
+ after do
95
+ Thread.abort_on_exception = @abort_on_exception
96
+ end
97
+
98
+ it "is false by default" do
99
+ Thread.abort_on_exception.should == false
100
+ end
101
+
102
+ it "returns true when .abort_on_exception= is passed true" do
103
+ Thread.abort_on_exception = true
104
+ Thread.abort_on_exception.should be_true
105
+ end
106
+ end
107
+
108
+ describe "Thread.abort_on_exception=" do
109
+ describe "when enabled and a non-main thread dies due to an exception" do
110
+ before :each do
111
+ ScratchPad.record []
112
+ ThreadSpecs.clear_state
113
+ @stderr, $stderr = $stderr, IOStub.new
114
+
115
+ @abort_on_exception = Thread.abort_on_exception
116
+ Thread.abort_on_exception = true
117
+ end
118
+
119
+ after :each do
120
+ Thread.abort_on_exception = @abort_on_exception
121
+ $stderr = @stderr
122
+ end
123
+
124
+ it_behaves_like :thread_abort_on_exception, nil, false
125
+ end
126
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ ruby_version_is "1.9" do
4
+ describe "Thread#add_trace_func" do
5
+ it "needs to be reviewed for spec completeness"
6
+ end
7
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#alive?" do
5
+ it "can check it's own status" do
6
+ ThreadSpecs.status_of_current_thread.alive?.should == true
7
+ end
8
+
9
+ it "describes a running thread" do
10
+ ThreadSpecs.status_of_running_thread.alive?.should == true
11
+ end
12
+
13
+ it "describes a sleeping thread" do
14
+ ThreadSpecs.status_of_sleeping_thread.alive?.should == true
15
+ end
16
+
17
+ it "describes a blocked thread" do
18
+ ThreadSpecs.status_of_blocked_thread.alive?.should == true
19
+ end
20
+
21
+ it "describes a completed thread" do
22
+ ThreadSpecs.status_of_completed_thread.alive?.should == false
23
+ end
24
+
25
+ it "describes a killed thread" do
26
+ ThreadSpecs.status_of_killed_thread.alive?.should == false
27
+ end
28
+
29
+ it "describes a thread with an uncaught exception" do
30
+ ThreadSpecs.status_of_thread_with_uncaught_exception.alive?.should == false
31
+ end
32
+
33
+ it "describes a dying running thread" do
34
+ ThreadSpecs.status_of_dying_running_thread.alive?.should == true
35
+ end
36
+
37
+ it "describes a dying sleeping thread" do
38
+ ThreadSpecs.status_of_dying_sleeping_thread.alive?.should == true
39
+ end
40
+
41
+ ruby_version_is '1.9' do
42
+ it "return true for a killed but still running thread" do
43
+ exit = false
44
+ t = Thread.new do
45
+ begin
46
+ sleep
47
+ ensure
48
+ Thread.pass until exit # Ruby 1.8 won't switch threads here
49
+ end
50
+ end
51
+
52
+ ThreadSpecs.spin_until_sleeping(t)
53
+
54
+ t.kill
55
+ t.alive?.should == true
56
+ exit = true
57
+ t.join
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "Thread.allocate" do
4
+ it "raises a TypeError" do
5
+ lambda {
6
+ Thread.allocate
7
+ }.should raise_error(TypeError)
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ ruby_version_is "1.9" do
4
+ describe "Thread#backtrace" do
5
+ it "needs to be reviewed for spec completeness"
6
+ end
7
+ end
@@ -0,0 +1,96 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ ruby_version_is "" ... "1.9" do
5
+ describe "Thread.critical=" do
6
+ before(:each) do
7
+ ScratchPad.clear
8
+ end
9
+
10
+ it "is a persistent attribute" do
11
+ Thread.critical = true
12
+ Thread.critical.should == true
13
+ Thread.critical = false
14
+ ThreadSpecs.critical_is_reset.should == true
15
+ end
16
+
17
+ it "allows all non-bool arguments" do
18
+ Thread.critical = "Hello"
19
+ Thread.critical.should == true
20
+
21
+ Thread.critical = nil
22
+ ThreadSpecs.critical_is_reset.should == true
23
+ end
24
+
25
+ it "functions as a critical section" do
26
+ ThreadSpecs.counter = 0
27
+ iters = 50
28
+ t = Thread.new { ThreadSpecs.increment_counter(iters) }
29
+ ThreadSpecs.increment_counter(iters)
30
+ t.join
31
+ ThreadSpecs.counter.should == iters * 2
32
+ end
33
+
34
+ it "does not change status of other existing threads" do
35
+ t = ThreadSpecs.create_critical_thread { ScratchPad.record Thread.main.status }
36
+ Thread.pass while t.status and t.status != false
37
+ ScratchPad.recorded.should == "run"
38
+ end
39
+
40
+ it "is reentrant" do
41
+ Thread.critical = true
42
+ Thread.critical = true
43
+ Thread.critical.should == true
44
+ Thread.critical = false
45
+ Thread.critical = false
46
+ ThreadSpecs.critical_is_reset.should == true
47
+ end
48
+
49
+ it "can be mismatched" do
50
+ Thread.critical = true
51
+ Thread.critical = true
52
+ Thread.critical.should == true
53
+ Thread.critical = false
54
+ ThreadSpecs.critical_is_reset.should == true
55
+ end
56
+
57
+ # Hangs on 1.8.6.114 OS X, possibly also on Linux
58
+ quarantine! do
59
+ it "schedules other threads on Thread.pass" do
60
+ ThreadSpecs.critical_thread_yields_to_main_thread { Thread.pass }
61
+ end
62
+
63
+ it "schedules other threads on sleep" do
64
+ ThreadSpecs.critical_thread_yields_to_main_thread(true) { sleep }
65
+ end
66
+ end
67
+
68
+ it "schedules other threads on Thread.stop" do
69
+ # Note that Thread.Stop resets Thread.critical, whereas sleep does not
70
+ ThreadSpecs.critical_thread_yields_to_main_thread(false, true) { Thread.stop }
71
+ end
72
+
73
+ it "defers exit" do
74
+ critical_thread = ThreadSpecs.create_and_kill_critical_thread()
75
+ Thread.pass while critical_thread.status
76
+ ScratchPad.recorded.should == "status=aborting"
77
+ end
78
+
79
+ it "defers exit until Thread.pass" do
80
+ critical_thread = ThreadSpecs.create_and_kill_critical_thread(true)
81
+ Thread.pass while critical_thread.status
82
+ ScratchPad.recorded.should == nil
83
+ end
84
+
85
+ not_compliant_on(:ironruby) do # requires green threads so that another thread can be scheduled when the critical thread is killed
86
+ it "is not reset if the critical thread is killed" do
87
+ critical_thread = ThreadSpecs.create_and_kill_critical_thread(true)
88
+ Thread.pass while critical_thread.status
89
+ Thread.critical.should == true
90
+
91
+ Thread.critical = false
92
+ ThreadSpecs.critical_is_reset.should == true
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread.current" do
5
+ it "returns a thread" do
6
+ current = Thread.current
7
+ current.should be_kind_of(Thread)
8
+ end
9
+
10
+ it "returns the current thread" do
11
+ t = Thread.new { Thread.current }
12
+ t.value.should equal(t)
13
+ Thread.current.should_not equal(t.value)
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+ require File.expand_path('../fixtures/classes', __FILE__)
3
+
4
+ describe "Thread#[]" do
5
+ it "gives access to thread local values" do
6
+ th = Thread.new do
7
+ Thread.current[:value] = 5
8
+ end
9
+ th.join
10
+ th[:value].should == 5
11
+ Thread.current[:value].should == nil
12
+ end
13
+
14
+ it "is not shared across threads" do
15
+ t1 = Thread.new do
16
+ Thread.current[:value] = 1
17
+ end
18
+ t2 = Thread.new do
19
+ Thread.current[:value] = 2
20
+ end
21
+ [t1,t2].each {|x| x.join}
22
+ t1[:value].should == 1
23
+ t2[:value].should == 2
24
+ end
25
+
26
+ it "is accessable using strings or symbols" do
27
+ t1 = Thread.new do
28
+ Thread.current[:value] = 1
29
+ end
30
+ t2 = Thread.new do
31
+ Thread.current["value"] = 2
32
+ end
33
+ [t1,t2].each {|x| x.join}
34
+ t1[:value].should == 1
35
+ t1["value"].should == 1
36
+ t2[:value].should == 2
37
+ t2["value"].should == 2
38
+ end
39
+
40
+ ruby_version_is ""..."1.9" do
41
+ it "raises exceptions on the wrong type of keys" do
42
+ lambda { Thread.current[nil] }.should raise_error(TypeError)
43
+ lambda { Thread.current[5] }.should raise_error(ArgumentError)
44
+ end
45
+ end
46
+
47
+ ruby_version_is "1.9" do
48
+ it "raises exceptions on the wrong type of keys" do
49
+ lambda { Thread.current[nil] }.should raise_error(TypeError)
50
+ lambda { Thread.current[5] }.should raise_error(TypeError)
51
+ end
52
+ end
53
+ end