summaryrefslogtreecommitdiff
path: root/spec/rubyspec/core/thread/fixtures/classes.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/rubyspec/core/thread/fixtures/classes.rb')
-rw-r--r--spec/rubyspec/core/thread/fixtures/classes.rb288
1 files changed, 288 insertions, 0 deletions
diff --git a/spec/rubyspec/core/thread/fixtures/classes.rb b/spec/rubyspec/core/thread/fixtures/classes.rb
new file mode 100644
index 0000000000..7f7bb69a61
--- /dev/null
+++ b/spec/rubyspec/core/thread/fixtures/classes.rb
@@ -0,0 +1,288 @@
+unless defined? Channel
+ require 'thread'
+ class Channel < Queue
+ alias receive shift
+ end
+end
+
+module ThreadSpecs
+
+ class SubThread < Thread
+ def initialize(*args)
+ super { args.first << 1 }
+ end
+ end
+
+ class Status
+ attr_reader :thread, :inspect, :status
+ def initialize(thread)
+ @thread = thread
+ @alive = thread.alive?
+ @inspect = thread.inspect
+ @status = thread.status
+ @stop = thread.stop?
+ end
+
+ def alive?
+ @alive
+ end
+
+ def stop?
+ @stop
+ end
+ end
+
+ # TODO: In the great Thread spec rewrite, abstract this
+ class << self
+ attr_accessor :state
+ end
+
+ def self.clear_state
+ @state = nil
+ end
+
+ def self.spin_until_sleeping(t)
+ Thread.pass while t.status and t.status != "sleep"
+ end
+
+ def self.sleeping_thread
+ Thread.new do
+ begin
+ sleep
+ ScratchPad.record :woken
+ rescue Object => e
+ ScratchPad.record e
+ end
+ end
+ end
+
+ def self.running_thread
+ Thread.new do
+ begin
+ ThreadSpecs.state = :running
+ loop { Thread.pass }
+ ScratchPad.record :woken
+ rescue Object => e
+ ScratchPad.record e
+ end
+ end
+ end
+
+ def self.completed_thread
+ Thread.new {}
+ end
+
+ def self.status_of_current_thread
+ Thread.new { Status.new(Thread.current) }.value
+ end
+
+ def self.status_of_running_thread
+ t = running_thread
+ Thread.pass while t.status and t.status != "run"
+ status = Status.new t
+ t.kill
+ t.join
+ status
+ end
+
+ def self.status_of_completed_thread
+ t = completed_thread
+ t.join
+ Status.new t
+ end
+
+ def self.status_of_sleeping_thread
+ t = sleeping_thread
+ Thread.pass while t.status and t.status != 'sleep'
+ status = Status.new t
+ t.run
+ t.join
+ status
+ end
+
+ def self.status_of_blocked_thread
+ m = Mutex.new
+ m.lock
+ t = Thread.new { m.lock }
+ Thread.pass while t.status and t.status != 'sleep'
+ status = Status.new t
+ m.unlock
+ t.join
+ status
+ end
+
+ def self.status_of_aborting_thread
+ end
+
+ def self.status_of_killed_thread
+ t = Thread.new { sleep }
+ Thread.pass while t.status and t.status != 'sleep'
+ t.kill
+ t.join
+ Status.new t
+ end
+
+ def self.status_of_thread_with_uncaught_exception
+ t = Thread.new { raise "error" }
+ begin
+ t.join
+ rescue RuntimeError
+ end
+ Status.new t
+ end
+
+ def self.status_of_dying_running_thread
+ status = nil
+ t = dying_thread_ensures { status = Status.new Thread.current }
+ t.join
+ status
+ end
+
+ def self.status_of_dying_sleeping_thread
+ t = dying_thread_ensures { Thread.stop; }
+ Thread.pass while t.status and t.status != 'sleep'
+ status = Status.new t
+ t.wakeup
+ t.join
+ status
+ end
+
+ def self.dying_thread_ensures(kill_method_name=:kill)
+ Thread.new do
+ begin
+ Thread.current.send(kill_method_name)
+ ensure
+ yield
+ end
+ end
+ end
+
+ def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
+ Thread.new do
+ begin
+ begin
+ Thread.current.send(kill_method_name)
+ ensure
+ raise "In dying thread"
+ end
+ ensure
+ yield
+ end
+ end
+ end
+
+ def self.join_dying_thread_with_outer_ensure(kill_method_name=:kill)
+ t = dying_thread_with_outer_ensure(kill_method_name) { yield }
+ lambda { t.join }.should raise_error(RuntimeError, "In dying thread")
+ return t
+ end
+
+ def self.wakeup_dying_sleeping_thread(kill_method_name=:kill)
+ t = ThreadSpecs.dying_thread_ensures(kill_method_name) { yield }
+ Thread.pass while t.status and t.status != 'sleep'
+ t.wakeup
+ t.join
+ end
+
+ def self.critical_is_reset
+ # Create another thread to verify that it can call Thread.critical=
+ t = Thread.new do
+ initial_critical = Thread.critical
+ Thread.critical = true
+ Thread.critical = false
+ initial_critical == false && Thread.critical == false
+ end
+ v = t.value
+ t.join
+ v
+ end
+
+ def self.counter
+ @@counter
+ end
+
+ def self.counter= c
+ @@counter = c
+ end
+
+ def self.increment_counter(incr)
+ incr.times do
+ begin
+ Thread.critical = true
+ @@counter += 1
+ ensure
+ Thread.critical = false
+ end
+ end
+ end
+
+ def self.critical_thread1
+ Thread.critical = true
+ Thread.current.key?(:thread_specs).should == false
+ end
+
+ def self.critical_thread2(is_thread_stop)
+ Thread.current[:thread_specs].should == 101
+ Thread.critical.should == !is_thread_stop
+ unless is_thread_stop
+ Thread.critical = false
+ end
+ end
+
+ def self.main_thread1(critical_thread, is_thread_sleep, is_thread_stop)
+ # Thread.stop resets Thread.critical. Also, with native threads, the Thread.Stop may not have executed yet
+ # since the main thread will race with the critical thread
+ unless is_thread_stop
+ Thread.critical.should == true
+ end
+ critical_thread[:thread_specs] = 101
+ if is_thread_sleep or is_thread_stop
+ # Thread#wakeup calls are not queued up. So we need to ensure that the thread is sleeping before calling wakeup
+ Thread.pass while critical_thread.status and critical_thread.status != "sleep"
+ critical_thread.wakeup
+ end
+ end
+
+ def self.main_thread2(critical_thread)
+ Thread.pass # The join below seems to cause a deadlock with CRuby unless Thread.pass is called first
+ critical_thread.join
+ Thread.critical.should == false
+ end
+
+ def self.critical_thread_yields_to_main_thread(is_thread_sleep=false, is_thread_stop=false)
+ @@after_first_sleep = false
+
+ critical_thread = Thread.new do
+ Thread.pass while Thread.main.status and Thread.main.status != "sleep"
+ critical_thread1()
+ Thread.main.wakeup
+ yield
+ Thread.pass while @@after_first_sleep != true # Need to ensure that the next statement does not see the first sleep itself
+ Thread.pass while Thread.main.status and Thread.main.status != "sleep"
+ critical_thread2(is_thread_stop)
+ Thread.main.wakeup
+ end
+
+ sleep 5
+ @@after_first_sleep = true
+ main_thread1(critical_thread, is_thread_sleep, is_thread_stop)
+ sleep 5
+ main_thread2(critical_thread)
+ end
+
+ def self.create_critical_thread
+ Thread.new do
+ Thread.critical = true
+ yield
+ Thread.critical = false
+ end
+ end
+
+ def self.create_and_kill_critical_thread(pass_after_kill=false)
+ ThreadSpecs.create_critical_thread do
+ Thread.current.kill
+ Thread.pass if pass_after_kill
+ ScratchPad.record("status=" + Thread.current.status)
+ end
+ end
+end