Class: LittleGhost::Support::Task

Inherits:
Object
  • Object
show all
Defined in:
lib/little_ghost/support/task.rb

Overview

Task represents one unit of framework-owned concurrent work. It provides the same completion contract whether TaskRunner selected a thread or fiber.

Constant Summary collapse

CURRENT_KEY =

:nodoc:

:little_ghost_support_task

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(execution_state:, capture_interruptions: false, &work) ⇒ Task

:nodoc:



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/little_ghost/support/task.rb', line 17

def initialize(execution_state:, capture_interruptions: false, &work) # :nodoc:
  @execution_state = execution_state
  @capture_interruptions = capture_interruptions
  @work = work
  @mutex = Mutex.new
  @condition = ConditionVariable.new
  @finished = false
  @result = nil
  @error = nil
  @terminable = false
  @joinable = false
end

Class Method Details

.currentObject

Returns the Task currently running for this caller, if any.



12
13
14
# File 'lib/little_ghost/support/task.rb', line 12

def current
  ExecutionState[CURRENT_KEY]
end

Instance Method Details

#alive?Boolean

Indicates that the task has not finished.

Returns:

  • (Boolean)


68
69
70
# File 'lib/little_ghost/support/task.rb', line 68

def alive?
  @mutex.synchronize { !@finished }
end

#callObject

:nodoc:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/little_ghost/support/task.rb', line 101

def call # :nodoc:
  ExecutionState.with(@execution_state) do
    result = ExecutionState.with(CURRENT_KEY => self) { @work.call }
    @mutex.synchronize { @result = result }
  end
rescue => caught
  @mutex.synchronize { @error = caught }
rescue Exception => caught # rubocop:disable Lint/RescueException
  raise unless @capture_interruptions

  @mutex.synchronize { @error = caught }
ensure
  @mutex.synchronize do
    @finished = true
    @condition.broadcast
  end
end

#current?Boolean

Indicates that the caller is running this task.

Returns:

  • (Boolean)


73
74
75
# File 'lib/little_ghost/support/task.rb', line 73

def current?
  equal?(self.class.current)
end

#errorObject

Returns the worker failure after completion, or nil.



63
64
65
# File 'lib/little_ghost/support/task.rb', line 63

def error
  @mutex.synchronize { @error }
end

#resultObject

Returns the task result after completion.



58
59
60
# File 'lib/little_ghost/support/task.rb', line 58

def result
  @mutex.synchronize { @result }
end

#start(worker = nil, terminable: false, joinable: false) ⇒ Object

:nodoc:



92
93
94
95
96
97
98
99
# File 'lib/little_ghost/support/task.rb', line 92

def start(worker = nil, terminable: false, joinable: false) # :nodoc:
  @mutex.synchronize do
    @worker = worker
    @terminable = terminable
    @joinable = joinable
  end
  self
end

#terminateObject

Requests forceful termination of a thread-backed task. Fiber tasks are cooperatively cancelled by their owning operation, so this method returns false for them. The owner remains responsible for a bounded wait after termination.



81
82
83
84
85
86
87
88
89
90
# File 'lib/little_ghost/support/task.rb', line 81

def terminate
  return false unless @terminable
  return false if current?

  worker = @mutex.synchronize { @worker unless @finished }
  return false unless worker

  worker.kill
  true
end

#wait(deadline: nil) ⇒ Object

Waits for completion and returns this Task.

deadline is an absolute Time. Reaching it raises DeadlineExceededError without stopping the task.

Raises:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/little_ghost/support/task.rb', line 34

def wait(deadline: nil)
  raise Error, "a task cannot wait for itself" if current?

  monotonic_deadline = if deadline
    monotonic_time + [deadline - Time.now, 0].max
  end
  worker, joinable = @mutex.synchronize do
    until @finished
      if monotonic_deadline
        remaining = monotonic_deadline - monotonic_time
        raise DeadlineExceededError, "Task did not finish before the wait deadline" unless remaining.positive?

        @condition.wait(@mutex, remaining)
      else
        @condition.wait(@mutex)
      end
    end
    [@worker, @joinable]
  end
  worker.join if joinable
  self
end