From 1d15d5f08032acf1b7bceacbb450d617ff6e0931 Mon Sep 17 00:00:00 2001 From: eregon Date: Wed, 20 Sep 2017 20:18:52 +0000 Subject: Move spec/rubyspec to spec/ruby for consistency * Other ruby implementations use the spec/ruby directory. [Misc #13792] [ruby-core:82287] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59979 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- spec/ruby/core/thread/fixtures/classes.rb | 298 ++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 spec/ruby/core/thread/fixtures/classes.rb (limited to 'spec/ruby/core/thread/fixtures') diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb new file mode 100644 index 0000000000..b572c8dd82 --- /dev/null +++ b/spec/ruby/core/thread/fixtures/classes.rb @@ -0,0 +1,298 @@ +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_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.status_of_dying_thread_after_sleep + status = nil + t = dying_thread_ensures { + Thread.stop + status = Status.new(Thread.current) + } + Thread.pass while t.status and t.status != 'sleep' + t.wakeup + Thread.pass while t.status and t.status == 'sleep' + 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 -- cgit v1.2.3