Class: Backtor

Inherits:
Object
  • Object
show all
Defined in:
lib/backtor.rb

Constant Summary collapse

MAIN =
Backtor.new(__backtor_special_main: true) {}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, name: nil, __backtor_special_main: false, &block) ⇒ Backtor

Returns a new instance of Backtor.

Raises:

  • (ArgumentError)


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/backtor.rb', line 11

def initialize(*args, name: nil, __backtor_special_main: false, &block)
  raise ArgumentError, 'must be called with a block' if block.nil?
  raise TypeError, "no implicit conversion of #{name.class} into String" \
    unless name.nil? || name.is_a?(String)
  
  @name = name
  @backtor_id = Backtor.new_id
  @__backtor_special_main = __backtor_special_main

  @thread = Thread.new do
    unless __backtor_special_main
      # TODO: send parameters the proper way, see spec
      # TODO: exceptions
      Backtor.yield(self.instance_exec(*args, &block))
    end
  end
  @thread.abort_on_exception = true
  @thread.instance_variable_set(:@backtor, self)

  @incoming_queue = []
  @incoming_queue_mutex = Mutex.new
  @incoming_queue_cv = ConditionVariable.new
  @outgoing_port = Concurrent::Channel.new
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



95
96
97
# File 'lib/backtor.rb', line 95

def name
  @name
end

Class Method Details

.currentObject



72
73
74
75
76
77
78
79
80
# File 'lib/backtor.rb', line 72

def self.current
  if Thread.current == Thread.main
    Backtor::MAIN
  elsif !Thread.current.instance_variable_get(:@backtor).nil?
    Thread.current.instance_variable_get(:@backtor)
  else
    raise 'current thread is not main nor a backtor'
  end
end

.new_idObject



5
6
7
8
9
# File 'lib/backtor.rb', line 5

def self.new_id
  @last_id ||= 0
  @last_id += 1
  @last_id
end

.recvObject



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/backtor.rb', line 48

def self.recv
  mutex = Thread.current.instance_variable_get(:@backtor).instance_variable_get(:@incoming_queue_mutex)

  mutex.synchronize do
    queue = Thread.current.instance_variable_get(:@backtor).instance_variable_get(:@incoming_queue)
    cv = Thread.current.instance_variable_get(:@backtor).instance_variable_get(:@incoming_queue_cv)

    cv.wait(mutex) if queue.empty?
    queue.shift
  end
end

.yield(obj) ⇒ Object



64
65
66
# File 'lib/backtor.rb', line 64

def self.yield(obj)
  Thread.current.instance_variable_get(:@backtor).instance_variable_get(:@outgoing_port).put(obj)
end

Instance Method Details

#inspectObject



68
69
70
# File 'lib/backtor.rb', line 68

def inspect
  "#<Backtor:##{@backtor_id} #{status}>"
end

#send(obj) ⇒ Object Also known as: <<

TODO: proper clone behaviour like real ractors



40
41
42
43
44
45
# File 'lib/backtor.rb', line 40

def send(obj)
  @incoming_queue_mutex.synchronize do
    @incoming_queue << obj
    @incoming_queue_cv.signal
  end
end

#statusObject



82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/backtor.rb', line 82

def status
  return "running" if @__backtor_special_main
  
  case @thread.status
  when "run"
    "running"
  when false
    "terminated"
  else
    "unimplemented"
  end
end

#takeObject



60
61
62
# File 'lib/backtor.rb', line 60

def take
  @outgoing_port.take
end