lib/elevate/io_coordinator.rb in elevate-0.5.0 vs lib/elevate/io_coordinator.rb in elevate-0.6.0

- old
+ new

@@ -1,69 +1,134 @@ module Elevate + # Implements task cancellation. + # + # Compliant I/O mechanisms (such as HTTP requests) register long-running + # operations with a well-known instance of this class. When a cancellation + # request is received from another thread, the long-running operation is + # cancelled. class IOCoordinator + # Retrieves the current IOCoordinator for this thread. + # + # @return [IOCoordinator,nil] + # IOCoordinator previously installed to this thread + # + # @api public def self.for_thread Thread.current[:io_coordinator] end + # Initializes a new IOCoordinator with the default state. + # + # @api private def initialize @lock = NSLock.alloc.init @blocking_operation = nil @cancelled = false + @exception_class = nil end - def cancel + # Cancels the I/O operation (if any), raising an exception of type + # +exception_class+ in the worker thread. + # + # If the thread is not currently blocked, then set a flag requesting cancellation. + # + # @return [void] + # + # @api private + def cancel(exception_class = CancelledError) blocking_operation = nil - @lock.lock() + @lock.lock @cancelled = true + @exception_class = exception_class blocking_operation = @blocking_operation - @lock.unlock() + @lock.unlock if blocking_operation - blocking_operation.cancel() + blocking_operation.cancel end end + # Returns the cancelled flag. + # + # @return [Boolean] + # true if this coordinator has been +cancel+ed previously. + # + # @api private def cancelled? cancelled = nil - @lock.lock() + @lock.lock cancelled = @cancelled - @lock.unlock() + @lock.unlock cancelled end + # Installs this IOCoordinator to a well-known thread-local. + # + # @return [void] + # + # @api private def install Thread.current[:io_coordinator] = self end + # Marks the specified operation as one that will potentially block the + # worker thread for a significant amount of time. + # + # @param operation [#cancel] + # operation responsible for blocking + # + # @return [void] + # + # @api public def signal_blocked(operation) check_for_cancellation - @lock.lock() + @lock.lock @blocking_operation = operation - @lock.unlock() + @lock.unlock end + # Signals that the specified operation has completed, and is no longer + # responsible for blocking the worker thread. + # + # @return [void] + # + # @api public def signal_unblocked(operation) - @lock.lock() + @lock.lock @blocking_operation = nil - @lock.unlock() + @lock.unlock check_for_cancellation end + # Removes the thread-local for the calling thread. + # + # @return [void] + # + # @api private def uninstall Thread.current[:io_coordinator] = nil end private def check_for_cancellation - raise CancelledError if cancelled? + raise @exception_class if cancelled? end end + # Raised when a task is cancelled. + # + # @api public class CancelledError < StandardError + end + + # Raised when a task's timeout expires + # + # @api public + class TimeoutError < CancelledError end end