dramatis 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/License.txt +20 -0
- data/Manifest.txt +119 -0
- data/README.txt +57 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/examples/README.txt +20 -0
- data/examples/auction.rb +90 -0
- data/examples/bank/bank.rb +7 -0
- data/examples/bank/bank_test.rb +7 -0
- data/examples/exception.rb +40 -0
- data/examples/fib/conservative.rb +50 -0
- data/examples/fib/future.rb +5 -0
- data/examples/fib/original.rb +33 -0
- data/examples/fib/threads.rb +51 -0
- data/examples/im/distributed/chat/client.rb +49 -0
- data/examples/im/distributed/chat/screen/fox.rb +92 -0
- data/examples/im/distributed/chat/screen.rb +11 -0
- data/examples/im/distributed/chat/server.rb +72 -0
- data/examples/im/distributed/chat.rb +5 -0
- data/examples/im/distributed/client.rb +9 -0
- data/examples/im/distributed/run.rb +18 -0
- data/examples/im/distributed/server.rb +11 -0
- data/examples/im/single/chat/client.rb +50 -0
- data/examples/im/single/chat/screen/fox.rb +96 -0
- data/examples/im/single/chat/screen/wxs.rb +63 -0
- data/examples/im/single/chat/screen.rb +11 -0
- data/examples/im/single/chat/server.rb +72 -0
- data/examples/im/single/chat.rb +5 -0
- data/examples/im/single/fox.rb +18 -0
- data/examples/im/single/wxchat.rb +19 -0
- data/examples/pingpong/actor.rb +33 -0
- data/examples/pingpong/actor_rec.rb +34 -0
- data/examples/pingpong/pingpong.txt +315 -0
- data/examples/pingpong/scala.rb +41 -0
- data/examples/pingpong/serial.rb +26 -0
- data/examples/pretty.txt +108 -0
- data/examples/telephone/.irbrc +2 -0
- data/examples/telephone/3esl.txt +21877 -0
- data/examples/telephone/fifth/kid.rb +36 -0
- data/examples/telephone/fifth/run.rb +26 -0
- data/examples/telephone/first/kid.rb +31 -0
- data/examples/telephone/first/run.rb +20 -0
- data/examples/telephone/fourth/kid.rb +31 -0
- data/examples/telephone/fourth/run.rb +26 -0
- data/examples/telephone/mangler.rb +53 -0
- data/examples/telephone/second/kid.rb +26 -0
- data/examples/telephone/second/run.rb +20 -0
- data/examples/telephone/seventh/kid.rb +40 -0
- data/examples/telephone/seventh/run.rb +35 -0
- data/examples/telephone/seventh/test.rb +28 -0
- data/examples/telephone/seventh/test2.rb +10 -0
- data/examples/telephone/sixth/kid.rb +39 -0
- data/examples/telephone/sixth/run.rb +26 -0
- data/examples/telephone/third/kid.rb +31 -0
- data/examples/telephone/third/run.rb +21 -0
- data/lib/dramatis/actor/interface.rb +118 -0
- data/lib/dramatis/actor/name/interface.rb +128 -0
- data/lib/dramatis/actor/name.rb +44 -0
- data/lib/dramatis/actor.rb +96 -0
- data/lib/dramatis/deadlock.rb +123 -0
- data/lib/dramatis/error/uncaught.rb +19 -0
- data/lib/dramatis/error.rb +125 -0
- data/lib/dramatis/future/interface.rb +45 -0
- data/lib/dramatis/future.rb +32 -0
- data/lib/dramatis/runtime/actor/main.rb +3 -0
- data/lib/dramatis/runtime/actor.rb +294 -0
- data/lib/dramatis/runtime/gate.rb +244 -0
- data/lib/dramatis/runtime/scheduler.rb +374 -0
- data/lib/dramatis/runtime/task.rb +390 -0
- data/lib/dramatis/runtime/thread_pool.rb +149 -0
- data/lib/dramatis/runtime/timer.rb +5 -0
- data/lib/dramatis/runtime.rb +129 -0
- data/lib/dramatis/shoes/runtime.rb +7 -0
- data/lib/dramatis/shoes.rb +14 -0
- data/lib/dramatis/version.rb +8 -0
- data/lib/dramatis.rb +73 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/spec/dramatis/actor/become_spec.rb +17 -0
- data/spec/dramatis/actor/future_spec.rb +189 -0
- data/spec/dramatis/actor/name_spec.rb +141 -0
- data/spec/dramatis/actor/task_spec.rb +75 -0
- data/spec/dramatis/actor_spec.rb +492 -0
- data/spec/dramatis/dramatis_spec.rb +23 -0
- data/spec/dramatis/exc_spec.rb +78 -0
- data/spec/dramatis/runtime/gate_spec.rb +57 -0
- data/spec/dramatis/runtime/thread_pool.rb +30 -0
- data/spec/dramatis/shoes_spec.rb +11 -0
- data/spec/dramatis/simple_spec.rb +32 -0
- data/spec/exp_spec.rb +21 -0
- data/spec/simple2_spec.rb +36 -0
- data/spec/simple_spec.rb +30 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/thread_spec.rb +13 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- data/test/jruby_lm.rb +13 -0
- data/test/test.rb +19 -0
- data/test/test10.rb +43 -0
- data/test/test11.rb +45 -0
- data/test/test12.rb +60 -0
- data/test/test13.rb +71 -0
- data/test/test2.rb +12 -0
- data/test/test3.rb +10 -0
- data/test/test4.rb +29 -0
- data/test/test5.rb +8 -0
- data/test/test6.rb +32 -0
- data/test/test7.rb +48 -0
- data/test/test8.rb +133 -0
- data/test/test9.rb +105 -0
- data/test/test_exc.rb +22 -0
- metadata +180 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
module Dramatis::Actor; end
|
3
|
+
class Dramatis::Actor::Name; end
|
4
|
+
|
5
|
+
# An Dramatis::Actor::Name::Interface object provides the ability to
|
6
|
+
# modify the semantics of actor name and preform other actor-level operations on an
|
7
|
+
# actor. It is typically created via Dramatis.interface.
|
8
|
+
|
9
|
+
class Dramatis::Actor::Name::Interface
|
10
|
+
|
11
|
+
# call-seq:
|
12
|
+
# continue nil -> a_name
|
13
|
+
# continue { |retval| ... } -> a_name
|
14
|
+
# continue( :exception => lambda { |exception| ... } ) { |retval| ... } -> a_name
|
15
|
+
#
|
16
|
+
# In call cases, returns a new name with the specified continuation semantics.
|
17
|
+
#
|
18
|
+
# When passed a nil argument, returns a new actor name with a nil
|
19
|
+
# continuation such that when used in an actor method call, the call
|
20
|
+
# will return nil immediately. The return value from such a call is
|
21
|
+
# lost. Equivalent to and usually called as Dramatis.release.
|
22
|
+
#
|
23
|
+
# The second form sets up the block passed to the function as the
|
24
|
+
# continuation of the call. When the continuation task is received from the
|
25
|
+
# target actor, the block will be executed. From senders point of
|
26
|
+
# view, the block is an unnamed method: it will only be
|
27
|
+
# scheduled when the actor is not executing any other task.
|
28
|
+
#
|
29
|
+
# Currently it is not possible to gate off block continuations.
|
30
|
+
#
|
31
|
+
# The third example is a variant on the second and is used to
|
32
|
+
# provide a second block to receive an exception object if the actor
|
33
|
+
# method call results in an exception being thrown. Otherwise, the
|
34
|
+
# runtime will try to deliver exceptions to a dramatis_exception
|
35
|
+
# actor method if defined. Otherwise it will be recored by the
|
36
|
+
# runtime.
|
37
|
+
#
|
38
|
+
#--
|
39
|
+
# this stuff is either tricky or evil; i need to lookup
|
40
|
+
# variable look ordering for instance_eval
|
41
|
+
# i'm assuming lexical scope over object scope
|
42
|
+
#++
|
43
|
+
|
44
|
+
def continue options = {}, &continuation
|
45
|
+
raise "contradictory options passed to continue" \
|
46
|
+
if ( options == nil and continuation ) or
|
47
|
+
( options and !continuation )
|
48
|
+
a, o = @name.instance_eval { [ @actor, @options ] }
|
49
|
+
@name = Dramatis::Actor::Name.new a
|
50
|
+
@name.instance_eval do
|
51
|
+
@options = o.dup
|
52
|
+
@options[:continuation] = options == nil ? :none : continuation
|
53
|
+
options and @options[:exception] = options[:exception]
|
54
|
+
end
|
55
|
+
@name
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# call-seq:
|
60
|
+
# future -> a_name
|
61
|
+
#
|
62
|
+
# Returns a new actor name that when used in an actor method call will return a Dramatis::Future. Usually
|
63
|
+
# called via Dramatis.future rather than directly.
|
64
|
+
|
65
|
+
def future
|
66
|
+
a, o = @name.instance_eval { [ @actor, @options ] }
|
67
|
+
@name = Dramatis::Actor::Name.new a
|
68
|
+
@name.instance_eval do
|
69
|
+
@options = o.dup
|
70
|
+
@options[:continuation] = :future
|
71
|
+
end
|
72
|
+
@name
|
73
|
+
end
|
74
|
+
|
75
|
+
# Binds the actor identified by this name to supplied behavior,
|
76
|
+
# which should be a native ruby object. Can only be called on
|
77
|
+
# unbound actors, typically created with Dramatis::Actor.new(). The
|
78
|
+
# result of the call is the actor name of the actor. The
|
79
|
+
# continuation semantics of the call depend on the name like a
|
80
|
+
# normal actor method call.
|
81
|
+
|
82
|
+
def bind behavior
|
83
|
+
actor_send :bind, behavior
|
84
|
+
end
|
85
|
+
|
86
|
+
def url #:nodoc: not done
|
87
|
+
"http://something"
|
88
|
+
end
|
89
|
+
|
90
|
+
def exception exception #:nodoc: this should be private/protected
|
91
|
+
actor_send :exception, exception
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def continuation c, options
|
97
|
+
a, o = @name.instance_eval { [ @actor, @options ] }
|
98
|
+
@name = Dramatis::Actor::Name.new a
|
99
|
+
@name.instance_eval do
|
100
|
+
@actor.register_continuation c
|
101
|
+
@options = o.dup
|
102
|
+
@options[:continuation_send] = c.to_s
|
103
|
+
@options[:continuation] = :none
|
104
|
+
# FIX merge options, rather than cherry-pck
|
105
|
+
options[:call_thread] and @options[:call_thread] = options[:call_thread]
|
106
|
+
end
|
107
|
+
@name
|
108
|
+
end
|
109
|
+
|
110
|
+
def actor_send *args, &block
|
111
|
+
@name.instance_eval do
|
112
|
+
options = @options
|
113
|
+
if block
|
114
|
+
options = options.dup
|
115
|
+
options[:block] = block
|
116
|
+
end
|
117
|
+
@actor.actor_send args, options
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def initialize name #:nodoc:
|
122
|
+
raise "hell: " + name.inspect \
|
123
|
+
if !name or !name.kind_of? Dramatis::Actor::Name
|
124
|
+
@name = name
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
module Dramatis::Actor; end
|
3
|
+
class Dramatis::Actor::Name; end
|
4
|
+
|
5
|
+
require 'dramatis/actor'
|
6
|
+
|
7
|
+
# Dramatis::Actor::Names are proxy objects for actors. When a method
|
8
|
+
# is called on an actor name, the dramatis runtime creates and
|
9
|
+
# schedules an actor task to be run on the actors (virtual) thread.
|
10
|
+
|
11
|
+
# Dramatis::Actor::Name has no user-callable methods (except for the
|
12
|
+
# implicit method_missing). Other actor name operations are available
|
13
|
+
# through the Dramatis::Actor::Name::Interface object, accessible via
|
14
|
+
# Dramatis.interface.
|
15
|
+
|
16
|
+
class Dramatis::Actor::Name
|
17
|
+
|
18
|
+
def to_s_off #:nodoc:
|
19
|
+
method_missing :to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def dup #:nodoc:
|
23
|
+
raise "hell again"
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing *args, &block #:nodoc:
|
27
|
+
options = @options
|
28
|
+
if block
|
29
|
+
options = options.clone
|
30
|
+
options[:block] = block
|
31
|
+
end
|
32
|
+
@actor.object_send args, options
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def initialize actor #:nodoc:
|
38
|
+
raise "hell" if !actor or !actor.kind_of? Dramatis::Runtime::Actor
|
39
|
+
@actor = actor
|
40
|
+
@options = { :continuation => :rpc }
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
module Dramatis::Actor; end
|
3
|
+
|
4
|
+
require 'dramatis/runtime/actor'
|
5
|
+
|
6
|
+
# The Dramatis::Actor module is used to create actor classes and
|
7
|
+
# objects. An actor class can be created by mixing Dramatis::Actor, e.g.,
|
8
|
+
# class MyClass
|
9
|
+
# include Dramatis::Actor
|
10
|
+
# ...
|
11
|
+
# end
|
12
|
+
# or can be used to create so called _naked_ _actors_, e.g.,
|
13
|
+
# my_hash_actor = Dramatis::Actor.new Hash.new
|
14
|
+
#
|
15
|
+
# When mixed in to a class, Dramatis::Actor has two effects:
|
16
|
+
# 1. It causes new to return a Dramatis::Actor::Name rather than an object reference
|
17
|
+
# 1. It defines an actor method which can be used by the class to access its actor name and
|
18
|
+
# otherwise affect its actor semantics
|
19
|
+
|
20
|
+
module Dramatis::Actor
|
21
|
+
|
22
|
+
def self.included cls #:nodoc:
|
23
|
+
cls.instance_eval do
|
24
|
+
include Dramatis
|
25
|
+
end
|
26
|
+
class << cls
|
27
|
+
def new *args
|
28
|
+
new_actor = Dramatis::Runtime::Actor.new
|
29
|
+
object = allocate
|
30
|
+
eigenclass = ( class << object; self; end )
|
31
|
+
eigenclass.send :define_method, :actor,
|
32
|
+
( lambda { new_actor.object_interface } )
|
33
|
+
new_actor.bind object
|
34
|
+
new_actor.instance_eval { @gate.refuse :object }
|
35
|
+
new_actor.actor_send [ :object_initialize, *args ],
|
36
|
+
:continuation => :rpc
|
37
|
+
new_actor.name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if false # for docs only ...
|
43
|
+
|
44
|
+
# call-seq:
|
45
|
+
# actor -> an_interface
|
46
|
+
#
|
47
|
+
# actor provides classes that have mixed in Dramatis::Actor access
|
48
|
+
# to a Dramatis::Actor::Interface object by which they can access
|
49
|
+
# their actor name and other actor operations.
|
50
|
+
|
51
|
+
def actor; end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
# call-seq:
|
56
|
+
# new( *args, &block ) -> an_actor_name
|
57
|
+
# new( behavior = nil ) -> an_actor_name
|
58
|
+
#
|
59
|
+
# The first case is used when a class has mixed in
|
60
|
+
# Dramatis::Actor. In this case, the arguments are passed to the
|
61
|
+
# initialize of method of the including class like normal.
|
62
|
+
#
|
63
|
+
# The second case is used when creating so called <em>naked
|
64
|
+
# actors</em>, e.g.,
|
65
|
+
# my_hash = Dramatis::Actor.new Hash.new
|
66
|
+
# If no
|
67
|
+
# behavior is provided, the actor can be later bound to a behavior
|
68
|
+
# by calling Dramatis::Actor::Name::Interface.bind
|
69
|
+
#
|
70
|
+
# In all cases, new returns a Dramatis::Actor::Name proxy
|
71
|
+
# object.
|
72
|
+
|
73
|
+
def self.new behavior = nil
|
74
|
+
( Dramatis::Runtime::Actor.new behavior ).name
|
75
|
+
end
|
76
|
+
|
77
|
+
if false
|
78
|
+
def self.included cls #:nodoc:
|
79
|
+
pp caller(0)
|
80
|
+
warn "Dramatis::Actor included by #{cls}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.derived cls #:nodoc:
|
84
|
+
warn "Dramatis::Actor included by #{cls}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.extended cls #:nodoc:
|
88
|
+
warn "Dramatis::Actor included by #{cls}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.inherited cls #:nodoc:
|
92
|
+
warn "Dramatis::Actor included by #{cls}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
|
3
|
+
class Dramatis::Error < StandardError; end
|
4
|
+
|
5
|
+
# Exception raised when the runtime determines that deadlock has
|
6
|
+
# occurred: that is, there are no executing actors and that while
|
7
|
+
# there are one or more tasks queued for one or more actors, all are
|
8
|
+
# gated off. Note that case where there are no tasks at all signals
|
9
|
+
# normal termination.
|
10
|
+
#
|
11
|
+
# Inherits most methods from Exception.
|
12
|
+
#
|
13
|
+
# Dramatis::Deadlock (and eventually all Dramatis::Error subclasses)
|
14
|
+
# modify the backtrace generated by native language exceptions in
|
15
|
+
# order to put them in a more useful context:
|
16
|
+
# 1. They chain exceptions across threads using continuation information
|
17
|
+
# 1. They remove dramatis runtime internal information
|
18
|
+
# See raw_backtrace.
|
19
|
+
|
20
|
+
class Dramatis::Deadlock < Dramatis::Error; end
|
21
|
+
|
22
|
+
class Dramatis::Deadlock_ < Dramatis::Error
|
23
|
+
|
24
|
+
# call-seq:
|
25
|
+
# raw_backtrace -> array of strings
|
26
|
+
#
|
27
|
+
# raw_backtrace returns the unfiltered but still chained backtrace
|
28
|
+
# information. It is the concatenation of the backtrace from each
|
29
|
+
# actor call site as an exception propagates back the continuation
|
30
|
+
# chain.
|
31
|
+
def raw_backtrace
|
32
|
+
@raw_backtrace
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize string = nil, opts = {} #:nodoc:
|
36
|
+
super string
|
37
|
+
@next = opts[:next]
|
38
|
+
@raw_backtrace = []
|
39
|
+
end
|
40
|
+
|
41
|
+
# how things stand:
|
42
|
+
# r18 and r19 call set_backtrace at the raise
|
43
|
+
# jr never calls it; instead the base class synthesizes it
|
44
|
+
# at the first backtrace call
|
45
|
+
# as far as frames go, it seems lke jr elides sends sometimes
|
46
|
+
|
47
|
+
def set_backtrace *args #:nodoc:
|
48
|
+
# p "sbt!"
|
49
|
+
# pp args[0]
|
50
|
+
array = @raw_backtrace = args[0]
|
51
|
+
if @next
|
52
|
+
@raw_backtrace = @next.raw_backtrace + @raw_backtrace
|
53
|
+
array = @next.backtrace + array
|
54
|
+
end
|
55
|
+
|
56
|
+
# pp "raw", @raw_backtrace
|
57
|
+
|
58
|
+
# remove the scheduler
|
59
|
+
|
60
|
+
filtered = []
|
61
|
+
array.each do |v|
|
62
|
+
file, line, func = v.split ':'
|
63
|
+
file =~ %r{/lib/dramatis/} or ( filtered << v and next )
|
64
|
+
func =~ %r{\Wmaybe_deadlock\W} and next
|
65
|
+
file =~ %r{/runtime/scheduler} and func =~ %r{\Wrun\W} and break
|
66
|
+
filtered << v
|
67
|
+
end
|
68
|
+
|
69
|
+
# remove queueing delivery
|
70
|
+
|
71
|
+
array = filtered
|
72
|
+
filtered = []
|
73
|
+
skipping = false
|
74
|
+
array.each do |v|
|
75
|
+
|
76
|
+
# p v
|
77
|
+
|
78
|
+
file, line, func = v.split ':'
|
79
|
+
|
80
|
+
if file !~ %r{/lib/dramatis/}
|
81
|
+
# p "not skipping x"
|
82
|
+
skipping = false
|
83
|
+
filtered << v
|
84
|
+
next
|
85
|
+
end
|
86
|
+
|
87
|
+
if !skipping and
|
88
|
+
( ( file =~ %r{/runtime/task} and func =~ %r{\Wqueued\W} ) or
|
89
|
+
( file =~ %r{/runtime/actor} and func =~ %r{\Wsend\W} ) or # r18, r19
|
90
|
+
( file =~ %r{/runtime/actor} and func =~ %r{\Wdeliver\W} ) ) # jr
|
91
|
+
# p "skipping"
|
92
|
+
skipping = true
|
93
|
+
next
|
94
|
+
end
|
95
|
+
|
96
|
+
if file =~ %r{/dramatis/actor/name} and func =~ %r{\Wmethod_missing\W}
|
97
|
+
# p "not skipping"
|
98
|
+
skipping = false
|
99
|
+
next
|
100
|
+
end
|
101
|
+
|
102
|
+
skipping or filtered << v
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# pp "filt", filtered
|
107
|
+
# pp args[0]
|
108
|
+
super filtered
|
109
|
+
# super args[0]
|
110
|
+
end
|
111
|
+
|
112
|
+
def backtrace #:nodoc:
|
113
|
+
if @raw_backtrace.empty?
|
114
|
+
bt = super
|
115
|
+
if bt
|
116
|
+
set_backtrace bt
|
117
|
+
end
|
118
|
+
end
|
119
|
+
# p "d"
|
120
|
+
super
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
|
3
|
+
class Dramatis::Error < StandardError; end
|
4
|
+
|
5
|
+
# Exception raised when the runtime exits with uncaught exceptions.
|
6
|
+
|
7
|
+
class Dramatis::Error::Uncaught < Dramatis::Error
|
8
|
+
|
9
|
+
# combines the name of all uncaught exceptions.
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
super + ": " + @exceptions.join( " " )
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize exceptions #:nodoc:
|
16
|
+
@exceptions = exceptions
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
|
3
|
+
# The base class of all non-internal dramatis exceptions.
|
4
|
+
|
5
|
+
class Dramatis::Error < StandardError; end
|
6
|
+
|
7
|
+
# Raised when an attempt is made to create an interface object on an
|
8
|
+
# object that does not define an interface class.
|
9
|
+
|
10
|
+
class Dramatis::Error::Interface < StandardError; end
|
11
|
+
|
12
|
+
# Raised when an attempt is made to bind an already-bound actor.
|
13
|
+
|
14
|
+
class Dramatis::Error::Bind < Dramatis::Error; end
|
15
|
+
|
16
|
+
require 'dramatis/error/uncaught'
|
17
|
+
|
18
|
+
class Dramatis::Error < StandardError
|
19
|
+
|
20
|
+
def self._traceback exception, _next = nil
|
21
|
+
tb = exception.instance_variable_get :@_dramatis_traceback
|
22
|
+
if !tb
|
23
|
+
tb = exception.instance_variable_set( :@_dramatis_traceback,
|
24
|
+
Traceback.new( _next ) )
|
25
|
+
end
|
26
|
+
tb
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class Dramatis::Error::Traceback_
|
32
|
+
|
33
|
+
def initialize _next
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class Exception
|
39
|
+
|
40
|
+
alias _dramatis_set_backtrace set_backtrace
|
41
|
+
alias _dramatis_backtrace backtrace
|
42
|
+
|
43
|
+
def set_backtrace arg
|
44
|
+
# p "set back #{self}"
|
45
|
+
_dramatis_set_backtrace arg
|
46
|
+
end
|
47
|
+
|
48
|
+
def backtrace
|
49
|
+
# p "back #{self}"
|
50
|
+
if instance_variable_defined? :@_dramatis_raw_backtrace
|
51
|
+
filter @_dramatis_raw_backtrace
|
52
|
+
else
|
53
|
+
_dramatis_backtrace
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def _dramatis_reraise
|
58
|
+
# return
|
59
|
+
# p "reraise"
|
60
|
+
if @_dramatis_raw_backtrace
|
61
|
+
@_dramatis_raw_backtrace = backtrace + filter( caller )
|
62
|
+
else
|
63
|
+
@_dramatis_raw_backtrace = filter( backtrace ) + filter( caller )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter array
|
68
|
+
|
69
|
+
# pp "_", array
|
70
|
+
|
71
|
+
filtered = []
|
72
|
+
array.each do |v|
|
73
|
+
file, line, func = v.split ':'
|
74
|
+
file =~ %r{/lib/dramatis/} or ( filtered << v and next )
|
75
|
+
func =~ %r{\Wmaybe_deadlock\W} and next
|
76
|
+
file =~ %r{/runtime/scheduler} and func =~ %r{\Wrun\W} and break
|
77
|
+
filtered << v
|
78
|
+
end
|
79
|
+
|
80
|
+
# pp "0", filtered
|
81
|
+
|
82
|
+
# remove queueing delivery
|
83
|
+
|
84
|
+
array = filtered
|
85
|
+
filtered = []
|
86
|
+
skipping = false
|
87
|
+
array.each do |v|
|
88
|
+
|
89
|
+
# p v
|
90
|
+
|
91
|
+
file, line, func = v.split ':'
|
92
|
+
|
93
|
+
if file !~ %r{/lib/dramatis/}
|
94
|
+
# p "not skipping x"
|
95
|
+
skipping = false
|
96
|
+
filtered << v
|
97
|
+
next
|
98
|
+
end
|
99
|
+
|
100
|
+
if !skipping and
|
101
|
+
( ( file =~ %r{/runtime/task} and func =~ %r{\Wqueued\W} ) or
|
102
|
+
( file =~ %r{/runtime/actor} and func =~ %r{\Wsend\W} ) or # r18, r19
|
103
|
+
( file =~ %r{/runtime/actor} and func =~ %r{\Wdeliver\W} ) ) # jr
|
104
|
+
# p "skipping"
|
105
|
+
skipping = true
|
106
|
+
next
|
107
|
+
end
|
108
|
+
|
109
|
+
if file =~ %r{/dramatis/actor/name} and func =~ %r{\Wmethod_missing\W}
|
110
|
+
# p "not skipping"
|
111
|
+
skipping = false
|
112
|
+
next
|
113
|
+
end
|
114
|
+
|
115
|
+
skipping or filtered << v
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
# pp "filt", filtered
|
120
|
+
# pp args[0]
|
121
|
+
filtered
|
122
|
+
# super args[0]
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
class Dramatis::Future; end
|
3
|
+
|
4
|
+
# A Dramatis::Future::Interface object provides the ability to
|
5
|
+
# observe and access the semantics of a future. It is typically
|
6
|
+
# created via Dramatis.interface.
|
7
|
+
|
8
|
+
class Dramatis::Future::Interface
|
9
|
+
|
10
|
+
# Returns the native value of the future. If the value of the future
|
11
|
+
# is not yet available, the method blocks (with rpc gating
|
12
|
+
# semantics) until it is.
|
13
|
+
#
|
14
|
+
# In many cases, this method is not necessary since the
|
15
|
+
# method_missing method on the future will catch most attempts to
|
16
|
+
# accesses the value. This method may be necessary in corner cases,
|
17
|
+
# for example when usingconditionals, conversions, and
|
18
|
+
# metaprogramming.
|
19
|
+
|
20
|
+
def value
|
21
|
+
@future.instance_eval do
|
22
|
+
@continuation.value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if the future may be evaluated without
|
27
|
+
# blocking. Returns false if the value is not yet available.
|
28
|
+
#
|
29
|
+
# Once a future is ready it cannot become unready, so once ready? returns
|
30
|
+
# true, it will always be true and value access will never block.
|
31
|
+
|
32
|
+
def ready?
|
33
|
+
@future.instance_eval do
|
34
|
+
@continuation.ready?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize *args, &block #:nodoc:
|
39
|
+
@future = args.shift
|
40
|
+
@args = args
|
41
|
+
@block = block
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Dramatis; end
|
2
|
+
|
3
|
+
# Dramatis::Futures are proxy objects for the values returned from
|
4
|
+
# actor method calls made with future continuations. When a method is
|
5
|
+
# called on a future, the runtime checks to see if the future has been
|
6
|
+
# evaluated and returned from the actor that executed the task. If it
|
7
|
+
# has, the method is executed on the returned value as if the proxy
|
8
|
+
# object was not there.
|
9
|
+
#
|
10
|
+
# If the task with the future continuation has not yet completed or
|
11
|
+
# the continuation task has not yet been run, the method called on
|
12
|
+
# the proxy is suspended until the reply is received. Thus, methods on
|
13
|
+
# futures sometimes but not always block. If they block, they have
|
14
|
+
# normal continuation gating semantics.
|
15
|
+
#
|
16
|
+
# Dramatis::Future has no user-callable methods (except for the
|
17
|
+
# implicit method_missing). Other future operations are available
|
18
|
+
# through the Dramatis::Future::Interface object, accessible via
|
19
|
+
# Dramatis.interface.
|
20
|
+
|
21
|
+
class Dramatis::Future
|
22
|
+
|
23
|
+
def method_missing *args #:nodoc:
|
24
|
+
@continuation.value.send( *args )
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize continuation #:nodoc:
|
28
|
+
@continuation = continuation
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|