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.
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