lib/sync.rb
DEFINITIONS
This source file includes following functions.
1 #
2 # sync.rb - 2 phase lock with counter
3 # $Release Version: 1.0$
4 # $Revision: 1.4 $
5 # $Date: 2001/06/06 14:19:33 $
6 # by Keiju ISHITSUKA(keiju@ishitsuka.com)
7 #
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
17 #
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
25 #
26 # Sync, Synchronicer:
27 # include Sync_m
28 # Usage:
29 # sync = Sync.new
30 #
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 #
40 #
41
42 unless defined? Thread
43 fail "Thread not available for this ruby interpreter"
44 end
45
46 module Sync_m
47 RCS_ID='-$Header: /src/ruby/lib/sync.rb,v 1.4 2001/06/06 14:19:33 keiju Exp $-'
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
103
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
116
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
142
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
234
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
244
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
253
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
299 end
300 Synchronizer_m = Sync_m
301
302 class Sync
303 #Sync_m.extend_class self
304 include Sync_m
305
306 def initialize
307 super
308 end
309
310 end
311 Synchronizer = Sync