| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # See copyright, etc in below POD section. | 
| 2 |  |  |  |  |  |  | ###################################################################### | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | =head1 NAME | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | IPC::Locker - Distributed lock handler | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | use IPC::Locker; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | my $lock = IPC::Locker->lock(lock=>'one_per_machine', | 
| 13 |  |  |  |  |  |  | host=>'example.std.com', | 
| 14 |  |  |  |  |  |  | port=>223); | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | if ($lock->lock()) { something; } | 
| 17 |  |  |  |  |  |  | if ($lock->locked()) { something; } | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | $lock->unlock(); | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | L will query a remote lockerd server to obtain a lock around a | 
| 24 |  |  |  |  |  |  | critical section.  When the critical section completes, the lock may be | 
| 25 |  |  |  |  |  |  | returned. | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | This is useful for distributed utilities which run on many machines, and | 
| 28 |  |  |  |  |  |  | cannot use file locks or other such mechanisms due to NFS or lack of common | 
| 29 |  |  |  |  |  |  | file systems. | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | Multiple locks may be requested, in which case the first lock to be free | 
| 32 |  |  |  |  |  |  | will be used.  Lock requests are serviced in a first-in-first-out order, | 
| 33 |  |  |  |  |  |  | and the locker can optionally free locks for any processes that cease to | 
| 34 |  |  |  |  |  |  | exist. | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | =over 4 | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | =item new ([parameter=>value ...]); | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | Create a lock structure. | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | =item lock ([parameter=>value ...]); | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | Try to obtain the lock, return the lock object if successful, else undef. | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | =item locked () | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | Return true if the lock has been obtained. | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | =item lock_name () | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | Return the name of the lock. | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | =item unlock () | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | Remove the given lock.  This will be called automatically when the object | 
| 57 |  |  |  |  |  |  | is destroyed. | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =item ping () | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | A simplified version of ping_status; polls the server to see if it is up. | 
| 62 |  |  |  |  |  |  | Returns true if up, otherwise undef. | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | =item ping_status () | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | Polls the server to see if it is up.  Returns hash reference with {ok} | 
| 67 |  |  |  |  |  |  | indicating if up, and {status} with status information.  If called without | 
| 68 |  |  |  |  |  |  | an object, defaults to call new() with connect_tries=>1, under the | 
| 69 |  |  |  |  |  |  | assumption that a quick go/nogo response is desired. | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | =item break_lock () | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | Remove current locker for the given lock. | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | =item owner ([parameter=>value ...]); | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | Returns a string of who has the lock or undef if not currently locked. | 
| 78 |  |  |  |  |  |  | Note that this information is not atomic, and may change asynchronously; do | 
| 79 |  |  |  |  |  |  | not use this to tell if the lock will be available, to do that, try to | 
| 80 |  |  |  |  |  |  | obtain the lock and then release it if you got it. | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | =back | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | =head1 PARAMETERS | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | =over 4 | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =item block | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | Boolean flag, true indicates wait for the lock when calling lock() and die | 
| 91 |  |  |  |  |  |  | if an error occurs.  False indicates to just return false.  Defaults to | 
| 92 |  |  |  |  |  |  | true. | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | =item connect_tries | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | If none of the lockerd hosts are available or other network errors are | 
| 97 |  |  |  |  |  |  | encountered, perform this number of retries, with a random connect_delay to | 
| 98 |  |  |  |  |  |  | connect_delay*2 interval between them before signalling an error. | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | =item connect_delay | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | The minimum seconds to wait between each of the connect_tries, and | 
| 103 |  |  |  |  |  |  | one-half of the maximum random wait.  Defaults to 30 seconds. | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | =item destroy_unlock | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | Boolean flag, true indicates destruction of the lock variable should unlock | 
| 108 |  |  |  |  |  |  | the lock, only if the current process id matches the pid passed to the | 
| 109 |  |  |  |  |  |  | constructor.  Set to false if destruction should not close the lock, such | 
| 110 |  |  |  |  |  |  | as when other children destroying the lock variable should not unlock the | 
| 111 |  |  |  |  |  |  | lock. | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | =item family | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | The family of transport to use, either INET or UNIX.  Defaults to INET. | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | =item host | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | The name of the host containing the lock server.  It may also be an array | 
| 120 |  |  |  |  |  |  | of hostnames, where if the first one is down, subsequent ones will be | 
| 121 |  |  |  |  |  |  | tried.  Defaults to value of IPCLOCKER_HOST or localhost. | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | =item port | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | The port number (INET) or name (UNIX) of the lock server.  Defaults to | 
| 126 |  |  |  |  |  |  | IPCLOCKER_PORT environment variable, else 'lockerd' looked up via | 
| 127 |  |  |  |  |  |  | /etc/services, else 1751. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =item lock | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | The name of the lock.  This may also be a reference to an array of lock names, | 
| 132 |  |  |  |  |  |  | and the first free lock will be returned. | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | =item lock_list | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | Return a list of lock and lock owner pairs.  (You can assign this to a hash | 
| 137 |  |  |  |  |  |  | for easier parsing.) | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | =item pid | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | The process ID that owns the lock, defaults to the current process id. | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | =item print_broke | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | A function to print a message when the lock is broken.  The only argument | 
| 146 |  |  |  |  |  |  | is self.  Defaults to print a message if verbose is set. | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | =item print_down | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | A function to print a message when the lock server is unavailable.  The | 
| 151 |  |  |  |  |  |  | first argument is self.  Defaults to a croak message. | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =item print_obtained | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | A function to print a message when the lock is obtained after a delay.  The | 
| 156 |  |  |  |  |  |  | only argument is self.  Defaults to print a message if verbose is set. | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | =item print_retry | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | A function to print a message when the lock server is unavailable, and is | 
| 161 |  |  |  |  |  |  | about to be retried.  The first argument is self.  Defaults to a print | 
| 162 |  |  |  |  |  |  | message. | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | =item print_waiting | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | A function to print a message when the lock is busy and needs to be waited | 
| 167 |  |  |  |  |  |  | for.  The first argument is self, second the name of the lock.  Defaults to | 
| 168 |  |  |  |  |  |  | print a message if verbose is set. | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | =item timeout | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | The maximum time in seconds that the lock may be held before being forced | 
| 173 |  |  |  |  |  |  | open, passed to the server when the lock is created.  Thus if the requester | 
| 174 |  |  |  |  |  |  | dies, the lock will be released after that amount of time.  Zero disables | 
| 175 |  |  |  |  |  |  | the timeout.  Defaults to 30 minutes. | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | =item user | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | Name to request the lock under, defaults to host_pid_user | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | =item autounlock | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | True to cause the server to automatically timeout a lock if the locking | 
| 184 |  |  |  |  |  |  | process has died.  For the process to be detected, it must be on the same | 
| 185 |  |  |  |  |  |  | host as either the locker client (the host making the lock call), or the | 
| 186 |  |  |  |  |  |  | locker server.  Defaults false. | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | =item verbose | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | True to print messages when waiting for locks.  Defaults false. | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | =back | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | =head1 ENVIRONMENT | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | =over 4 | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | =item IPCLOCKER_HOST | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | Hostname of L server, or colon separated list including backup | 
| 201 |  |  |  |  |  |  | servers.  Defaults to localhost. | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | =item IPCLOCKER_PORT | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | The port number (INET) or name (UNIX) of the lock server.  Defaults to | 
| 206 |  |  |  |  |  |  | 'lockerd' looked up via /etc/services, else 1751. | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | =back | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | =head1 DISTRIBUTION | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | The latest version is available from CPAN and from L. | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | Copyright 1999-2022 by Wilson Snyder.  This package is free software; you | 
| 215 |  |  |  |  |  |  | can redistribute it and/or modify it under the terms of either the GNU | 
| 216 |  |  |  |  |  |  | Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | =head1 AUTHORS | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | Wilson Snyder | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | L, L | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | L, L, L, L | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | =cut | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | ###################################################################### | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | package IPC::Locker; | 
| 233 |  |  |  |  |  |  | require 5.004; | 
| 234 |  |  |  |  |  |  | require Exporter; | 
| 235 |  |  |  |  |  |  | @ISA = qw(Exporter); | 
| 236 |  |  |  |  |  |  |  | 
| 237 | 3 |  |  | 3 |  | 79995 | use Socket; | 
|  | 3 |  |  |  |  | 14 |  | 
|  | 3 |  |  |  |  | 1088 |  | 
| 238 | 3 |  |  | 3 |  | 1282 | use Time::HiRes qw(gettimeofday tv_interval); | 
|  | 3 |  |  |  |  | 3406 |  | 
|  | 3 |  |  |  |  | 8 |  | 
| 239 | 3 |  |  | 3 |  | 466 | use IO::Socket; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 14 |  | 
| 240 |  |  |  |  |  |  |  | 
| 241 | 3 |  |  | 3 |  | 2547 | use IPC::PidStat; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 88 |  | 
| 242 | 3 |  |  | 3 |  | 14 | use strict; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 65 |  | 
| 243 | 3 |  |  | 3 |  | 21 | use vars qw($VERSION $Debug $Default_Port $Default_Family $Default_UNIX_port $Default_PidStat_Port); | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 170 |  | 
| 244 | 3 |  |  | 3 |  | 14 | use Carp; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 7504 |  | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | ###################################################################### | 
| 247 |  |  |  |  |  |  | #### Configuration Section | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | # Other configurable settings. | 
| 250 |  |  |  |  |  |  | $Debug = 0; | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | $VERSION = '1.502'; | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | ###################################################################### | 
| 255 |  |  |  |  |  |  | #### Useful Globals | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | $Default_Port = ($ENV{IPCLOCKER_PORT}||'lockerd');	# Number (1751) or name to lookup in /etc/services | 
| 258 |  |  |  |  |  |  | $Default_Port = 1751 if ($Default_Port !~ /^\d+$/ && !getservbyname ($Default_Port,"")); | 
| 259 |  |  |  |  |  |  | $Default_PidStat_Port = 'pidstatd';	# Number (1752) or name to lookup in /etc/services | 
| 260 |  |  |  |  |  |  | $Default_PidStat_Port = 1752 if !getservbyname ($Default_PidStat_Port,""); | 
| 261 |  |  |  |  |  |  | $Default_Family = 'INET'; | 
| 262 |  |  |  |  |  |  | $Default_UNIX_port = '/var/locks/lockerd'; | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | ###################################################################### | 
| 265 |  |  |  |  |  |  | #### Creator | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | sub new { | 
| 268 | 6 | 50 |  | 6 | 1 | 1005725 | @_ >= 1 or croak 'usage: IPC::Locker->new ({options})'; | 
| 269 | 6 |  |  |  |  | 17 | my $proto = shift; | 
| 270 | 6 |  | 33 |  |  | 48 | my $class = ref($proto) || $proto; | 
| 271 | 6 |  |  |  |  | 15 | my $hostname = hostfqdn(); | 
| 272 |  |  |  |  |  |  | my $self = { | 
| 273 |  |  |  |  |  |  | #Documented | 
| 274 |  |  |  |  |  |  | host=>($ENV{IPCLOCKER_HOST}||'localhost'), | 
| 275 |  |  |  |  |  |  | port=>$Default_Port, | 
| 276 |  |  |  |  |  |  | lock=>['lock'], | 
| 277 |  |  |  |  |  |  | timeout=>60*10, block=>1, | 
| 278 |  |  |  |  |  |  | pid=>$$, | 
| 279 |  |  |  |  |  |  | #user=>		# below | 
| 280 |  |  |  |  |  |  | hostname=>$hostname, | 
| 281 |  |  |  |  |  |  | autounlock=>0, | 
| 282 |  |  |  |  |  |  | destroy_unlock=>1, | 
| 283 |  |  |  |  |  |  | verbose=>$Debug, | 
| 284 |  |  |  |  |  |  | connect_tries=>3, | 
| 285 |  |  |  |  |  |  | connect_delay=>30, | 
| 286 | 0 | 0 |  | 0 |  | 0 | print_broke=>sub {my $self=shift; print "Broke lock from $_[0] at ".(scalar(localtime))."\n" if $self->{verbose};}, | 
|  | 0 |  |  |  |  | 0 |  | 
| 287 | 0 | 0 |  | 0 |  | 0 | print_obtained=>sub {my $self=shift; print "Obtained lock at ".(scalar(localtime))."\n" if $self->{verbose};}, | 
|  | 0 |  |  |  |  | 0 |  | 
| 288 | 0 | 0 |  | 0 |  | 0 | print_waiting=>sub {my $self=shift; print "Waiting for lock from $_[0] at ".(scalar(localtime))."\n" if $self->{verbose};}, | 
|  | 0 |  |  |  |  | 0 |  | 
| 289 | 0 | 0 |  | 0 |  | 0 | print_retry=>sub {my ($self,$sleep)=@_; print "Unable to connect to server, retrying connection in ${sleep} sec at ".(scalar(localtime))."\n" if $self->{verbose};}, | 
|  | 0 |  |  |  |  | 0 |  | 
| 290 | 6 |  | 50 |  |  | 240 | print_down=>undef, | 
| 291 |  |  |  |  |  |  | family=>$Default_Family, | 
| 292 |  |  |  |  |  |  | #Internal | 
| 293 |  |  |  |  |  |  | locked=>0, | 
| 294 |  |  |  |  |  |  | @_,}; | 
| 295 | 6 |  | 50 |  |  | 37 | $self->{user} ||= hostfqdn() . "_".$self->{pid}."_" . ($ENV{USER} || ""); | 
|  |  |  | 66 |  |  |  |  | 
| 296 | 6 |  |  |  |  | 24 | foreach (_array_or_one($self->{lock})) { | 
| 297 | 6 | 50 |  |  |  | 33 | ($_ !~ /\s/) or carp "%Error: Lock names cannot contain whitespace: $_\n"; | 
| 298 |  |  |  |  |  |  | } | 
| 299 | 6 |  |  |  |  | 13 | bless $self, $class; | 
| 300 | 6 | 50 |  |  |  | 16 | _timelog("Locker->new ",$self->lock_name_list,"\n") if $Debug; | 
| 301 | 6 |  |  |  |  | 18 | return $self; | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | ###################################################################### | 
| 305 |  |  |  |  |  |  | #### Static Accessors | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | sub hostfqdn { | 
| 308 | 11 |  |  | 11 | 0 | 37 | return IPC::PidStat::hostfqdn(); | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | ###################################################################### | 
| 312 |  |  |  |  |  |  | #### Accessors | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | sub locked () { | 
| 315 | 21 | 50 | 33 | 21 | 1 | 31 | my $self = shift; ($self && ref($self)) or croak 'usage: $self->locked()'; | 
|  | 21 |  |  |  |  | 71 |  | 
| 316 | 21 | 100 |  |  |  | 43 | return $self if $self->{locked}; | 
| 317 | 12 |  |  |  |  | 29 | return undef; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub ping { | 
| 321 | 1 |  |  | 1 | 1 | 3 | my $self = shift; | 
| 322 | 1 |  |  |  |  | 3 | my $res = $self->ping_status(@_); | 
| 323 | 1 | 50 |  |  |  | 4 | if ($res->{ok}) { | 
| 324 | 1 |  |  |  |  | 4 | return $self; | 
| 325 |  |  |  |  |  |  | } else { | 
| 326 | 0 |  |  |  |  | 0 | return undef; | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | sub ping_status { | 
| 331 | 1 |  |  | 1 | 1 | 2 | my $self = shift; | 
| 332 |  |  |  |  |  |  | # Return OK and status message, for nagios like checks | 
| 333 | 1 | 50 |  |  |  | 3 | $self = $self->new(connect_tries=>1, @_) if (!ref($self)); | 
| 334 | 1 |  |  |  |  | 2 | my $ok = 0; | 
| 335 | 1 |  |  |  |  | 4 | my $start_time = [gettimeofday()]; | 
| 336 | 1 |  |  |  |  | 2 | eval { | 
| 337 | 1 |  |  |  |  | 3 | $self->_request(""); | 
| 338 | 1 |  |  |  |  | 2 | $ok = 1; | 
| 339 |  |  |  |  |  |  | }; | 
| 340 | 1 |  |  |  |  | 23 | my $elapsed = tv_interval ( $start_time, [gettimeofday]); | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 1 | 50 |  |  |  | 19 | if (!$ok) { | 
| 343 | 0 |  |  |  |  | 0 | return ({ok=>undef,status=>"No response from lockerd on $self->{host}:$self->{port}"}); | 
| 344 |  |  |  |  |  |  | } else { | 
| 345 | 1 |  |  |  |  | 19 | return ({ok=>1,status=>sprintf("%1.3f second response on $self->{host}:$self->{port}", $elapsed)}); | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | ###################################################################### | 
| 350 |  |  |  |  |  |  | #### Constructor | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | sub lock { | 
| 353 | 8 |  |  | 8 | 1 | 957 | my $self = shift; | 
| 354 | 8 | 100 |  |  |  | 24 | $self = $self->new(@_) if (!ref($self)); | 
| 355 | 8 | 100 |  |  |  | 14 | if (!$self->locked) { | 
| 356 | 6 |  |  |  |  | 20 | $self->_request("LOCK"); | 
| 357 | 6 | 50 |  |  |  | 17 | croak $self->{error} if $self->{error}; | 
| 358 |  |  |  |  |  |  | } | 
| 359 | 8 | 100 |  |  |  | 39 | return ($self) if $self->{locked}; | 
| 360 | 2 |  |  |  |  | 15 | return undef; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | ###################################################################### | 
| 364 |  |  |  |  |  |  | #### Destructor/Unlock | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | sub DESTROY () { | 
| 367 | 6 | 50 | 33 | 6 |  | 601 | my $self = shift; ($self && ref($self)) or croak 'usage: $self->DESTROY()'; | 
|  | 6 |  |  |  |  | 27 |  | 
| 368 | 6 | 50 | 33 |  |  | 32 | if ($self->{destroy_unlock} && $self->{pid} && $self->{pid}==$$) { | 
|  |  |  | 33 |  |  |  |  | 
| 369 | 6 |  |  |  |  | 12 | $self->unlock(); | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | sub unlock { | 
| 374 | 8 | 50 | 33 | 8 | 1 | 8 | my $self = shift; ($self && ref($self)) or croak 'usage: $self->unlock()'; | 
|  | 8 |  |  |  |  | 21 |  | 
| 375 | 8 | 100 |  |  |  | 14 | if ($self->locked) { | 
| 376 | 4 |  |  |  |  | 8 | $self->_request("UNLOCK"); | 
| 377 | 4 | 50 |  |  |  | 10 | croak $self->{error} if $self->{error}; | 
| 378 |  |  |  |  |  |  | } | 
| 379 | 8 |  |  |  |  | 198 | return ($self); | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | sub break_lock { | 
| 383 | 0 | 0 |  | 0 | 1 | 0 | my $self = shift; ($self) or croak 'usage: $self->break_lock()'; | 
|  | 0 |  |  |  |  | 0 |  | 
| 384 | 0 | 0 |  |  |  | 0 | $self = $self->new(@_) if (!ref($self)); | 
| 385 | 0 |  |  |  |  | 0 | $self->_request("BREAK_LOCK"); | 
| 386 | 0 | 0 |  |  |  | 0 | croak $self->{error} if $self->{error}; | 
| 387 | 0 |  |  |  |  | 0 | return ($self); | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | sub dead_pid { | 
| 391 | 0 | 0 |  | 0 | 0 | 0 | my $self = shift; (ref $self) or croak 'usage: $self->dead_pid()'; | 
|  | 0 |  |  |  |  | 0 |  | 
| 392 | 0 |  |  |  |  | 0 | my %args = (host => hostfqdn(), | 
| 393 |  |  |  |  |  |  | pid => -1, | 
| 394 |  |  |  |  |  |  | @_); | 
| 395 |  |  |  |  |  |  | # Used internally to indicate a pid is gone. | 
| 396 | 0 |  |  |  |  | 0 | $self->_request("DEAD_PID $args{host} $args{pid}"); | 
| 397 | 0 | 0 |  |  |  | 0 | croak $self->{error} if $self->{error}; | 
| 398 | 0 |  |  |  |  | 0 | return ($self); | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | ###################################################################### | 
| 402 |  |  |  |  |  |  | #### User utilities: owner | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | sub owner { | 
| 405 | 1 | 50 |  | 1 | 1 | 2 | my $self = shift; ($self) or croak 'usage: $self->status()'; | 
|  | 1 |  |  |  |  | 3 |  | 
| 406 | 1 | 50 |  |  |  | 2 | $self = $self->new(@_) if (!ref($self)); | 
| 407 | 1 |  |  |  |  | 3 | $self->_request ("STATUS"); | 
| 408 | 1 | 50 |  |  |  | 3 | croak $self->{error} if $self->{error}; | 
| 409 | 1 | 50 | 0 |  |  | 3 | _timelog("Locker->owner = ",($self->{owner}||''),"\n") if $Debug; | 
| 410 | 1 |  |  |  |  | 4 | return $self->{owner}; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | sub lock_name { | 
| 414 | 2 | 50 |  | 2 | 1 | 248 | my $self = shift; ($self) or croak 'usage: $self->lock_name()'; | 
|  | 2 |  |  |  |  | 5 |  | 
| 415 | 2 | 50 | 33 |  |  | 5 | if (ref $self->{lock} | 
| 416 | 0 |  |  |  |  | 0 | && $#{$self->{lock}}<1) { | 
| 417 | 0 |  |  |  |  | 0 | return $self->{lock}[0]; | 
| 418 |  |  |  |  |  |  | } else { | 
| 419 | 2 |  |  |  |  | 9 | return $self->{lock}; | 
| 420 |  |  |  |  |  |  | } | 
| 421 |  |  |  |  |  |  | } | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | sub lock_list { | 
| 424 | 1 |  |  | 1 | 1 | 3 | my $self = shift; | 
| 425 | 1 | 50 |  |  |  | 3 | $self = $self->new(@_) if (!ref($self)); | 
| 426 | 1 |  |  |  |  | 3 | $self->_request("LOCK_LIST"); | 
| 427 | 1 | 50 |  |  |  | 3 | croak $self->{error} if $self->{error}; | 
| 428 | 1 |  |  |  |  | 2 | return @{$self->{lock_list}}; | 
|  | 1 |  |  |  |  | 9 |  | 
| 429 |  |  |  |  |  |  | } | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | ###################################################################### | 
| 432 |  |  |  |  |  |  | ###################################################################### | 
| 433 |  |  |  |  |  |  | #### Guts: Sending and receiving messages | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | sub _request { | 
| 436 | 13 |  |  | 13 |  | 14 | my $self = shift; | 
| 437 | 13 |  |  |  |  | 46 | my $cmd = shift; | 
| 438 |  |  |  |  |  |  |  | 
| 439 | 13 |  |  |  |  | 29 | my @hostlist = ('localhost'); | 
| 440 | 13 | 50 |  |  |  | 26 | if ($self->{family} eq 'INET') { | 
| 441 | 13 |  |  |  |  | 17 | @hostlist = ($self->{host}); | 
| 442 | 13 | 50 |  |  |  | 44 | @hostlist = split (':', $self->{host}) if (!ref($self->{host})); | 
| 443 | 13 | 50 |  |  |  | 21 | @hostlist = @{$self->{host}} if (ref($self->{host}) eq "ARRAY"); | 
|  | 0 |  |  |  |  | 0 |  | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 | 13 |  |  |  |  | 12 | my $ok; | 
| 447 |  |  |  |  |  |  | try: | 
| 448 | 13 |  | 50 |  |  | 35 | for (my $tries = 0; $tries < ($self->{connect_tries}||1); $tries++) { | 
| 449 | 13 | 50 |  |  |  | 17 | if ($tries > 0) { | 
| 450 | 0 |  |  |  |  | 0 | my $sleep = $self->{connect_delay} + int(rand($self->{connect_delay})); | 
| 451 | 0 | 0 |  |  |  | 0 | _timelog("Locker->connect_delay $sleep sec\n") if $Debug; | 
| 452 | 0 |  |  |  |  | 0 | &{$self->{print_retry}} ($self, $sleep); | 
|  | 0 |  |  |  |  | 0 |  | 
| 453 | 0 |  |  |  |  | 0 | sleep($sleep); | 
| 454 |  |  |  |  |  |  | } | 
| 455 | 13 |  |  |  |  | 15 | foreach my $host (@hostlist) { | 
| 456 | 13 |  |  |  |  | 31 | $ok = $self->_request_attempt($cmd,$host); | 
| 457 | 13 | 50 |  |  |  | 24 | if ($ok) { | 
| 458 | 13 | 50 |  |  |  | 21 | if ($host ne $hostlist[0]) { | 
| 459 |  |  |  |  |  |  | # Reorganize host list so whoever responded is first | 
| 460 |  |  |  |  |  |  | # This is so if we grab a lock we'll try to return it to the same host | 
| 461 | 0 |  |  |  |  | 0 | $self->{host} = [$host, grep( ($_ ne $host), @hostlist)]; | 
| 462 |  |  |  |  |  |  | } | 
| 463 | 13 |  |  |  |  | 21 | last try; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 13 | 50 |  |  |  | 17 | if (!$ok) { | 
| 469 | 0 | 0 |  |  |  | 0 | if (defined $self->{print_down}) { | 
| 470 | 0 |  |  |  |  | 0 | &{$self->{print_down}} ($self); | 
|  | 0 |  |  |  |  | 0 |  | 
| 471 | 0 |  |  |  |  | 0 | return; | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | croak "%Error: Can't locate lock server on " | 
| 474 | 0 | 0 |  |  |  | 0 | . (($self->{family} eq 'INET') ? (join " or ", @hostlist) : "UNIX port") | 
| 475 |  |  |  |  |  |  | ." $self->{port}\n" | 
| 476 |  |  |  |  |  |  | . "\tYou probably need to run lockerd\n$self->_request(): Stopped"; | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 13 | 50 |  |  |  | 25 | _timelog("Locker->DONE\n") if $Debug; | 
| 480 |  |  |  |  |  |  | } | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | sub _request_attempt { | 
| 483 | 13 |  |  | 13 |  | 14 | my $self = shift; | 
| 484 | 13 |  |  |  |  | 12 | my $cmd = shift; | 
| 485 | 13 |  |  |  |  | 27 | my $host = shift; | 
| 486 |  |  |  |  |  |  | # Return true if request was successful | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | # IO::Socket::INET nastily undef's $@.  Since this may get called | 
| 489 |  |  |  |  |  |  | # in a destructor due to an error, that looses the error message. | 
| 490 |  |  |  |  |  |  | # Workaround: save the error and restore at the end. | 
| 491 | 13 |  |  |  |  | 12 | my $preerror = $@; | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | retry: | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | # If adding new features, only send the new feature to the server | 
| 496 |  |  |  |  |  |  | # if the feature is on.  This allows for newer clients that don't | 
| 497 |  |  |  |  |  |  | # need to the new feature to still talk to older servers. | 
| 498 |  |  |  |  |  |  | my $req = ("user $self->{user}\n" | 
| 499 | 13 |  |  |  |  | 24 | ."locks ".join(' ',@{_array_or_one($self->{lock})})."\n"); | 
|  | 13 |  |  |  |  | 18 |  | 
| 500 |  |  |  |  |  |  | $req.=    ("block ".($self->{block}||0)."\n" | 
| 501 | 13 | 100 | 100 |  |  | 52 | ."timeout ".($self->{timeout}||0)."\n") if $cmd ne 'UNLOCK'; | 
|  |  |  | 50 |  |  |  |  | 
| 502 |  |  |  |  |  |  | $req.=    ("autounlock ".($self->{autounlock}||0)."\n" | 
| 503 |  |  |  |  |  |  | ."pid ".($self->{pid}||$$)."\n" | 
| 504 |  |  |  |  |  |  | ."hostname ".($self->{hostname})."\n" | 
| 505 | 13 | 100 | 50 |  |  | 47 | ) if $self->{autounlock} && $cmd ne 'UNLOCK'; | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 506 | 13 |  |  |  |  | 23 | $req.=    ("$cmd\n" | 
| 507 |  |  |  |  |  |  | ."\n"  # End of group.  Some day we may not always send EOF immediately | 
| 508 |  |  |  |  |  |  | ."EOF\n"); | 
| 509 | 13 | 50 |  |  |  | 17 | _timelog("Locker->REQ\nR   ",join("\nR   ",split(/\n/,$req)),"\n") if $Debug; | 
| 510 |  |  |  |  |  |  |  | 
| 511 | 13 |  |  |  |  | 12 | my $fh; | 
| 512 | 13 | 50 |  |  |  | 22 | if ($self->{family} eq 'INET') { | 
|  |  | 0 |  |  |  |  |  | 
| 513 | 13 | 50 |  |  |  | 15 | _timelog("Locker->Trying host $host $self->{port}\n") if $Debug; | 
| 514 |  |  |  |  |  |  | $fh = IO::Socket::INET->new( Proto     => _tcp_proto(), | 
| 515 |  |  |  |  |  |  | PeerAddr  => $host, | 
| 516 | 13 |  |  |  |  | 39 | PeerPort  => $self->{port}, ); | 
| 517 |  |  |  |  |  |  | } elsif ($self->{family} eq 'UNIX') { | 
| 518 | 0 | 0 |  |  |  | 0 | _timelog("Locker->Trying UNIX socket\n") if $Debug; | 
| 519 | 0 |  |  |  |  | 0 | $fh = IO::Socket::UNIX->new( Peer => $self->{port}, ); | 
| 520 |  |  |  |  |  |  | } else { | 
| 521 | 0 |  |  |  |  | 0 | croak "IPC::Locker->_request(): No or wrong transport specified."; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 | 13 | 50 |  |  |  | 4366 | return undef if !$fh; | 
| 525 |  |  |  |  |  |  |  | 
| 526 | 13 |  |  |  |  | 37 | $self->{lock_list} = []; | 
| 527 |  |  |  |  |  |  |  | 
| 528 | 13 |  |  |  |  | 328 | print $fh "$req\n"; | 
| 529 | 13 |  |  |  |  | 9277 | while (defined (my $line = <$fh>)) { | 
| 530 | 52 |  |  |  |  | 69 | chomp $line; | 
| 531 | 52 | 100 |  |  |  | 544 | next if $line =~ /^\s*$/; | 
| 532 | 28 |  |  |  |  | 87 | my @args = split /\s+/, $line; | 
| 533 | 28 |  |  |  |  | 39 | my $cmd = shift @args; | 
| 534 | 28 | 50 |  |  |  | 41 | _timelog("RESP $line\n") if $Debug; | 
| 535 | 28 | 100 |  |  |  | 40 | $self->{locked} = $args[0] if ($cmd eq "locked"); | 
| 536 | 28 | 100 |  |  |  | 42 | $self->{owner}  = $args[0] if ($cmd eq "owner"); | 
| 537 | 28 | 50 |  |  |  | 33 | $self->{error}  = $args[0] if ($cmd eq "error"); | 
| 538 | 28 | 100 |  |  |  | 32 | if ($cmd eq "lockname") {  # LOCK request's reply | 
| 539 | 5 |  |  |  |  | 10 | $self->{lock}   = [$args[0]]; | 
| 540 | 5 | 50 |  |  |  | 5 | $self->{lock}   = $self->{lock}[0] if ($#{$self->{lock}}<1);  # Back compatible | 
|  | 5 |  |  |  |  | 15 |  | 
| 541 |  |  |  |  |  |  | } | 
| 542 | 28 | 100 | 66 |  |  | 60 | if ($cmd eq 'lock' && @args == 2) {  # LOCK_LIST request's reply | 
| 543 | 1 |  |  |  |  | 3 | push @{$self->{lock_list}}, @args; | 
|  | 1 |  |  |  |  | 3 |  | 
| 544 |  |  |  |  |  |  | } | 
| 545 | 28 | 50 |  |  |  | 30 | if ($cmd eq "autounlock_check") { | 
| 546 |  |  |  |  |  |  | # See if we can break the lock because the lock holder ran on this same machine. | 
| 547 | 0 |  |  |  |  | 0 | my ($lname,$lhost,$lpid,$supports_dead) = @args; | 
| 548 | 0 | 0 |  |  |  | 0 | if ($self->{hostname} eq $lhost) { | 
| 549 | 0 | 0 |  |  |  | 0 | if (IPC::PidStat::local_pid_doesnt_exist($lpid)) { | 
| 550 | 0 | 0 |  |  |  | 0 | _timelog("Autounlock_LOCAL $lname $lhost $lpid $supports_dead\n") if $Debug; | 
| 551 | 0 | 0 |  |  |  | 0 | if ($supports_dead) {  # 1.480 server and newer | 
| 552 | 0 |  |  |  |  | 0 | $self->dead_pid(host=>$lhost, pid=>$lpid); | 
| 553 |  |  |  |  |  |  | } else {  # This has a potential race case, which may kill the wrong lock | 
| 554 | 0 |  |  |  |  | 0 | $self->break_lock(lock=>$self->{lock}); | 
| 555 |  |  |  |  |  |  | } | 
| 556 | 0 |  |  |  |  | 0 | $fh->close(); | 
| 557 | 0 |  |  |  |  | 0 | goto retry; | 
| 558 |  |  |  |  |  |  | } | 
| 559 |  |  |  |  |  |  | } | 
| 560 |  |  |  |  |  |  | } | 
| 561 | 28 | 50 |  |  |  | 35 | &{$self->{print_obtained}} ($self,@args)  if ($cmd eq "print_obtained"); | 
|  | 0 |  |  |  |  | 0 |  | 
| 562 | 28 | 50 |  |  |  | 32 | &{$self->{print_waiting}}  ($self,@args)  if ($cmd eq "print_waiting"); | 
|  | 0 |  |  |  |  | 0 |  | 
| 563 | 28 | 50 |  |  |  | 33 | &{$self->{print_broke}}    ($self,@args)  if ($cmd eq "print_broke"); | 
|  | 0 |  |  |  |  | 0 |  | 
| 564 | 28 | 0 | 33 |  |  | 79 | print "$1\n" if ($line =~ /^ECHO\s+(.*)$/ && $self->{verbose});  #debugging | 
| 565 |  |  |  |  |  |  | } | 
| 566 |  |  |  |  |  |  | # Note above break_lock also has prologue close | 
| 567 | 13 |  |  |  |  | 68 | $fh->close(); | 
| 568 |  |  |  |  |  |  |  | 
| 569 | 13 |  | 66 |  |  | 645 | $@ = $preerror || $@;  # User's error is more important than any we make | 
| 570 | 13 |  |  |  |  | 56 | return 1; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | ###################################################################### | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | our $_Tcp_Proto; | 
| 576 |  |  |  |  |  |  | sub _tcp_proto { | 
| 577 |  |  |  |  |  |  | # We don't want creating a socket to have to keep reading /etc/services | 
| 578 |  |  |  |  |  |  | # One would have thought IO::Socket etc kept this for us... | 
| 579 | 13 | 100 |  | 13 |  | 19 | if (!defined $_Tcp_Proto) { | 
| 580 | 1 | 50 |  |  |  | 109 | $_Tcp_Proto = getprotobyname("tcp") | 
| 581 |  |  |  |  |  |  | or die "Could not determine the protocol number for tcp"; | 
| 582 |  |  |  |  |  |  | } | 
| 583 | 13 |  |  |  |  | 152 | return $_Tcp_Proto; | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | sub _array_or_one { | 
| 587 | 19 | 100 |  | 19 |  | 52 | return [$_[0]] if !ref $_[0]; | 
| 588 | 10 |  |  |  |  | 24 | return $_[0]; | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | sub colon_joined_list { | 
| 592 | 0 |  |  | 0 | 0 |  | my $item = shift; | 
| 593 | 0 | 0 |  |  |  |  | return $item if !ref $item; | 
| 594 | 0 |  |  |  |  |  | return (join ":",@{$item}); | 
|  | 0 |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | } | 
| 596 |  |  |  |  |  |  |  | 
| 597 |  |  |  |  |  |  | sub lock_name_list { | 
| 598 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 599 | 0 |  |  |  |  |  | return colon_joined_list($self->{lock}); | 
| 600 |  |  |  |  |  |  | } | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | ###################################################################### | 
| 603 |  |  |  |  |  |  | #### Logging | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | sub _timelog { | 
| 606 | 0 |  |  | 0 |  |  | my $msg = join('',@_); | 
| 607 | 0 |  |  |  |  |  | my ($time, $time_usec) = Time::HiRes::gettimeofday(); | 
| 608 | 0 |  |  |  |  |  | my ($sec,$min,$hour,$mday,$mon) = localtime($time); | 
| 609 | 0 |  |  |  |  |  | printf +("[%02d/%02d %02d:%02d:%02d.%06d] %s", | 
| 610 |  |  |  |  |  |  | $mon+1, $mday, $hour, $min, $sec, $time_usec, $msg); | 
| 611 |  |  |  |  |  |  | } | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | sub _timelog_split { | 
| 614 | 0 |  |  | 0 |  |  | my $first = shift; | 
| 615 | 0 |  |  |  |  |  | my $prefix = shift; | 
| 616 | 0 |  |  |  |  |  | my $text = shift; | 
| 617 | 0 |  |  |  |  |  | my $msg = $first . join("\n$prefix", split(/\n+/, "\n$text")) . "\n"; | 
| 618 | 0 |  |  |  |  |  | _timelog($msg) | 
| 619 |  |  |  |  |  |  | } | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | ###################################################################### | 
| 622 |  |  |  |  |  |  | #### Package return | 
| 623 |  |  |  |  |  |  | 1; |