dramatis 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/History.txt +7 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +119 -0
  4. data/README.txt +57 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +70 -0
  7. data/config/requirements.rb +17 -0
  8. data/examples/README.txt +20 -0
  9. data/examples/auction.rb +90 -0
  10. data/examples/bank/bank.rb +7 -0
  11. data/examples/bank/bank_test.rb +7 -0
  12. data/examples/exception.rb +40 -0
  13. data/examples/fib/conservative.rb +50 -0
  14. data/examples/fib/future.rb +5 -0
  15. data/examples/fib/original.rb +33 -0
  16. data/examples/fib/threads.rb +51 -0
  17. data/examples/im/distributed/chat/client.rb +49 -0
  18. data/examples/im/distributed/chat/screen/fox.rb +92 -0
  19. data/examples/im/distributed/chat/screen.rb +11 -0
  20. data/examples/im/distributed/chat/server.rb +72 -0
  21. data/examples/im/distributed/chat.rb +5 -0
  22. data/examples/im/distributed/client.rb +9 -0
  23. data/examples/im/distributed/run.rb +18 -0
  24. data/examples/im/distributed/server.rb +11 -0
  25. data/examples/im/single/chat/client.rb +50 -0
  26. data/examples/im/single/chat/screen/fox.rb +96 -0
  27. data/examples/im/single/chat/screen/wxs.rb +63 -0
  28. data/examples/im/single/chat/screen.rb +11 -0
  29. data/examples/im/single/chat/server.rb +72 -0
  30. data/examples/im/single/chat.rb +5 -0
  31. data/examples/im/single/fox.rb +18 -0
  32. data/examples/im/single/wxchat.rb +19 -0
  33. data/examples/pingpong/actor.rb +33 -0
  34. data/examples/pingpong/actor_rec.rb +34 -0
  35. data/examples/pingpong/pingpong.txt +315 -0
  36. data/examples/pingpong/scala.rb +41 -0
  37. data/examples/pingpong/serial.rb +26 -0
  38. data/examples/pretty.txt +108 -0
  39. data/examples/telephone/.irbrc +2 -0
  40. data/examples/telephone/3esl.txt +21877 -0
  41. data/examples/telephone/fifth/kid.rb +36 -0
  42. data/examples/telephone/fifth/run.rb +26 -0
  43. data/examples/telephone/first/kid.rb +31 -0
  44. data/examples/telephone/first/run.rb +20 -0
  45. data/examples/telephone/fourth/kid.rb +31 -0
  46. data/examples/telephone/fourth/run.rb +26 -0
  47. data/examples/telephone/mangler.rb +53 -0
  48. data/examples/telephone/second/kid.rb +26 -0
  49. data/examples/telephone/second/run.rb +20 -0
  50. data/examples/telephone/seventh/kid.rb +40 -0
  51. data/examples/telephone/seventh/run.rb +35 -0
  52. data/examples/telephone/seventh/test.rb +28 -0
  53. data/examples/telephone/seventh/test2.rb +10 -0
  54. data/examples/telephone/sixth/kid.rb +39 -0
  55. data/examples/telephone/sixth/run.rb +26 -0
  56. data/examples/telephone/third/kid.rb +31 -0
  57. data/examples/telephone/third/run.rb +21 -0
  58. data/lib/dramatis/actor/interface.rb +118 -0
  59. data/lib/dramatis/actor/name/interface.rb +128 -0
  60. data/lib/dramatis/actor/name.rb +44 -0
  61. data/lib/dramatis/actor.rb +96 -0
  62. data/lib/dramatis/deadlock.rb +123 -0
  63. data/lib/dramatis/error/uncaught.rb +19 -0
  64. data/lib/dramatis/error.rb +125 -0
  65. data/lib/dramatis/future/interface.rb +45 -0
  66. data/lib/dramatis/future.rb +32 -0
  67. data/lib/dramatis/runtime/actor/main.rb +3 -0
  68. data/lib/dramatis/runtime/actor.rb +294 -0
  69. data/lib/dramatis/runtime/gate.rb +244 -0
  70. data/lib/dramatis/runtime/scheduler.rb +374 -0
  71. data/lib/dramatis/runtime/task.rb +390 -0
  72. data/lib/dramatis/runtime/thread_pool.rb +149 -0
  73. data/lib/dramatis/runtime/timer.rb +5 -0
  74. data/lib/dramatis/runtime.rb +129 -0
  75. data/lib/dramatis/shoes/runtime.rb +7 -0
  76. data/lib/dramatis/shoes.rb +14 -0
  77. data/lib/dramatis/version.rb +8 -0
  78. data/lib/dramatis.rb +73 -0
  79. data/log/debug.log +0 -0
  80. data/script/destroy +14 -0
  81. data/script/generate +14 -0
  82. data/script/txt2html +74 -0
  83. data/setup.rb +1585 -0
  84. data/spec/dramatis/actor/become_spec.rb +17 -0
  85. data/spec/dramatis/actor/future_spec.rb +189 -0
  86. data/spec/dramatis/actor/name_spec.rb +141 -0
  87. data/spec/dramatis/actor/task_spec.rb +75 -0
  88. data/spec/dramatis/actor_spec.rb +492 -0
  89. data/spec/dramatis/dramatis_spec.rb +23 -0
  90. data/spec/dramatis/exc_spec.rb +78 -0
  91. data/spec/dramatis/runtime/gate_spec.rb +57 -0
  92. data/spec/dramatis/runtime/thread_pool.rb +30 -0
  93. data/spec/dramatis/shoes_spec.rb +11 -0
  94. data/spec/dramatis/simple_spec.rb +32 -0
  95. data/spec/exp_spec.rb +21 -0
  96. data/spec/simple2_spec.rb +36 -0
  97. data/spec/simple_spec.rb +30 -0
  98. data/spec/spec.opts +0 -0
  99. data/spec/spec_helper.rb +26 -0
  100. data/spec/thread_spec.rb +13 -0
  101. data/tasks/deployment.rake +34 -0
  102. data/tasks/environment.rake +7 -0
  103. data/tasks/rspec.rake +21 -0
  104. data/tasks/website.rake +17 -0
  105. data/test/jruby_lm.rb +13 -0
  106. data/test/test.rb +19 -0
  107. data/test/test10.rb +43 -0
  108. data/test/test11.rb +45 -0
  109. data/test/test12.rb +60 -0
  110. data/test/test13.rb +71 -0
  111. data/test/test2.rb +12 -0
  112. data/test/test3.rb +10 -0
  113. data/test/test4.rb +29 -0
  114. data/test/test5.rb +8 -0
  115. data/test/test6.rb +32 -0
  116. data/test/test7.rb +48 -0
  117. data/test/test8.rb +133 -0
  118. data/test/test9.rb +105 -0
  119. data/test/test_exc.rb +22 -0
  120. metadata +180 -0
