Class: Rubinius::Actor

Inherits:
Object
  • Object
show all
Defined in:
lib/rubinius/actor/filter.rb,
lib/rubinius/actor.rb

Overview

actor/filter.rb - actor message filters

Copyright 2007-2008 MenTaLguY <[email protected]>

2007-2011  Evan Phoenix <[email protected]>

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, thi slist of conditions and the following disclaimer.

  • Redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentatio and/or other materials provided with the distribution.

  • Neither the name of the Evan Phoenix nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Defined Under Namespace

Classes: DeadActorError, Filter

Constant Summary collapse

ANY =
Object.new
@@registered_lock =
Rubinius::Channel.new
@@registered =
{}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeActor

Returns a new instance of Actor.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/rubinius/actor.rb', line 194

def initialize
  @lock = Rubinius::Channel.new

  @filter = nil
  @ready = Rubinius::Channel.new
  @action = nil
  @message = nil

  @mailbox = []
  @interrupts = []
  @links = []
  @alive = true
  @exit_reason = nil
  @trap_exit = false
  @thread = Thread.current

  @lock << nil

  if block_given?
    watchdog { yield self }
  else
    Thread.new { watchdog { @thread.join } }
  end
end

Class Method Details

._unregister(actor) ⇒ Object

:nodoc:



184
185
186
187
188
189
190
191
# File 'lib/rubinius/actor.rb', line 184

def _unregister(actor) #:nodoc:
  @@registered_lock.receive
  begin
    @@registered.delete_if { |n, a| actor.equal? a }
  ensure
    @@registered_lock << nil
  end
end

.check_for_interruptObject

Polls for exit notifications



93
94
95
96
# File 'lib/rubinius/actor.rb', line 93

def check_for_interrupt
  current._check_for_interrupt
  self
end

.currentObject



58
59
60
# File 'lib/rubinius/actor.rb', line 58

def current
  Thread.current[:__current_actor__] ||= private_new
end

Link the current Actor to another one.



119
120
121
122
123
124
# File 'lib/rubinius/actor.rb', line 119

def link(actor)
  current = self.current
  current.notify_link actor
  actor.notify_link current
  self
end

.lookup(name) ⇒ Object Also known as: []

Lookup a locally named service

Raises:

  • (ArgumentError)


153
154
155
156
157
158
159
160
161
# File 'lib/rubinius/actor.rb', line 153

def lookup(name)
  raise ArgumentError, "name must be a symbol" unless Symbol === name
  @@registered_lock.receive
  begin
    @@registered[name]
  ensure
    @@registered_lock << nil
  end
end

.receiveObject

Waits until a matching message is received in the current actor’s mailbox, and executes the appropriate action. May be interrupted by exit notifications.



101
102
103
104
105
106
107
108
109
# File 'lib/rubinius/actor.rb', line 101

def receive #:yields: filter
  filter = Filter.new
  if block_given?
    yield filter
  else
    filter.when(ANY) { |m| m }
  end
  current._receive(filter)
end

.register(name, actor) ⇒ Object Also known as: []=

Register an Actor locally as a named service

Raises:

  • (ArgumentError)


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rubinius/actor.rb', line 165

def register(name, actor)
  raise ArgumentError, "name must be a symbol" unless Symbol === name
  unless actor.nil? or actor.is_a?(Actor)
    raise ArgumentError, "only actors may be registered"
  end

  @@registered_lock.receive
  begin
    if actor.nil?
      @@registered.delete(name)
    else
      @@registered[name] = actor
    end
  ensure
    @@registered_lock << nil
  end
end

.send_exit(recipient, reason) ⇒ Object

Send a “fake” exit notification to another actor, as if the current actor had exited with reason



113
114
115
116
# File 'lib/rubinius/actor.rb', line 113

def send_exit(recipient, reason)
  recipient.notify_exited(current, reason)
  self
end

.spawn(*args, &block) ⇒ Object Also known as: new

Spawn a new Actor that will run in its own thread

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rubinius/actor.rb', line 63

def spawn(*args, &block)
  raise ArgumentError, "no block given" unless block
  spawned = Rubinius::Channel.new
  Thread.new do
    private_new do |actor|
      Thread.current[:__current_actor__] = actor
      spawned << actor
      block.call *args
    end
  end
  spawned.receive
end

Atomically spawn an actor and link it to the current actor



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rubinius/actor.rb', line 78

def spawn_link(*args, &block)
  current = self.current
  link_complete = Rubinius::Channel.new
  spawn do
    begin
      Actor.link(current)
    ensure
      link_complete << Actor.current
    end
    block.call *args
  end
  link_complete.receive
end

.trap_exitObject Also known as: trap_exit?

