]> git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Lock/API.pm
21f3ecfd8356474dd2ddca325d80178cb0afd33d
[selfforum.git] / selfforum-cgi / shared / Lock / API.pm
1 package Lock::API;
2
3 ################################################################################
4 # #
5 # File: shared/Lock/API.pm #
6 # #
7 # Authors: Andre Malo <nd@o3media.de>, 2001-05-25 #
8 # #
9 # Description: system independent part of Locking and Filehandle class #
10 # NOT FOR PUBLIC USE #
11 # #
12 ################################################################################
13
14 use strict;
15 use vars qw(
16 $VERSION
17 );
18
19 use Carp;
20
21 use base qw(
22 Lock::Handle
23 Lock::_simple
24 );
25
26 ################################################################################
27 #
28 # Version check
29 #
30 $VERSION = do { my @r =(q$Revision$ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
31
32 ### sub lock ###################################################################
33 #
34 # set a lock on the file
35 #
36 # Params: $locktype - what kind of locking?
37 # $timeout - (optional) Timeout
38 #
39 # Return: success (boolean)
40 #
41 sub lock {
42 my $self = shift;
43 my $locktype = shift;
44
45 return if $self -> masterlocked;
46
47 ###########################################
48 # shared lock
49 #
50 if ($locktype == $self -> LH_SHARED) {
51 return 1 if $self -> locked_shared;
52 return if $self -> locked_exclusive;
53
54 my $timeout = shift || $self -> timeout ('shared');
55
56 # try to increase the reference counter
57 #
58 if ($self -> add_ref($timeout)) {
59 $self -> set_static (locked_shared => 1);
60 return 1;
61 }
62 }
63
64
65 ###########################################
66 # exclusive lock
67 #
68 elsif ($locktype == $self -> LH_EXCL) {
69 return 1 if $self -> locked_exclusive;
70
71 my $timeout = shift || $self -> timeout ('exclusive');
72
73 #####################
74 # transform exclusive shared lock into exclusive lock
75 #
76 if ($self -> locked_exsh) {
77 my $reflock = new Lock::Handle ($self -> reflock);
78
79 for (0..$timeout) {
80 if ($self -> set_excl_announce and $self -> _simple_lock ($reflock)) {
81 if ($self -> get_ref == 1) {
82 $self -> set_ref(0);
83 $self -> remove_exsh_announce;
84 $self -> set_static (locked_exsh => 0);
85 $self -> set_static (locked_exclusive => 1);
86 return 1;
87 }
88
89 last unless ($self -> _simple_unlock ($reflock->filename));
90 }
91
92 sleep 1;
93 }
94 $self -> remove_excl_announce;
95 }
96
97 #####################
98 # set exclusive lock
99 #
100 else {
101 my $reflock = new Lock::Handle ($self -> reflock);
102
103 for (0..$timeout) {
104 if ($self -> set_excl_announce and $self -> _simple_lock ($reflock)) {
105 if ($self -> get_ref == 0) {
106 $self -> set_static (locked_exclusive => 1);
107 return 1;
108 }
109
110 last unless ($self -> _simple_unlock ($reflock->filename));
111 }
112
113 sleep 1;
114 }
115 $self -> remove_excl_announce;
116 }
117 }
118
119
120 ###########################################
121 # exclusive shared lock
122 #
123 elsif ($locktype == $self -> LH_EXSH) {
124 return 1 if $self -> locked_exsh;
125 return if ($self -> locked_shared or $self -> locked_exclusive);
126
127 my $timeout = shift || $self -> timeout ('shared');
128
129 # try to increase the reference counter
130 #
131 if ($self -> es_add_ref($timeout)) {
132 $self -> set_static (locked_exsh => 1);
133 return 1;
134 }
135 }
136
137
138 ###########################################
139 # master lock
140 #
141 elsif ($locktype == $self -> LH_MASTER) {
142 $self -> lock ($self->LH_EXCL, $self -> timeout('master')) and
143 $self -> _simple_lock (new Lock::Handle ($self->masterlock)) and
144 return 1;
145 }
146
147 ###########################################
148 # unknown locking type
149 #
150 else {
151 croak "unknown locking type '$locktype'";
152 }
153
154 # timeout
155 #
156 $self -> unlock_violent;
157 return;
158 }
159
160 ### sub unlock #################################################################
161 #
162 # remove shared or exclusive lock
163 #
164 # Params: $timeout - (optional) Timeout
165 #
166 # Return: success (boolean)
167 #
168 sub unlock {
169 my $self = shift;
170 my $timeout = shift || $self -> timeout ('shared');
171
172 return if $self -> masterlocked;
173
174 ###########################################
175 # shared lock
176 #
177 if ($self -> locked_shared) {
178 # try to decrease the reference counter
179 #
180 if ($self -> sub_ref($timeout)) {
181 $self -> set_static (locked_shared => 0);
182 return 1;
183 }
184 }
185
186
187 ###########################################
188 # exclusive lock
189 #
190 elsif ($self -> locked_exclusive) {
191 my $reflock = new Lock::Handle ($self -> reflock);
192
193 for (0..$timeout) {
194 if ($self -> _simple_unlock ($reflock->filename)) {
195 $self -> remove_excl_announce;
196 $self -> set_static (locked_exclusive => 0);
197 return 1;
198 }
199
200 sleep 1;
201 }
202 }
203
204
205 ###########################################
206 # exclusive shared lock
207 #
208 elsif ($self -> locked_exsh) {
209 # try to decrease the reference counter
210 #
211 if ($self -> es_sub_ref($timeout)) {
212 $self -> remove_exsh_announce;
213 $self -> set_static (locked_exsh => 0);
214 return 1;
215 }
216 }
217
218
219 ###########################################
220 # not locked
221 #
222 else {
223 return 1;
224 }
225
226 # unlocking failed
227 #
228 $self -> unlock_violent;
229 return;
230 }
231
232 ### sub unlock_violent #########################################################
233 #
234 # remove any lock violently (excludes master lock)
235 #
236 # Params: ~none~
237 #
238 # Return: -none- (the success is undefined)
239 #
240 sub unlock_violent {
241 my $self = shift;
242
243 unless ($self -> masterlocked) {
244
245 # find out last modification time
246 # and do nothing unless 'violent-timout' is over
247 #
248 my $time = $self -> _reftime;
249
250 if ($time) {
251 return if ((time - $time) < $self -> timeout('violent'));
252 }
253
254 $self -> set_ref (0); # reference counter = 0
255 $self -> _simple_unlock ($self -> reflock); # release reference counter file
256 $self -> _simple_unlock ($self -> exshlock); # remove excl shared lock
257 $self -> _simple_unlock ($self -> lockfile); # release file
258 }
259
260 return;
261 }
262
263 ### sub release ################################################################
264 #
265 # release a file
266 #
267 # Params: ~none~
268 #
269 # Return: ~none~
270 #
271 sub release {
272 my $self = shift;
273
274 $self -> set_ref (0); # reference counter = 0
275 $self -> _simple_unlock ($self -> reflock); # release reference counter
276 $self -> _simple_unlock ($self -> lockfile); # remove any write lock announce
277 $self -> _simple_unlock ($self -> exshlock); # remove any excl shared lock
278 $self -> _simple_unlock ($self -> masterlock); # remove master lock
279
280 return;
281 }
282
283 # keep 'require' happy
284 1;
285
286 #
287 #
288 ### end of Lock::API ###########################################################

patrick-canterino.de