dramatis 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|