1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
require File.expand_path('../spec_helper', __FILE__)
require File.expand_path('../../../core/thread/shared/wakeup', __FILE__)
load_extension("thread")
class Thread
def self.capi_thread_specs=(t)
@@capi_thread_specs = t
end
def call_capi_rb_thread_wakeup
@@capi_thread_specs.rb_thread_wakeup(self)
end
end
describe "C-API Thread function" do
before :each do
@t = CApiThreadSpecs.new
ScratchPad.clear
Thread.capi_thread_specs = @t
end
describe "rb_thread_select" do
it "returns true if an fd is ready to read" do
read, write = IO.pipe
@t.rb_thread_select_fd(read.to_i, 0).should == false
write << "1"
@t.rb_thread_select_fd(read.to_i, 0).should == true
end
it "does not block all threads" do
t = Thread.new do
sleep 0.25
ScratchPad.record :inner
end
Thread.pass while t.status and t.status != "sleep"
@t.rb_thread_select(500_000)
t.alive?.should be_false
ScratchPad.recorded.should == :inner
t.join
end
end
describe "rb_thread_wait_for" do
it "sleeps the current thread for the give ammount of time" do
start = Time.now
@t.rb_thread_wait_for(0, 100_000)
(Time.now - start).should be_close(0.1, 0.1)
end
end
describe "rb_thread_alone" do
it "returns true if there is only one thread" do
pred = Thread.list.size == 1
@t.rb_thread_alone.should == pred
end
end
describe "rb_thread_current" do
it "equals Thread.current" do
@t.rb_thread_current.should == Thread.current
end
end
describe "rb_thread_local_aref" do
it "returns the value of a thread-local variable" do
thr = Thread.current
sym = :thread_capi_specs_aref
thr[sym] = 1
@t.rb_thread_local_aref(thr, sym).should == 1
end
it "returns nil if the value has not been set" do
@t.rb_thread_local_aref(Thread.current, :thread_capi_specs_undefined).should be_nil
end
end
describe "rb_thread_local_aset" do
it "sets the value of a thread-local variable" do
thr = Thread.current
sym = :thread_capi_specs_aset
@t.rb_thread_local_aset(thr, sym, 2).should == 2
thr[sym].should == 2
end
end
describe "rb_thread_wakeup" do
it_behaves_like :thread_wakeup, :call_capi_rb_thread_wakeup
end
describe "rb_thread_create" do
it "creates a new thread" do
obj = Object.new
proc = lambda { |x| ScratchPad.record x }
thr = @t.rb_thread_create(proc, obj)
thr.should be_kind_of(Thread)
thr.join
ScratchPad.recorded.should == obj
end
it "handles throwing an exception in the thread" do
proc = lambda { |x| raise NotImplementedError }
thr = @t.rb_thread_create(proc, nil)
thr.should be_kind_of(Thread)
lambda { thr.join }.should raise_error(NotImplementedError)
end
end
end
describe :rb_thread_blocking_region, :shared => true do
before :each do
@t = CApiThreadSpecs.new
ScratchPad.clear
end
it "runs a C function with the global lock unlocked" do
thr = Thread.new do
@t.send(@method)
end
# Wait until it's blocking...
sleep 1
# Wake it up, causing the unblock function to be run.
thr.wakeup
# Make sure it stopped
thr.join(1).should_not be_nil
# And we got a proper value
thr.value.should be_true
end
end
describe "C-API Thread function" do
describe "rb_thread_blocking_region" do
extended_on :rubinius do
it_behaves_like :rb_thread_blocking_region, :rb_thread_blocking_region_with_ubf_io
it_behaves_like :rb_thread_blocking_region, :rb_thread_blocking_region
end
ruby_version_is "1.9" do
it_behaves_like :rb_thread_blocking_region, :rb_thread_blocking_region_with_ubf_io
it_behaves_like :rb_thread_blocking_region, :rb_thread_blocking_region
end
end
end
|