Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

116 lines (100 sloc) 2.927 kb
# -*- encoding: us-ascii -*-
class Thread
def self.set_critical(obj)
Rubinius.primitive :thread_set_critical
Kernel.raise PrimitiveFailure, "Thread.set_critical primitive failed"
end
def self.start(*args)
thr = Rubinius.invoke_primitive :thread_allocate, self
Rubinius.asm(args, thr) do |args, obj|
run obj
dup
push_false
send :setup, 1, true
pop
run args
push_block
send_with_splat :__thread_initialize__, 0, true
# no pop here, as .asm blocks imply a pop as they're not
# allowed to leak a stack value
end
return thr
end
class << self
alias_method :fork, :start
end
def self.stop
# Make sure that if we're stopping the current Thread,
# others can run, so reset critical.
Thread.critical = false
sleep
nil
end
def self.critical
@critical
end
def self.critical=(value)
set_critical value
@critical = !!value
end
# Called by Thread#fork in the new thread
#
def __run__()
begin
begin
Rubinius.unlock(self)
@result = @block.call(*@args)
ensure
begin
# We must lock self in a careful way.
#
# At this point, it's possible that an other thread does Thread#raise
# and then our execution is interrupted AT ANY GIVEN TIME. We
# absolutely must make sure to lock self as soon as possible to lock
# out interrupts from other threads.
#
# Rubinius.uninterrupted_lock(self) just does that.
#
# Notice that this can't be moved to other methods and there should be
# no preceding code before it in the enclosing ensure clause.
# These are to prevent any interrupted lock failures.
Rubinius.uninterrupted_lock(self)
# Now, we locked self. No other thread can interrupt this thread
# anymore.
# If there is any not-triggered interrupt, check and process it. In
# either case, we jump to the following ensure clause.
Rubinius.check_interrupts
ensure
@joins.each { |join| join.send self }
end
end
rescue Exception => e
# I don't really get this, but this is MRI's behavior. If we're dying
# by request, ignore any raised exception.
@exception = e # unless @dying
ensure
@alive = false
Rubinius.unlock(self)
unlock_locks
end
if @exception
if abort_on_exception or Thread.abort_on_exception
Thread.main.raise @exception
elsif $DEBUG
STDERR.puts "Exception in thread: #{@exception.message} (#{@exception.class})"
end
end
end
def setup(prime_lock)
@group = nil
@alive = true
@result = false
@exception = nil
@critical = false
@dying = false
@joins = []
end
def value
join_inner { @result }
end
end
Jump to Line
Something went wrong with that request. Please try again.