@@ -0,0 +1,294 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ require 'dramatis/runtime/task'
5
+ require 'dramatis/runtime/gate'
6
+ require 'dramatis/runtime/timer'
7
+ require 'dramatis/actor/interface'
8
+ require 'dramatis/actor/name'
9
+ require 'thread'
10
+
11
+ begin require 'pp'; rescue Exception; end
12
+
13
+ class Dramatis::Runtime::Actor #:nodoc: all
14
+
15
+ def name
16
+ @name ||= Dramatis::Actor::Name.new self
17
+ end
18
+
19
+ attr_reader :object_interface
20
+ attr_reader :object
21
+ attr_reader :gate
22
+ attr_reader :call_thread
23
+
24
+ def initialize object = nil
25
+ @call_threading = false
26
+ @call_thread = nil
27
+ @object = object
28
+ @gate = Dramatis::Runtime::Gate.new
29
+ if !object
30
+ @gate.refuse :object
31
+ end
32
+ @gate.always( ( [ :object, :dramatis_exception ] ), true )
33
+ blocked!
34
+ @queue = []
35
+ @mutex = Mutex.new
36
+ @continuations = {}
37
+ @object_interface = Dramatis::Actor::Interface.new self
38
+ Dramatis::Runtime::Scheduler.current << self
39
+ end
40
+
41
+ def call_threading?
42
+ @call_threading
43
+ end
44
+
45
+ def enable_call_threading
46
+ @call_threading = true
47
+ end
48
+
49
+ def current_call_thread? that
50
+ # warn "current_call_thread? #{@call_thread} #{(@call_thread and (@call_thread == that)).inspect} #{that}"
51
+ @call_thread and @call_thread == that
52
+ end
53
+
54
+ def object_initialize *args
55
+ @gate.accept :object
56
+ @object.send :initialize, *args
57
+ end
58
+
59
+ def yield; end
60
+
61
+ def bind object
62
+ raise Dramatis::Error::Bind if @object
63
+ @object = object
64
+ @gate.accept :object
65
+ name
66
+ end
67
+
68
+ def exception exception
69
+ if @object.respond_to? :dramatis_exception
70
+ @object.dramatis_exception exception
71
+ else
72
+ Dramatis::Runtime.current.exception exception
73
+ end
74
+ self
75
+ end
76
+
77
+ def deadlock e
78
+ tasks = nil
79
+ @mutex.synchronize do
80
+ tasks = @queue.dup
81
+ @queue.clear
82
+ end
83
+ tasks.each { |task| task.exception e }
84
+ end
85
+
86
+ def register_continuation c
87
+ # p "selfish", self, @continuations
88
+ # pp "csr", c.to_s
89
+ @continuations[c.to_s] = c
90
+ end
91
+
92
+ def actor_send args, opts
93
+ common_send :actor, args, opts
94
+ end
95
+
96
+ def object_send args, opts
97
+ t = nil
98
+ if opts[:continuation_send]
99
+ t = :continuation
100
+ args.unshift opts[:continuation_send]
101
+ else
102
+ t = :object
103
+ end
104
+ common_send t, args, opts
105
+ end
106
+
107
+ def common_send dest, args, opts
108
+
109
+ # warn "common send #{self} #{dest} #{args[0]}"
110
+ # warn "common send #{self} #{dest} #{args.join(' ')} #{opts.to_a.join(' ' )}"
111
+
112
+ task = Dramatis::Runtime::Task.new( self, dest, args, opts )
113
+
114
+ # warn "#{task.type} #{task.method}"
115
+ # warn "#{self} #{Thread.current} common send r? #{runnable?} g? #{@gate.accepts?( *( [ task.type, task.method ] + task.arguments ) ) } q #{@queue.length}"
116
+ @mutex.synchronize do
117
+ # FIX arguments to gate
118
+ if !runnable? and ( @gate.accepts?( *( [ task.type, task.method ] + task.arguments ) ) or current_call_thread?( task.call_thread ) )
119
+ runnable!
120
+ Dramatis::Runtime::Scheduler.current.schedule task
121
+ else
122
+ # warn "+>schd #{self} #{@queue.join(' ')}"
123
+ @queue << task
124
+ # warn "+<schd #{self} #{@queue.join(' ')}"
125
+ end
126
+ end
127
+
128
+ task.queued
129
+
130
+ end
131
+
132
+ def deliver dest, args, continuation, call_thread
133
+ old_call_thread = @call_thread
134
+ begin
135
+ @call_thread = call_thread
136
+ method = args.shift
137
+ # warn "switch " + dest.to_s + " " + method.to_s
138
+ result =
139
+ case dest
140
+ when :actor
141
+ # FIX: do name folding; needs test
142
+ self.send method, *args
143
+ # p "sent actor #{method}"
144
+ when :object
145
+ # p "send object #{@object} #{method} #{args.length}"
146
+ v = @object.send method, *args
147
+ if v.object_id == @object.object_id
148
+ v = name
149
+ end
150
+ # p "sent object #{method}"
151
+ v
152
+ when :continuation
153
+ # FIX: name folding?
154
+ # p "send continuation #{method}"
155
+ continuation_name = method
156
+ # warn "c is #{continuation_name}"
157
+ c = @continuations[continuation_name]
158
+ # pp "cs", @continuations.keys
159
+ raise "hell 0 #{Thread.current}" if !c
160
+ method = args.shift
161
+ method = case method
162
+ when :result; :continuation_result
163
+ when :exception; :continuation_exception
164
+ else; raise "hell *"
165
+ end
166
+ # pp c.to_s, "send", method, args
167
+ c.send method, *args
168
+ @continuations.delete continuation_name
169
+ # pp "csd", continuation_name, @continuations.keys
170
+ else
171
+ raise "hell 1: " + @dest.to_s
172
+ end
173
+ # p "call c '#{result}'"
174
+ # p continuation.to_s
175
+ continuation.result result
176
+ # p "called c #{result}"
177
+ rescue Exception => exception
178
+ # pp "0 exception ", exception
179
+ # pp exception.backtrace
180
+ begin
181
+ continuation.exception exception
182
+ rescue Exception => e
183
+ warn "double exception fault: #{e}"
184
+ pp e
185
+ raise e
186
+ end
187
+ ensure
188
+ @call_thread = old_call_thread
189
+ schedule
190
+ end
191
+ end
192
+
193
+ # note called from task.rb, too
194
+ def schedule continuation = nil
195
+ @mutex.synchronize do
196
+ # warn ">schd #{self} #{@state} #{@queue.join(' ')}"
197
+ task = nil
198
+ index = 0
199
+ while task == nil and index < @queue.length do
200
+ candidate = @queue[index]
201
+ # FIX arugments?
202
+ if @gate.accepts?( *( [ candidate.type, candidate.method ] + candidate.arguments ) ) or
203
+ current_call_thread? candidate.call_thread
204
+ task = candidate
205
+ @queue[index,1] = []
206
+ end
207
+ index += 1
208
+ end
209
+ if task
210
+ Dramatis::Runtime::Scheduler.current.schedule task
211
+ else
212
+ blocked!
213
+ end
214
+ # warn "<schd #{self} #{@queue.join(' ')} #{@state} #{Thread.current}"
215
+ end
216
+ end
217
+
218
+ def blocked!
219
+ # warn "blocked! #{self} #{@state}"
220
+ @state = :blocked
221
+ end
222
+
223
+ def runnable!
224
+ # warn "runnable! #{self} #{@state}"
225
+ @state = :runnable
226
+ end
227
+
228
+ def runnable?
229
+ # warn "runnable? #{self} #{@state}"
230
+ @state == :runnable
231
+ end
232
+
233
+ def timeout value, *args
234
+ @timer ||= Dramatis::Runtime::Timer.new
235
+ end
236
+
237
+ end
238
+
239
+ # Might be nice if this was broken out into another file ... YAGNI?
240
+ # This needs to be reworked. External threads and the main thread are
241
+ # related but different (there can only be one main thread). Mutliple
242
+ # at_exit calls are suspect. Of course, if the main actor tracks multilple
243
+ # runtimes, it might be okay.
244
+
245
+ class Dramatis::Runtime::Actor::Main < Dramatis::Runtime::Actor #:nodoc: all
246
+
247
+ class DefaultBehavior
248
+
249
+ class Exception < ::Exception; end
250
+
251
+ def method_missing *args
252
+ raise Exception.new( "must use Actor#become to enable main actor" )
253
+ end
254
+
255
+ def dramatis_exception e
256
+ if Dramatis::Runtime.current.warnings?
257
+ warn "exception on main thread: #{e}"
258
+ # pp caller
259
+ end
260
+ Dramatis::Runtime.current.exception e
261
+ end
262
+
263
+ end
264
+
265
+ @@current = nil
266
+
267
+ def self.current
268
+ @@current ||= self.new
269
+ end
270
+
271
+ def self.reset
272
+ @@current = nil
273
+ end
274
+
275
+ def quiesce
276
+ schedule
277
+ end
278
+
279
+ def finalize
280
+ if !@at_exit_run
281
+ @at_exit_run = true
282
+ schedule
283
+ Dramatis::Runtime::Scheduler.current.main_at_exit
284
+ end
285
+ end
286
+
287
+ def initialize
288
+ super DefaultBehavior.new
289
+ @at_exit_run = false
290
+ at_exit { finalize }
291
+ runnable!
292
+ end
293
+
294
+ end
@@ -0,0 +1,244 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ begin require 'pp'; rescue Exception; end
5
+
6
+ class Dramatis::Runtime::Gate #:nodoc: all
7
+
8
+ def self.new
9
+ gate = Case.new
10
+ gate.accept Object
11
+ gate.accept :actor
12
+ gate.accept :continuation
13
+ gate.accept :object
14
+ gate
15
+ end
16
+
17
+ class Case
18
+ def always args, value, options = {}
19
+ _change @always, Array( args ), value, options
20
+ end
21
+ def only args, options = {}
22
+ _change @list, [ :object ], false, options
23
+ _change @list, [ :continuation ], false, options
24
+ _change @list, [ :continuation, Object, :exception ], true, options
25
+ _change @list, Array( args ), true, options
26
+ end
27
+ def default args, options = {}
28
+ _change @list, args, nil, options
29
+ end
30
+ def default_by_tag tag
31
+ _change @list, nil, nil, { :tag => tag }
32
+ end
33
+ def _change list, args, value, options = {}
34
+ inplace = options[ :inplace ]
35
+ tag = options[ :tag ]
36
+ # pp ">> #{args and args.join(' ')} #{value} #{inplace} #{tag}", list
37
+ prepend = true
38
+ tbd = []
39
+ list.each_with_index do |entry, list_index|
40
+ vector, result, entry_tag = entry
41
+ matches = true
42
+ if tag and entry_tag != tag
43
+ # p "#{tag} tag and #{entry_tag} dont' match"
44
+ next
45
+ end
46
+ if args
47
+ args.each_with_index do |arg, arg_index|
48
+ # p "compare #{vector[arg_index]} #{arg}"
49
+ if vector[arg_index] != arg
50
+ # p "matches"
51
+ matches = false
52
+ break
53
+ end
54
+ end
55
+ end
56
+ if matches
57
+ # p "matched"
58
+ if inplace and value != nil
59
+ # p "inplace"
60
+ list[list_index][1] = value
61
+ # FIX: tag?
62
+ prepend = false
63
+ else
64
+ # p "schedule remove #{list[list_index].join(' ')} at #{list_index}"
65
+ tbd << list_index
66
+ # list[list_index,1] = []
67
+ end
68
+ # break
69
+ end
70
+ end
71
+ tbd.reverse.each do |index|
72
+ # p "remove #{index} #{list[index].join(' ')} at #{index}"
73
+ list[index,1] = []
74
+ end
75
+ if prepend and value != nil
76
+ list.unshift [ args, value, tag ]
77
+ end
78
+ # pp "<< #{args and args.join(' ')} #{value} #{inplace} #{tag}", list
79
+ end
80
+ def change args, value, inplace
81
+ # pp "> #{args.join(' ')} #{value} #{inplace}", @list
82
+ prepend = true
83
+ @list.each_with_index do |entry, list_index|
84
+ vector, result = entry
85
+ matches = true
86
+ args.each_with_index do |arg, arg_index|
87
+ # p "compare #{vector[arg_index]} #{arg}"
88
+ if vector[arg_index] != arg
89
+ # p "matches"
90
+ matches = false
91
+ break
92
+ end
93
+ end
94
+ if matches
95
+ # p "matched"
96
+ if inplace
97
+ # p "inplace"
98
+ @list[list_index][1] = value
99
+ # FIX: tag?
100
+ prepend = false
101
+ else
102
+ @list[list_index,1] = []
103
+ end
104
+ break
105
+ end
106
+ end
107
+ if prepend
108
+ @list.unshift [ args, value ]
109
+ end
110
+ # pp "<", @list
111
+ end
112
+ def accept *args
113
+ change args, true, false
114
+ end
115
+ def refuse *args
116
+ change args, false, false
117
+ end
118
+ def update value, *args
119
+ end
120
+ def accepts? *args
121
+ # p "accepts? #{args.join(" ")}"
122
+ accepted = nil
123
+ ( @always + @list ).each do |entry|
124
+ vector, result = entry
125
+ matches = true
126
+ vector.each_with_index do |v, i|
127
+ # warn "#{v} #{args[i]} => #{v === args[i]} so #{result}"
128
+ if not( v === args[i] )
129
+ matches = false
130
+ break
131
+ end
132
+ end
133
+ if matches
134
+ accepted = result
135
+ break
136
+ end
137
+ end
138
+ # warn "last '#{accepted}'"
139
+ # p "accepts? #{args.join(" ")} => '#{accepted}'"
140
+ accepted == true
141
+ end
142
+ def initialize
143
+ @always = []
144
+ @list = []
145
+ end
146
+ def list
147
+ @list
148
+ end
149
+ end
150
+
151
+ class Constant
152
+ def initialize constant
153
+ @constant = constant
154
+ end
155
+ def accepts? *args
156
+ @constant
157
+ end
158
+ def refuse *args
159
+ warn "HELLL"
160
+ raise "hell"
161
+ end
162
+ def accept *args
163
+ warn "HELLL"
164
+ raise "hell"
165
+ end
166
+ def default *args
167
+ warn "HELLL"
168
+ raise "hell"
169
+ end
170
+ def set_default *args
171
+ warn "HELLL"
172
+ raise "hell"
173
+ end
174
+ end
175
+
176
+ ACCEPT = Constant.new true
177
+ REJECT = Constant.new false
178
+
179
+ class Hash
180
+
181
+ def initialize default, hash = {}
182
+ @default = default
183
+ @hash = hash.clone
184
+ @queued = {}
185
+ track and warn "create default = #{@default} hash = [#{@hash.keys.join(' ')}]"
186
+ @always = []
187
+ @call_thread = nil
188
+ end
189
+
190
+ def track; false; end
191
+
192
+ def always *args
193
+ track and warn "always [#{args.join(' ')}]"
194
+ @always << args
195
+ end
196
+
197
+ def refuse *args
198
+ track and warn "refuse [#{args.join(' ')}]"
199
+ if args.length == 1
200
+ @hash[args[0]] = REJECT
201
+ else
202
+ @hash[args[0]].refuse( *args[1,args.length] )
203
+ end
204
+ end
205
+
206
+ def accept *args
207
+ track and warn "accept [#{args.join(' ')}]"
208
+ if args.length == 1
209
+ @hash[args[0]] = ACCEPT
210
+ else
211
+ @hash[args[0]].accept( *args[1,args.length] )
212
+ end
213
+ end
214
+
215
+ def default *args
216
+ track and warn "default [#{args.join(' ')}]"
217
+ if args.length == 1
218
+ @hash.delete args[0]
219
+ else
220
+ @hash[args[0]].default( *args[1,args.length] )
221
+ end
222
+ end
223
+
224
+ def set_default value, *args
225
+ track and warn "default = #{value} [#{args.join(' ')}] #{args.length}"
226
+ if args.length == 0
227
+ @default = value
228
+ else
229
+ @hash[args[0]].set_default value, *args[1,args.length]
230
+ end
231
+ end
232
+
233
+ def accepts? *args
234
+ v = nil
235
+ if v == nil
236
+ v = @hash.has_key?( args[0] ) ? @hash[args[0]].accepts?( *args[1,args.length] ) : @default
237
+ end
238
+ track and warn "accepts? [#{args.join(' ')}] => #{v}"
239
+ v
240
+ end
241
+
242
+ end
243
+
244
+ end