Is the Actor trapping exit?



147
148
149
# File 'lib/rubinius/actor.rb', line 147

def trap_exit
  current._trap_exit
end

.trap_exit=(value) ⇒ Object

Actors trapping exit do not die when an error occurs in an Actor they are linked to. Instead the exit message is sent to their regular mailbox in the form [:exit, actor, reason]. This allows certain Actors to supervise sets of others and restart them in the event of an error. Setting the trap flag may be interrupted by pending exit notifications.



141
142
143
144
# File 'lib/rubinius/actor.rb', line 141

def trap_exit=(value)
  current._trap_exit = value
  self
end

Unlink the current Actor from another one



127
128
129
130
131
132
# File 'lib/rubinius/actor.rb', line 127

def unlink(actor)
  current = self.current
  current.notify_unlink actor
  actor.notify_unlink current
  self
end

Instance Method Details

#_check_for_interruptObject

:nodoc:



242
243
244
245
246
247
248
249
250
# File 'lib/rubinius/actor.rb', line 242

def _check_for_interrupt #:nodoc:
  check_thread
  @lock.receive
  begin
    raise @interrupts.shift unless @interrupts.empty?
  ensure
    @lock << nil
  end
end

#_receive(filter) ⇒ Object

:nodoc:



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/rubinius/actor.rb', line 252

def _receive(filter) #:nodoc:
  check_thread

  action = nil
  message = nil
  timed_out = false

  @lock.receive
  begin
    raise @interrupts.shift unless @interrupts.empty?

    for i in 0...(@mailbox.size)
      message = @mailbox[i]
      action = filter.action_for(message)
      if action
        @mailbox.delete_at(i)
        break
      end
    end

    unless action
      @filter = filter
      @lock << nil
      begin
        if filter.timeout?
          timed_out = @ready.receive_timeout(filter.timeout) == false
        else
          @ready.receive
        end
      ensure
        @lock.receive
      end

      if !timed_out and @interrupts.empty?
        action = @action
        message = @message
      else
        @mailbox << @message if @action
      end

      @action = nil
      @message = nil

      raise @interrupts.shift unless @interrupts.empty?
    end
  ensure
    @lock << nil
  end

  if timed_out
    filter.timeout_action.call
  else
    action.call message
  end
end

#_trap_exitObject

:nodoc:



416
417
418
419
420
421
422
423
424
# File 'lib/rubinius/actor.rb', line 416

def _trap_exit #:nodoc:
  check_thread
  @lock.receive
  begin
    @trap_exit
  ensure
    @lock << nil
  end
end

#_trap_exit=(value) ⇒ Object

:nodoc:



405
406
407
408
409
410
411
412
413
414
# File 'lib/rubinius/actor.rb', line 405

def _trap_exit=(value) #:nodoc:
  check_thread
  @lock.receive
  begin
    raise @interrupts.shift unless @interrupts.empty?
    @trap_exit = !!value
  ensure
    @lock << nil
  end
end

#notify_exited(actor, reason) ⇒ Object

Notify this actor that one of the Actors it’s linked to has exited; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.send_exit instead.



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/rubinius/actor.rb', line 346

def notify_exited(actor, reason)
  to_send = nil
  @lock.receive
  begin
    return self unless @alive
    @links.delete(actor)
    ex = DeadActorError.new(actor, reason)
    if @trap_exit
      to_send = ex
    elsif reason
      @interrupts << ex
      if @filter
        @filter = nil
        @ready << nil
      end
    end
  ensure
    @lock << nil
  end
  send to_send if to_send
  self
end

Notify this actor that it’s now linked to the given one; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.link instead.



312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/rubinius/actor.rb', line 312

def notify_link(actor)
  @lock.receive
  alive = nil
  exit_reason = nil
  begin
    alive = @alive
    exit_reason = @exit_reason
    @links << actor if alive and not @links.include? actor
  ensure
    @lock << nil
  end
  actor.notify_exited(self, exit_reason) unless alive
  self
end

Notify this actor that it’s now unlinked from the given one; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.unlink instead.



331
332
333
334
335
336
337
338
339
340
# File 'lib/rubinius/actor.rb', line 331

def notify_unlink(actor)
  @lock.receive
  begin
    return self unless @alive
    @links.delete(actor)
  ensure
    @lock << nil
  end
  self
end

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



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rubinius/actor.rb', line 219

def send(message)
  @lock.receive
  begin
    return self unless @alive
    if @filter
      @action = @filter.action_for(message)
      if @action
        @filter = nil
        @message = message
        @ready << nil
      else
        @mailbox << message
      end
    else
      @mailbox << message
    end
  ensure
    @lock << nil
  end
  self
end