dramatis 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +1 -2
- data/README.txt +1 -1
- data/examples/pingpong/{pingpong.txt → ruby.txt} +4 -5
- data/lib/dramatis/actor/interface.rb +11 -0
- data/lib/dramatis/actor/name/interface.rb +5 -3
- data/lib/dramatis/deadlock.rb +2 -114
- data/lib/dramatis/error.rb +17 -26
- data/lib/dramatis/error/uncaught.rb +3 -0
- data/lib/dramatis/future/interface.rb +7 -1
- data/lib/dramatis/runtime.rb +30 -9
- data/lib/dramatis/runtime/task.rb +3 -1
- data/lib/dramatis/runtime/thread_pool.rb +1 -1
- data/lib/dramatis/version.rb +1 -1
- metadata +4 -5
- data/log/debug.log +0 -0
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -32,7 +32,7 @@ examples/im/single/fox.rb
|
|
32
32
|
examples/im/single/wxchat.rb
|
33
33
|
examples/pingpong/actor.rb
|
34
34
|
examples/pingpong/actor_rec.rb
|
35
|
-
examples/pingpong/
|
35
|
+
examples/pingpong/ruby.txt
|
36
36
|
examples/pingpong/scala.rb
|
37
37
|
examples/pingpong/serial.rb
|
38
38
|
examples/pretty.txt
|
@@ -76,7 +76,6 @@ lib/dramatis/runtime/timer.rb
|
|
76
76
|
lib/dramatis/shoes.rb
|
77
77
|
lib/dramatis/shoes/runtime.rb
|
78
78
|
lib/dramatis/version.rb
|
79
|
-
log/debug.log
|
80
79
|
script/destroy
|
81
80
|
script/generate
|
82
81
|
script/txt2html
|
data/README.txt
CHANGED
@@ -10,7 +10,7 @@ An actor library for dynamic languages like Ruby and Python.
|
|
10
10
|
|
11
11
|
dramatis provides a library for writing concurrent programs using the actor programming model.
|
12
12
|
|
13
|
-
This is an early version, the first release with packaging (a gem for ruby,
|
13
|
+
This is an early version, the first release with packaging (a gem for ruby, distutils for python).
|
14
14
|
|
15
15
|
It's available on github to download and does come with documentation, a tutorial, and several examples, all of which (mostly) work, so it's stable enough to being to play with.
|
16
16
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
h1. PingPong tutorial
|
1
|
+
h1. PingPong tutorial (Ruby version)
|
2
2
|
|
3
3
|
h2. PingPong
|
4
4
|
|
@@ -148,7 +148,7 @@ dramatis has other continuation types, as will be shown below. dramatis continua
|
|
148
148
|
|
149
149
|
h2. Concurrent PingPong
|
150
150
|
|
151
|
-
So, with some background on actors, let return to our example. When we mixed in @Dramatis::Actor@, what changed in our program? First, lets look at the
|
151
|
+
So, with some background on actors, let return to our example. When we mixed in @Dramatis::Actor@, what changed in our program? First, lets look at the lines that created our actors:
|
152
152
|
<pre><code class="ruby">
|
153
153
|
ping = PingPong.new "ping"
|
154
154
|
pong = PingPong.new "pong"
|
@@ -169,7 +169,7 @@ h2. _pass by value_
|
|
169
169
|
|
170
170
|
Another actor issue comes in to play at this step. Actor systems are generally _pass by value_. That is, they send object values or copies, rather than references to objects. Nothing is shared between the caller and the callee. In pure actor systems, there are only values (which include actor names) and actors so nothing except actor state is mutable and actors are internally serial.
|
171
171
|
|
172
|
-
In this sense, dramatis is not a pure actor system. Since it's only a library on top of a non-actor language and virtual machine, this is pretty much guaranteed: to make a pure actor system would generally require changing either one or both. In addition to immutable values like numbers, dramatis programs have all the
|
172
|
+
In this sense, dramatis is not a pure actor system. Since it's only a library on top of a non-actor language and virtual machine, this is pretty much guaranteed: to make a pure actor system would generally require changing either one or both. In addition to immutable values like numbers, dramatis programs have all the mutable objects found in non-concurrent program. dramatis provides mechanisms for for managing concurrency but cannot guarantee that shared objects will not have concurrent conflicts if they are used.
|
173
173
|
|
174
174
|
At this time, dramatis does not specify whether actor method call arguments will be copied or not. Thus some care is required when considering objects passed to actor methods.
|
175
175
|
|
@@ -215,8 +215,7 @@ What we need is a way to call a method but not wait around for the results (if y
|
|
215
215
|
|
216
216
|
In dramatis, we make this non-waiting call by writing
|
217
217
|
<pre><code class="ruby">
|
218
|
-
|
219
|
-
release( partner ).pingpong count-1, self
|
218
|
+
release( partner ).pingpong count-1, self
|
220
219
|
</code></pre>
|
221
220
|
@release@ (or @Dramatis.release@ if you haven't used @include Dramatis@) takes an actor name and returns a new name. This new name acts slightly differently than the original name. It _releases_, if you will, the task created by the call. That is, it doesn't ask the task to return value and the method call returns immediately. Another way of looking at is that rather than providing the current continuation, it provides a nil continuation.
|
222
221
|
|
@@ -72,6 +72,9 @@ class Dramatis::Actor::Interface
|
|
72
72
|
@actor.gate.always( ( [ :object ] + Array( args ) ), value )
|
73
73
|
end
|
74
74
|
|
75
|
+
# call-seq:
|
76
|
+
# enable_call_threading -> nil
|
77
|
+
#
|
75
78
|
# Enables call threading for actor method calls made by this
|
76
79
|
# actor. When call threading is enabled, method gating is modified
|
77
80
|
# such that recursive and co-recursive calls are allowed. Normally
|
@@ -82,14 +85,21 @@ class Dramatis::Actor::Interface
|
|
82
85
|
|
83
86
|
def enable_call_threading
|
84
87
|
@actor.enable_call_threading
|
88
|
+
nil
|
85
89
|
end
|
86
90
|
|
91
|
+
# call-seq:
|
92
|
+
# name -> actor_name_of_actor
|
93
|
+
#
|
87
94
|
# Returns the actor name for the object.
|
88
95
|
|
89
96
|
def name
|
90
97
|
@actor.name
|
91
98
|
end
|
92
99
|
|
100
|
+
# call-seq:
|
101
|
+
# yield -> nil
|
102
|
+
#
|
93
103
|
# Yields the actor to allow other tasks to be executed.
|
94
104
|
# Currently, messages are handled FIFO so the yield will
|
95
105
|
# return when all the messages received up to the point of the
|
@@ -99,6 +109,7 @@ class Dramatis::Actor::Interface
|
|
99
109
|
def yield
|
100
110
|
@actor.actor_send [ :yield ], :continuation => :rpc,
|
101
111
|
:nonblocking => true
|
112
|
+
nil
|
102
113
|
end
|
103
114
|
|
104
115
|
def timeout value, *args #:nodoc: not ready
|
@@ -2,8 +2,8 @@ module Dramatis; end
|
|
2
2
|
module Dramatis::Actor; end
|
3
3
|
class Dramatis::Actor::Name; end
|
4
4
|
|
5
|
-
#
|
6
|
-
# modify the semantics of actor name and
|
5
|
+
# A Dramatis::Actor::Name::Interface object provides the ability to
|
6
|
+
# modify the semantics of actor name and perform other actor-level operations on an
|
7
7
|
# actor. It is typically created via Dramatis.interface.
|
8
8
|
|
9
9
|
class Dramatis::Actor::Name::Interface
|
@@ -55,7 +55,6 @@ class Dramatis::Actor::Name::Interface
|
|
55
55
|
@name
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
58
|
# call-seq:
|
60
59
|
# future -> a_name
|
61
60
|
#
|
@@ -72,6 +71,9 @@ class Dramatis::Actor::Name::Interface
|
|
72
71
|
@name
|
73
72
|
end
|
74
73
|
|
74
|
+
# call-seq:
|
75
|
+
# bind( behavior ) -> actor_name
|
76
|
+
#
|
75
77
|
# Binds the actor identified by this name to supplied behavior,
|
76
78
|
# which should be a native ruby object. Can only be called on
|
77
79
|
# unbound actors, typically created with Dramatis::Actor.new(). The
|
data/lib/dramatis/deadlock.rb
CHANGED
@@ -3,121 +3,9 @@ module Dramatis; end
|
|
3
3
|
class Dramatis::Error < StandardError; end
|
4
4
|
|
5
5
|
# Exception raised when the runtime determines that deadlock has
|
6
|
-
# occurred: that is, there are no executing actors and
|
6
|
+
# occurred: that is, there are no executing actors and while
|
7
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
|
8
|
+
# gated off. Note that case where there are no tasks at all indicates
|
9
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
10
|
|
20
11
|
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
|
data/lib/dramatis/error.rb
CHANGED
@@ -15,35 +15,26 @@ class Dramatis::Error::Bind < Dramatis::Error; end
|
|
15
15
|
|
16
16
|
require 'dramatis/error/uncaught'
|
17
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_
|
18
|
+
class Dramatis::Error < StandardError; end
|
32
19
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
20
|
+
# Dramatis modifies exceptions thrown within the context of an actor rpc call,
|
21
|
+
# combinding the the backtraces generated by native language exceptions in
|
22
|
+
# order to put them in a more useful context:
|
23
|
+
# 1. Exceptions are chained across threads using continuation information
|
24
|
+
# 1. Dramatis runtime internal call frames are removed
|
37
25
|
|
38
26
|
class Exception
|
39
27
|
|
40
|
-
|
41
|
-
alias _dramatis_backtrace backtrace
|
28
|
+
# :stopdoc:
|
29
|
+
alias _dramatis_backtrace backtrace
|
30
|
+
# :startdoc:
|
42
31
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
32
|
+
# call-seq:
|
33
|
+
# backtrace -> array of strings
|
34
|
+
#
|
35
|
+
# dramatis wraps and filters the native exception backtrace method in order to
|
36
|
+
# augment the backtrace to follow the backtrace through actor rpc calls.
|
37
|
+
#
|
47
38
|
|
48
39
|
def backtrace
|
49
40
|
# p "back #{self}"
|
@@ -54,7 +45,7 @@ class Exception
|
|
54
45
|
end
|
55
46
|
end
|
56
47
|
|
57
|
-
def _dramatis_reraise
|
48
|
+
def _dramatis_reraise #:nodoc:
|
58
49
|
# return
|
59
50
|
# p "reraise"
|
60
51
|
if @_dramatis_raw_backtrace
|
@@ -64,7 +55,7 @@ class Exception
|
|
64
55
|
end
|
65
56
|
end
|
66
57
|
|
67
|
-
def filter array
|
58
|
+
def filter array #:nodoc:
|
68
59
|
|
69
60
|
# pp "_", array
|
70
61
|
|
@@ -7,6 +7,9 @@ class Dramatis::Future; end
|
|
7
7
|
|
8
8
|
class Dramatis::Future::Interface
|
9
9
|
|
10
|
+
# call-seq:
|
11
|
+
# value -> object
|
12
|
+
#
|
10
13
|
# Returns the native value of the future. If the value of the future
|
11
14
|
# is not yet available, the method blocks (with rpc gating
|
12
15
|
# semantics) until it is.
|
@@ -14,7 +17,7 @@ class Dramatis::Future::Interface
|
|
14
17
|
# In many cases, this method is not necessary since the
|
15
18
|
# method_missing method on the future will catch most attempts to
|
16
19
|
# accesses the value. This method may be necessary in corner cases,
|
17
|
-
# for example when
|
20
|
+
# for example when using conditionals, conversions, and
|
18
21
|
# metaprogramming.
|
19
22
|
|
20
23
|
def value
|
@@ -23,6 +26,9 @@ class Dramatis::Future::Interface
|
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
# call-seq:
|
30
|
+
# ready? -> boolean
|
31
|
+
#
|
26
32
|
# Returns true if the future may be evaluated without
|
27
33
|
# blocking. Returns false if the value is not yet available.
|
28
34
|
#
|
data/lib/dramatis/runtime.rb
CHANGED
@@ -9,16 +9,22 @@ require 'thread'
|
|
9
9
|
|
10
10
|
class Dramatis::Runtime
|
11
11
|
|
12
|
+
# call-seq:
|
13
|
+
# current -> current_runtime_object
|
14
|
+
#
|
12
15
|
# Returns a reference to the current Dramatis::Runtime object.
|
13
16
|
|
14
17
|
def self.current
|
15
18
|
@@current ||= self.new
|
16
19
|
end
|
17
20
|
|
21
|
+
# call-seq:
|
22
|
+
# reset -> nil
|
23
|
+
#
|
18
24
|
# Resets the current runtime instance. Note that this method hard
|
19
|
-
# resets counters and
|
20
|
-
# idea. It is typical only used in unit test
|
21
|
-
# failing tests from cascading.
|
25
|
+
# resets counters and ignores exceptions which is generally a bad
|
26
|
+
# idea. It is typical only used in unit test and spec "after"
|
27
|
+
# methods to keep failing tests from cascading.
|
22
28
|
|
23
29
|
def self.reset
|
24
30
|
# this swallows exceptions: it's assumed to be used to clean up
|
@@ -32,10 +38,13 @@ class Dramatis::Runtime
|
|
32
38
|
@@current = nil
|
33
39
|
end
|
34
40
|
|
41
|
+
# call-seq:
|
42
|
+
# quiesce -> nil
|
43
|
+
#
|
35
44
|
# Causes the runtime to suspend the current thread until there are
|
36
45
|
# no more tasks that can be executed. If no tasks remain, returns
|
37
46
|
# normally. If tasks remain but are gated off,
|
38
|
-
#
|
47
|
+
# Dramatis::Deadlock is raised.
|
39
48
|
#
|
40
49
|
# As a side effect, this method releases the current actor to
|
41
50
|
# process messages but does not change the task gate.
|
@@ -62,7 +71,10 @@ class Dramatis::Runtime
|
|
62
71
|
end
|
63
72
|
end
|
64
73
|
|
65
|
-
#
|
74
|
+
# call-seq:
|
75
|
+
# exceptions -> array_of_exceptions
|
76
|
+
#
|
77
|
+
# Returns the list of exceptions that were not caught by an actor.
|
66
78
|
|
67
79
|
def exceptions
|
68
80
|
result = nil
|
@@ -72,9 +84,12 @@ class Dramatis::Runtime
|
|
72
84
|
result
|
73
85
|
end
|
74
86
|
|
75
|
-
#
|
87
|
+
# call-seq:
|
88
|
+
# clear_exceptions -> nil
|
89
|
+
#
|
90
|
+
# Clears the list of uncaught exceptions. Used in unit tests and specs to
|
76
91
|
# clear expected exceptions. If exceptions are raised and not
|
77
|
-
#
|
92
|
+
# cleared, they will be raised at the end of the program via a
|
78
93
|
# Dramatis::Error::Uncaught.
|
79
94
|
|
80
95
|
def clear_exceptions
|
@@ -101,13 +116,19 @@ class Dramatis::Runtime
|
|
101
116
|
end
|
102
117
|
end
|
103
118
|
|
104
|
-
#
|
105
|
-
#
|
119
|
+
# call-seq:
|
120
|
+
# warnings = boolean -> boolean
|
121
|
+
#
|
122
|
+
# Enables or disables printing warnings, e.g., when uncaught
|
123
|
+
# exceptions are detected. Returns the value passed.
|
106
124
|
|
107
125
|
def warnings= value
|
108
126
|
@warnings = value
|
109
127
|
end
|
110
128
|
|
129
|
+
# call-seq:
|
130
|
+
# warnings? -> boolean
|
131
|
+
#
|
111
132
|
# Returns true if warnings are enabled.
|
112
133
|
|
113
134
|
def warnings?
|
@@ -58,7 +58,9 @@ class Dramatis::Runtime::Task #:nodoc: all
|
|
58
58
|
when :none
|
59
59
|
@continuation = Continuation::None.new name, @call_thread
|
60
60
|
when :rpc
|
61
|
-
@continuation = Continuation::RPC.new name,
|
61
|
+
@continuation = Continuation::RPC.new name,
|
62
|
+
@call_thread,
|
63
|
+
options[:nonblocking]
|
62
64
|
when :future
|
63
65
|
@continuation = Continuation::Future.new name, @call_thread
|
64
66
|
when Proc
|
data/lib/dramatis/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dramatis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Parkes
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-06-
|
12
|
+
date: 2008-06-06 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -26,7 +26,7 @@ extra_rdoc_files:
|
|
26
26
|
- Manifest.txt
|
27
27
|
- README.txt
|
28
28
|
- examples/README.txt
|
29
|
-
- examples/pingpong/
|
29
|
+
- examples/pingpong/ruby.txt
|
30
30
|
- examples/pretty.txt
|
31
31
|
- examples/telephone/3esl.txt
|
32
32
|
files:
|
@@ -64,7 +64,7 @@ files:
|
|
64
64
|
- examples/im/single/wxchat.rb
|
65
65
|
- examples/pingpong/actor.rb
|
66
66
|
- examples/pingpong/actor_rec.rb
|
67
|
-
- examples/pingpong/
|
67
|
+
- examples/pingpong/ruby.txt
|
68
68
|
- examples/pingpong/scala.rb
|
69
69
|
- examples/pingpong/serial.rb
|
70
70
|
- examples/pretty.txt
|
@@ -108,7 +108,6 @@ files:
|
|
108
108
|
- lib/dramatis/shoes.rb
|
109
109
|
- lib/dramatis/shoes/runtime.rb
|
110
110
|
- lib/dramatis/version.rb
|
111
|
-
- log/debug.log
|
112
111
|
- script/destroy
|
113
112
|
- script/generate
|
114
113
|
- script/txt2html
|
data/log/debug.log
DELETED
File without changes
|