mercurial/lock.py
changeset 2016 ff5c9a92f556
parent 1877 d314a89fa4f1
child 2579 0875cda033fd
equal deleted inserted replaced
2009:182f500805db 2016:ff5c9a92f556
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 from demandload import *
     8 from demandload import *
     9 demandload(globals(), 'errno os socket time util')
     9 demandload(globals(), 'errno os socket time util')
    10 
    10 
    11 class LockException(Exception):
    11 class LockException(IOError):
    12     pass
    12     def __init__(self, errno, strerror, filename, desc):
       
    13         IOError.__init__(self, errno, strerror, filename)
       
    14         self.desc = desc
       
    15 
    13 class LockHeld(LockException):
    16 class LockHeld(LockException):
    14     pass
    17     def __init__(self, errno, filename, desc, locker):
       
    18         LockException.__init__(self, errno, 'Lock held', filename, desc)
       
    19         self.locker = locker
       
    20 
    15 class LockUnavailable(LockException):
    21 class LockUnavailable(LockException):
    16     pass
    22     pass
    17 
    23 
    18 class lock(object):
    24 class lock(object):
    19     # lock is symlink on platforms that support it, file on others.
    25     # lock is symlink on platforms that support it, file on others.
    22     # are atomic even over nfs.
    28     # are atomic even over nfs.
    23 
    29 
    24     # old-style lock: symlink to pid
    30     # old-style lock: symlink to pid
    25     # new-style lock: symlink to hostname:pid
    31     # new-style lock: symlink to hostname:pid
    26 
    32 
    27     def __init__(self, file, timeout=-1, releasefn=None):
    33     def __init__(self, file, timeout=-1, releasefn=None, desc=None):
    28         self.f = file
    34         self.f = file
    29         self.held = 0
    35         self.held = 0
    30         self.timeout = timeout
    36         self.timeout = timeout
    31         self.releasefn = releasefn
    37         self.releasefn = releasefn
    32         self.id = None
    38         self.id = None
    33         self.host = None
    39         self.host = None
    34         self.pid = None
    40         self.pid = None
       
    41         self.desc = desc
    35         self.lock()
    42         self.lock()
    36 
    43 
    37     def __del__(self):
    44     def __del__(self):
    38         self.release()
    45         self.release()
    39 
    46 
    47                 if timeout != 0:
    54                 if timeout != 0:
    48                     time.sleep(1)
    55                     time.sleep(1)
    49                     if timeout > 0:
    56                     if timeout > 0:
    50                         timeout -= 1
    57                         timeout -= 1
    51                     continue
    58                     continue
    52                 raise inst
    59                 raise LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
       
    60                                inst.locker)
    53 
    61 
    54     def trylock(self):
    62     def trylock(self):
    55         if self.id is None:
    63         if self.id is None:
    56             self.host = socket.gethostname()
    64             self.host = socket.gethostname()
    57             self.pid = os.getpid()
    65             self.pid = os.getpid()
    62                 self.held = 1
    70                 self.held = 1
    63             except (OSError, IOError), why:
    71             except (OSError, IOError), why:
    64                 if why.errno == errno.EEXIST:
    72                 if why.errno == errno.EEXIST:
    65                     locker = self.testlock()
    73                     locker = self.testlock()
    66                     if locker:
    74                     if locker:
    67                         raise LockHeld(locker)
    75                         raise LockHeld(errno.EAGAIN, self.f, self.desc,
       
    76                                        locker)
    68                 else:
    77                 else:
    69                     raise LockUnavailable(why)
    78                     raise LockUnavailable(why.errno, why.strerror,
       
    79                                           why.filename, self.desc)
    70 
    80 
    71     def testlock(self):
    81     def testlock(self):
    72         '''return id of locker if lock is valid, else None.'''
    82         '''return id of locker if lock is valid, else None.'''
    73         # if old-style lock, we cannot tell what machine locker is on.
    83         # if old-style lock, we cannot tell what machine locker is on.
    74         # with new-style lock, if locker is on this machine, we can
    84         # with new-style lock, if locker is on this machine, we can