Removed inadvertently added files from mspec.
[rbx.git] / stdlib / sync.rb
blob92840bcecfbd2ccd4b9b836ef144f2db71836d90
2 #   sync.rb - 2 phase lock with counter
3 #       $Release Version: 1.0$
4 #       $Revision: 11708 $
5 #       $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
6 #       by Keiju ISHITSUKA(keiju@ishitsuka.com)
8 # --
9 #  Sync_m, Synchronizer_m
10 #  Usage:
11 #   obj.extend(Sync_m)
12 #   or
13 #   class Foo
14 #       include Sync_m
15 #       :
16 #   end
18 #   Sync_m#sync_mode
19 #   Sync_m#sync_locked?, locked?
20 #   Sync_m#sync_shared?, shared?
21 #   Sync_m#sync_exclusive?, sync_exclusive?
22 #   Sync_m#sync_try_lock, try_lock
23 #   Sync_m#sync_lock, lock
24 #   Sync_m#sync_unlock, unlock
26 #   Sync, Synchronicer:
27 #       include Sync_m
28 #   Usage:
29 #   sync = Sync.new
31 #   Sync#mode
32 #   Sync#locked?
33 #   Sync#shared?
34 #   Sync#exclusive?
35 #   Sync#try_lock(mode) -- mode = :EX, :SH, :UN
36 #   Sync#lock(mode)     -- mode = :EX, :SH, :UN
37 #   Sync#unlock
38 #   Sync#synchronize(mode) {...}
39 #   
42 unless defined? Thread
43   fail "Thread not available for this ruby interpreter"
44 end
46 module Sync_m
47   RCS_ID='-$Header$-'
48   
49   # lock mode
50   UN = :UN
51   SH = :SH
52   EX = :EX
53   
54   # exceptions
55   class Err < StandardError
56     def Err.Fail(*opt)
57       fail self, sprintf(self::Message, *opt)
58     end
59     
60     class UnknownLocker < Err
61       Message = "Thread(%s) not locked."
62       def UnknownLocker.Fail(th)
63         super(th.inspect)
64       end
65     end
66     
67     class LockModeFailer < Err
68       Message = "Unknown lock mode(%s)"
69       def LockModeFailer.Fail(mode)
70         if mode.id2name
71           mode = id2name
72         end
73         super(mode)
74       end
75     end
76   end
77   
78   def Sync_m.define_aliases(cl)
79     cl.module_eval %q{
80       alias locked? sync_locked?
81       alias shared? sync_shared?
82       alias exclusive? sync_exclusive?
83       alias lock sync_lock
84       alias unlock sync_unlock
85       alias try_lock sync_try_lock
86       alias synchronize sync_synchronize
87     }
88   end
89   
90   def Sync_m.append_features(cl)
91     super
92     unless cl.instance_of?(Module)
93       # do nothing for Modules
94       # make aliases and include the proper module.
95       define_aliases(cl)
96     end
97   end
98   
99   def Sync_m.extend_object(obj)
100     super
101     obj.sync_extended
102   end
104   def sync_extended
105     unless (defined? locked? and
106             defined? shared? and
107             defined? exclusive? and
108             defined? lock and
109             defined? unlock and
110             defined? try_lock and
111             defined? synchronize)
112       Sync_m.define_aliases(class<<self;self;end)
113     end
114     sync_initialize
115   end
117   # accessing
118   def sync_locked?
119     sync_mode != UN
120   end
121   
122   def sync_shared?
123     sync_mode == SH
124   end
125   
126   def sync_exclusive?
127     sync_mode == EX
128   end
129   
130   # locking methods.
131   def sync_try_lock(mode = EX)
132     return unlock if sync_mode == UN
133     
134     Thread.critical = true
135     ret = sync_try_lock_sub(sync_mode)
136     Thread.critical = false
137     ret
138   end
139   
140   def sync_lock(m = EX)
141     return unlock if m == UN
143     until (Thread.critical = true; sync_try_lock_sub(m))
144       if sync_sh_locker[Thread.current]
145         sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
146         sync_sh_locker.delete(Thread.current)
147       else
148         sync_waiting.push Thread.current
149       end
150       Thread.stop
151     end
152     Thread.critical = false
153     self
154   end
155   
156   def sync_unlock(m = EX)
157     Thread.critical = true
158     if sync_mode == UN
159       Thread.critical = false
160       Err::UnknownLocker.Fail(Thread.current)
161     end
162     
163     m = sync_mode if m == EX and sync_mode == SH
164     
165     runnable = false
166     case m
167     when UN
168       Thread.critical = false
169       Err::UnknownLocker.Fail(Thread.current)
170       
171     when EX
172       if sync_ex_locker == Thread.current
173         if (self.sync_ex_count = sync_ex_count - 1) == 0
174           self.sync_ex_locker = nil
175           if sync_sh_locker.include?(Thread.current)
176             self.sync_mode = SH
177           else
178             self.sync_mode = UN
179           end
180           runnable = true
181         end
182       else
183         Err::UnknownLocker.Fail(Thread.current)
184       end
185       
186     when SH
187       if (count = sync_sh_locker[Thread.current]).nil?
188         Err::UnknownLocker.Fail(Thread.current)
189       else
190         if (sync_sh_locker[Thread.current] = count - 1) == 0 
191           sync_sh_locker.delete(Thread.current)
192           if sync_sh_locker.empty? and sync_ex_count == 0
193             self.sync_mode = UN
194             runnable = true
195           end
196         end
197       end
198     end
199     
200     if runnable
201       if sync_upgrade_waiting.size > 0
202         for k, v in sync_upgrade_waiting
203           sync_sh_locker[k] = v
204         end
205         wait = sync_upgrade_waiting
206         self.sync_upgrade_waiting = []
207         Thread.critical = false
208         
209         for w, v in wait
210           w.run
211         end
212       else
213         wait = sync_waiting
214         self.sync_waiting = []
215         Thread.critical = false
216         for w in wait
217           w.run
218         end
219       end
220     end
221     
222     Thread.critical = false
223     self
224   end
225   
226   def sync_synchronize(mode = EX)
227     begin
228       sync_lock(mode)
229       yield
230     ensure
231       sync_unlock
232     end
233   end
235   attr :sync_mode, true
236     
237   attr :sync_waiting, true
238   attr :sync_upgrade_waiting, true
239   attr :sync_sh_locker, true
240   attr :sync_ex_locker, true
241   attr :sync_ex_count, true
242     
243   private
245   def sync_initialize
246     @sync_mode = UN
247     @sync_waiting = []
248     @sync_upgrade_waiting = []
249     @sync_sh_locker = Hash.new
250     @sync_ex_locker = nil
251     @sync_ex_count = 0
252   end
254   def initialize(*args)
255     sync_initialize
256     super
257   end
258     
259   def sync_try_lock_sub(m)
260     case m
261     when SH
262       case sync_mode
263       when UN
264         self.sync_mode = m
265         sync_sh_locker[Thread.current] = 1
266         ret = true
267       when SH
268         count = 0 unless count = sync_sh_locker[Thread.current]
269         sync_sh_locker[Thread.current] = count + 1
270         ret = true
271       when EX
272         # in EX mode, lock will upgrade to EX lock
273         if sync_ex_locker == Thread.current
274           self.sync_ex_count = sync_ex_count + 1
275           ret = true
276         else
277           ret = false
278         end
279       end
280     when EX
281       if sync_mode == UN or
282         sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current) 
283         self.sync_mode = m
284         self.sync_ex_locker = Thread.current
285         self.sync_ex_count = 1
286         ret = true
287       elsif sync_mode == EX && sync_ex_locker == Thread.current
288         self.sync_ex_count = sync_ex_count + 1
289         ret = true
290       else
291         ret = false
292       end
293     else
294       Thread.critical = false
295       Err::LockModeFailer.Fail mode
296     end
297     return ret
298   end
300 Synchronizer_m = Sync_m
302 class Sync
303   #Sync_m.extend_class self
304   include Sync_m
305     
306   def initialize
307     super
308   end
309     
311 Synchronizer = Sync