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,374 @@
1
+ module Dramatis; end
2
+ class Dramatis::Runtime; end
3
+
4
+ require 'thread'
5
+
6
+ require 'dramatis/runtime/thread_pool'
7
+ require 'dramatis/runtime/actor/main'
8
+ require 'dramatis/runtime'
9
+ require 'dramatis'
10
+
11
+ begin require 'pp'; rescue Exception; end
12
+
13
+ class Dramatis::Runtime::Scheduler #:nodoc: all
14
+
15
+ def checkio; false; end
16
+
17
+ @@thread_pools = []
18
+
19
+ def self.reset
20
+ @@thread_pools.each do |thread_pool|
21
+ thread_pool.reset
22
+ end
23
+ @@current.reset
24
+ @@current = nil
25
+ end
26
+
27
+ @@current = nil
28
+
29
+ def self.current
30
+ @@current ||= self.new
31
+ end
32
+
33
+ def reset
34
+ # pp @suspended_continuations
35
+ end
36
+
37
+ def schedule task
38
+ @mutex.synchronize do
39
+ # warn "sched #{@queue.length} #{@state} #{task}"
40
+ begin
41
+ raise "bad bad bad" if task == nil
42
+ rescue Exception => e
43
+ p "very bad very #{e}"
44
+ pp e.backtrace
45
+ raise e
46
+ end
47
+ @queue << task
48
+ if @queue.length == 1
49
+ if @state == :waiting
50
+ @wait.signal
51
+ elsif @state == :idle
52
+ @state = :running
53
+ @running_threads = 1
54
+ checkio and warn "#{Thread.current} checkout main #{Thread.main} #{@running_threads}"
55
+ @thread = Thread.new { run }
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ # must be called with @mutex locked
62
+ # must be called after @running_threads decremented
63
+ def maybe_deadlock
64
+ # warn "maybe_deadlock #{Thread.current} #{Thread.main} threads #{@running_threads} queue #{@queue.length} #{Thread.list.join(" ")} qg #{@quiescing} scl #{@suspended_continuations.length}"
65
+ if @running_threads == 0 and @queue.length == 0 and @suspended_continuations.length > 0 and !@quiescing
66
+ # p "DEADLOCK!"
67
+ raise Dramatis::Deadlock.new
68
+ end
69
+ end
70
+
71
+ def suspend_notification continuation
72
+ @mutex.synchronize do
73
+ if @state == :idle
74
+ @state = :running
75
+ @running_threads = 1
76
+ checkio and warn "#{Thread.current} checkout -1 #{Thread.main} #{@running_threads}"
77
+ @thread = Thread.new { run }
78
+ end
79
+ checkio and warn "#{Thread.current} checkin 0 #{Thread.main} #{@running_threads}"
80
+ @running_threads -= 1
81
+ begin
82
+ raise "cane" if @running_threads < 0
83
+ rescue ::Exception => e
84
+ pp e.backtrace
85
+ end
86
+ if @state == :waiting
87
+ @wait.signal
88
+ end
89
+ @suspended_continuations[continuation.to_s] = continuation
90
+ end
91
+ end
92
+
93
+ def wakeup_notification continuation
94
+ @mutex.synchronize do
95
+ @suspended_continuations.delete continuation.to_s
96
+ @running_threads += 1
97
+ checkio and warn "#{Thread.current} checkout #{@running_threads}"
98
+ end
99
+ end
100
+
101
+ def quiesce
102
+ Dramatis::Runtime::Actor::Main.current.quiesce
103
+ main_at_exit true
104
+ end
105
+
106
+ def main_at_exit quiescing = false
107
+ # warn "quiescing" if quiescing
108
+ # warn "main has exited: waiting" if !quiescing
109
+ @mutex.synchronize do
110
+ @quiescing = quiescing
111
+ checkio and warn "#{Thread.current} main maybe checkin 1 #{@running_threads} #{@state} #{@main_state} #{quiescing}"
112
+ if @state != :idle
113
+ @running_threads -= 1
114
+ if @state == :waiting
115
+ @wait.signal
116
+ end
117
+ end
118
+
119
+ raise "hell #{@main_state.to_s}" if @main_state != :running and @main_state != :may_finish
120
+ checkio and warn "#{Thread.current} main signaled #{@running_threads} #{@state} #{@main_state} #{quiescing}"
121
+
122
+ @main_mutex.synchronize do
123
+ if @main_state == :running
124
+ if @state != :idle
125
+ @main_state = :waiting
126
+ begin
127
+ @main_wait.wait @mutex
128
+ rescue Exception => e
129
+ # pp "wait said #{e}", e.backtrace
130
+ raise e
131
+ end
132
+ @main_join.join
133
+ @main_join = nil
134
+ raise "hell #{@main_state.to_s}" if @main_state != :may_finish
135
+ else
136
+ begin
137
+ maybe_deadlock
138
+ rescue Dramatis::Deadlock => deadlock
139
+ warn "Deadlock at exit: uncompleted tasks exist"
140
+ raise deadlock
141
+ end
142
+ @main_state = :may_finish
143
+ end
144
+ end
145
+ @main_state = :running if @quiescing
146
+ end
147
+ @quiescing = false
148
+ end
149
+ raise "hell #{@main_state.to_s}" if @main_state != :may_finish and @main_state != :running
150
+ # warn "?threads? #{Thread.list.join(' ')}"
151
+ # warn "main has exited: done"
152
+ @thread_pool.reset()
153
+ Dramatis::Runtime.current.maybe_raise_exceptions quiescing
154
+ end
155
+
156
+ def << actor
157
+ @actors << actor
158
+ end
159
+
160
+ def thread_count
161
+ @mutex.synchronize do
162
+ @@thread_pools.inject(0) { |a,b| a+b.length }
163
+ end
164
+ end
165
+
166
+ private
167
+
168
+ def initialize
169
+ @thread_pool = Dramatis::Runtime::ThreadPool.new
170
+ @@thread_pools << @thread_pool
171
+ # Thread.abort_on_exception = true
172
+ @mutex = Mutex.new
173
+ @wait = ConditionVariable.new
174
+ @running_threads = 0
175
+ @suspended_continuations = {}
176
+ @queue = []
177
+ @state = :idle
178
+
179
+ @main_mutex = Mutex.new
180
+ @main_wait = ConditionVariable.new
181
+ @main_state = :running
182
+ @quiescing = false
183
+
184
+ @thread = nil
185
+
186
+ @actors = []
187
+ end
188
+
189
+ class Done < ::Exception
190
+ end
191
+
192
+ def run
193
+
194
+ checkio and warn "#{Thread.current} scheduler starting #{@state}"
195
+
196
+ begin
197
+ while true
198
+ @mutex.synchronize do
199
+ # warn "qe #{@queue.empty?} tr '#{@running_threads}'"
200
+ while @queue.empty? and @running_threads != 0
201
+ @state = :waiting
202
+ begin
203
+ raise "hell" if @running_threads == 0
204
+ @wait.wait @mutex
205
+ rescue Exception => exception
206
+ warn "wait exception: #{exception}"
207
+ ensure
208
+ @state = :running
209
+ end
210
+ end
211
+ end
212
+
213
+ begin
214
+ @mutex.synchronize { maybe_deadlock }
215
+ rescue Dramatis::Deadlock => deadlock
216
+ actors = @mutex.synchronize { @actors.dup }
217
+ thread = Thread.current
218
+ actors.each do |actor|
219
+ thread[:dramatis_actor] = actor.name
220
+ actor.deadlock deadlock
221
+ end
222
+ thread[:dramatis_actor] = nil
223
+ end
224
+
225
+ @mutex.synchronize { maybe_deadlock }
226
+
227
+ @mutex.synchronize do
228
+
229
+ raise Done if @queue.empty? and @running_threads == 0
230
+
231
+ if @queue.length > 0
232
+
233
+ task = @queue.shift
234
+
235
+ # p "task #{task}"
236
+
237
+ begin
238
+ raise "hell!!!!" if task == nil
239
+ rescue Exception => e
240
+ p "bad bad #{e}"
241
+ pp e.backtrace
242
+ raise e
243
+ end
244
+
245
+ @running_threads += 1
246
+
247
+ # p "tasket #{task}"
248
+
249
+ @thread_pool.new do
250
+
251
+ # "tasky", task
252
+
253
+ # "tasketx #{task}"
254
+
255
+ checkio and warn "#{Thread.current} spining up #{@running_threads}"
256
+ begin
257
+ deliver task
258
+ rescue Exception => e
259
+ warn "unexptected deliver error #{e}"
260
+ raise e
261
+ ensure
262
+ @mutex.synchronize do
263
+ checkio and warn "#{Thread.current} checkin 2 #{@running_threads} #{@state}"
264
+ @running_threads -= 1
265
+ if @state == :waiting
266
+ @wait.signal
267
+ else
268
+ # maybe_deadlock
269
+ end
270
+ end
271
+ end
272
+ checkio and warn "#{Thread.current} retiring #{@running_threads}"
273
+ end
274
+ end
275
+ end
276
+ end
277
+ # warn "after loop"
278
+ rescue Done
279
+ rescue Exception => exception
280
+ warn "1 *? exception " + exception.to_s
281
+ warn "smp!!! " + exception.backtrace.join("\n")
282
+ # pp exception.backtrace
283
+ Dramatis::Runtime.current.exception exception
284
+ end
285
+
286
+ checkio and warn "scheduler giving up the ghost #{@queue.length} #{Thread.current}"
287
+
288
+ begin
289
+ @mutex.synchronize do
290
+ maybe_deadlock
291
+ end
292
+ rescue Dramatis::Deadlock => deadlock
293
+ actors = @mutex.synchronize { @actors.dup }
294
+ actors.each { |actor| actor.deadlock deadlock }
295
+ rescue Exception => exception
296
+ warn "2 exception " + exception.to_s
297
+ Dramatis::Runtime.current.exception exception
298
+ end
299
+
300
+ checkio and warn "scheduler giving up after final deadlock check #{@queue.length} #{Thread.current}"
301
+
302
+ # FIX need to check all the mutex nesting between main_mutex and mutex
303
+ # I think this should be the main mutex ...
304
+ @mutex.synchronize do
305
+ raise "hell #{@main_state.to_s}" if @main_state != :running and @main_state != :waiting
306
+ state = @main_state
307
+ @main_state = :may_finish
308
+ # warn "main is #{state}"
309
+ if state == :waiting
310
+ @main_join = Thread.current
311
+ @main_wait.signal
312
+ end
313
+ # should this be synchronized?
314
+ # if there is more than one main (non-dramatis) thread ... well, I'm not sure
315
+ # how protected we are for that around shutdown/startup
316
+ # I guess it won't hurt, but I'm not sure it helps
317
+ # @mutex.synchronize do
318
+ # warn "s #{Thread.current} m #{Thread.main} l #{Thread.list.join(' ')} "
319
+ raise "hell" if @queue.length > 0
320
+ @state = :idle
321
+ @thread = nil
322
+ # end
323
+ end
324
+
325
+ checkio and warn "#{Thread.current} scheduler ending"
326
+
327
+ end
328
+
329
+ def deliver task
330
+ thread = Thread.current
331
+ begin
332
+ raise "hel!!!" if !task
333
+ rescue Exception => e
334
+ p "very bad!! #{e}"
335
+ pp e.backtrace
336
+ raise e
337
+ end
338
+ thread[:dramatis_actor] = task.actor.name
339
+ xx = task.actor.name
340
+ xx = xx.instance_eval { @actor }
341
+ # warn "assign #{xx} to #{thread}"
342
+ begin
343
+ # warn "deliver " + task.inspect
344
+ task.deliver
345
+ # warn "delivered " + task.inspect
346
+ rescue Exception => exception
347
+ warn "2 exception " + exception.to_s
348
+ # pp exception.backtrace
349
+ Dramatis::Runtime.current.exception exception
350
+ ensure
351
+ thread[:dramatis_actor] = nil
352
+ end
353
+ end
354
+
355
+ def self.actor
356
+ thread = Thread.current
357
+ actor = thread[:dramatis_actor]
358
+ if !actor
359
+ if thread == Thread.main
360
+ # p "here", actor
361
+ actor = Dramatis::Runtime::Actor::Main.current.name
362
+ # p "there", actor
363
+ end
364
+ else
365
+ # this is a debugging path; can go away
366
+ raise "hell" if thread == Thread.main and
367
+ actor != Dramatis::Runtime::Actor::Main.current
368
+ raise "hell" if thread != Thread.main and
369
+ actor == Dramatis::Runtime::Actor::Main.current
370
+ end
371
+ actor
372
+ end
373
+
374
+ end