home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / checkbox / contrib / glock.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-10-12  |  10.0 KB  |  309 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''
  5. This module defines the class GlobalLock that implements a global
  6. (inter-process) mutex on Windows and Unix, using file-locking on
  7. Unix.
  8.  
  9. @see: class L{GlobalLock} for more details.
  10. '''
  11. __version__ = '0.2.' + '$Revision: #5 $'[12:-2]
  12. __author__ = ('Richard Gruet', 'rjgruet@yahoo.com')
  13. __date__ = ('$Date: 2005/06/19 $'[7:-2], '$Author: rgruet $'[9:-2])
  14. __since__ = '2000-01-22'
  15. __doc__ += '\n@author: %s (U{%s})\n@version: %s' % (__author__[0], __author__[1], __version__)
  16. __all__ = [
  17.     'GlobalLock',
  18.     'GlobalLockError',
  19.     'LockAlreadyAcquired',
  20.     'NotOwner']
  21. import sys
  22. import string
  23. import os
  24. import errno
  25. import re
  26. import posixpath
  27. _windows = sys.platform == 'win32'
  28. if _windows:
  29.     
  30.     try:
  31.         import win32event
  32.         import win32api
  33.         import pywintypes
  34.     except ImportError:
  35.         sys.stderr.write('The win32 extensions need to be installed!')
  36.  
  37.     
  38.     try:
  39.         import ctypes
  40.     except ImportError:
  41.         ctypes = None
  42.     except:
  43.         None<EXCEPTION MATCH>ImportError
  44.     
  45.  
  46. None<EXCEPTION MATCH>ImportError
  47.  
  48. try:
  49.     import fcntl
  50. except ImportError:
  51.     sys.stderr.write("On what kind of OS am I ? (Mac?) I should be on Unix but can't import fcntl.\n")
  52.     raise 
  53.  
  54. import threading
  55.  
  56. class GlobalLockError(Exception):
  57.     ''' Error raised by the glock module.
  58.     '''
  59.     pass
  60.  
  61.  
  62. class NotOwner(GlobalLockError):
  63.     """ Attempt to release somebody else's lock.
  64.     """
  65.     pass
  66.  
  67.  
  68. class LockAlreadyAcquired(GlobalLockError):
  69.     ''' Non-blocking acquire but lock already seized.
  70.     '''
  71.     pass
  72.  
  73. if sys.version[:3] < '2.2':
  74.     (True, False) = (1, 0)
  75.  
  76.  
  77. class GlobalLock:
  78.     """ A global mutex.
  79.  
  80.         B{Specification}
  81.  
  82.          - The lock must act as a global mutex, ie block between different
  83.            candidate processus, but ALSO between different candidate
  84.            threads of the same process.
  85.  
  86.          - It must NOT block in case of reentrant lock request issued by
  87.            the SAME thread.
  88.          - Extraneous unlocks should be ideally harmless.
  89.  
  90.         B{Implementation}
  91.  
  92.         In Python there is no portable global lock AFAIK. There is only a
  93.         LOCAL/ in-process Lock mechanism (threading.RLock), so we have to
  94.         implement our own solution:
  95.  
  96.          - Unix: use fcntl.flock(). Recursive calls OK. Different process OK.
  97.            But <> threads, same process don't block so we have to use an extra
  98.            threading.RLock to fix that point.
  99.          - Windows: We use WIN32 mutex from Python Win32 extensions. Can't use
  100.            std module msvcrt.locking(), because global lock is OK, but
  101.            blocks also for 2 calls from the same thread!
  102.     """
  103.     RE_ERROR_MSG = re.compile('^\\[Errno ([0-9]+)\\]')
  104.     
  105.     def __init__(self, fpath, lockInitially = False, logger = None):
  106.         ''' Creates (or opens) a global lock.
  107.  
  108.             @param fpath: Path of the file used as lock target. This is also
  109.                           the global id of the lock. The file will be created
  110.                           if non existent.
  111.             @param lockInitially: if True locks initially.
  112.             @param logger: an optional logger object.
  113.         '''
  114.         self.logger = logger
  115.         self.fpath = fpath
  116.         if posixpath.exists(fpath):
  117.             self.previous_lockfile_present = True
  118.         else:
  119.             self.previous_lockfile_present = False
  120.         if _windows:
  121.             self.name = string.replace(fpath, '\\', '_')
  122.             self.mutex = win32event.CreateMutex(None, lockInitially, self.name)
  123.         else:
  124.             self.name = fpath
  125.             self.flock = open(fpath, 'w')
  126.             self.fdlock = self.flock.fileno()
  127.             self.threadLock = threading.RLock()
  128.         if lockInitially:
  129.             self.acquire()
  130.         
  131.  
  132.     
  133.     def __del__(self):
  134.         
  135.         try:
  136.             self.release()
  137.         except:
  138.             pass
  139.  
  140.         if _windows:
  141.             win32api.CloseHandle(self.mutex)
  142.         else:
  143.             
  144.             try:
  145.                 self.flock.close()
  146.             except:
  147.                 pass
  148.  
  149.  
  150.     
  151.     def __repr__(self):
  152.         return '<Global lock @ %s>' % self.name
  153.  
  154.     
  155.     def acquire(self, blocking = False):
  156.         """ Locks. Attemps to acquire a lock.
  157.  
  158.             @param blocking: If True, suspends caller until done. Otherwise,
  159.             LockAlreadyAcquired is raised if the lock cannot be acquired immediately.
  160.  
  161.             On windows an IOError is always raised after ~10 sec if the lock
  162.             can't be acquired.
  163.             @exception GlobalLockError: if lock can't be acquired (timeout)
  164.             @exception LockAlreadyAcquired: someone already has the lock and
  165.                        the caller decided not to block.
  166.         """
  167.         if self.logger:
  168.             self.logger.info('creating lockfile')
  169.         
  170.         if _windows:
  171.             if blocking:
  172.                 timeout = win32event.INFINITE
  173.             else:
  174.                 timeout = 0
  175.             r = win32event.WaitForSingleObject(self.mutex, timeout)
  176.             if r == win32event.WAIT_FAILED:
  177.                 raise GlobalLockError("Can't acquire mutex: error")
  178.             r == win32event.WAIT_FAILED
  179.             if not blocking and r == win32event.WAIT_TIMEOUT:
  180.                 raise LockAlreadyAcquired('Lock %s already acquired by someone else' % self.name)
  181.             r == win32event.WAIT_TIMEOUT
  182.         elif blocking:
  183.             options = fcntl.LOCK_EX
  184.         else:
  185.             options = fcntl.LOCK_EX | fcntl.LOCK_NB
  186.         
  187.         try:
  188.             fcntl.flock(self.fdlock, options)
  189.         except IOError:
  190.             message = None
  191.             if not blocking and self._errnoOf(message) == errno.EWOULDBLOCK:
  192.                 raise LockAlreadyAcquired('Lock %s already acquired by someone else' % self.name)
  193.             self._errnoOf(message) == errno.EWOULDBLOCK
  194.             raise GlobalLockError('Cannot acquire lock on "file" %s: %s\n' % (self.name, message))
  195.  
  196.         if not self.threadLock.acquire(blocking):
  197.             fcntl.flock(self.fdlock, fcntl.LOCK_UN)
  198.             raise LockAlreadyAcquired('Lock %s already acquired by someone else' % self.name)
  199.         self.threadLock.acquire(blocking)
  200.         if self.previous_lockfile_present and self.logger:
  201.             self.logger.warn('Stale lockfile detected and claimed.')
  202.         
  203.         self.is_locked = True
  204.  
  205.     
  206.     def release(self, skip_delete = False):
  207.         """ Unlocks. (caller must own the lock!)
  208.  
  209.             @param skip_delete: don't try to delete the file. This can
  210.                 be used when the original filename has changed; for
  211.                 instance, if the lockfile is erased out-of-band, or if
  212.                 the directory it contains has been renamed.
  213.  
  214.             @return: The lock count.
  215.             @exception IOError: if file lock can't be released
  216.             @exception NotOwner: Attempt to release somebody else's lock.
  217.         """
  218.         if not self.is_locked:
  219.             return None
  220.         if not skip_delete:
  221.             if self.logger:
  222.                 self.logger.debug('Removing lock file: %s', self.fpath)
  223.             
  224.             os.unlink(self.fpath)
  225.         elif self.logger:
  226.             self.logger.debug('Oops, my lock file disappeared: %s', self.fpath)
  227.         
  228.         if _windows:
  229.             pass
  230.         None if ctypes else None<EXCEPTION MATCH>pywintypes.error
  231.         
  232.         try:
  233.             self.threadLock.release()
  234.         except AssertionError:
  235.             raise NotOwner("Attempt to release somebody else's lock")
  236.  
  237.         
  238.         try:
  239.             fcntl.flock(self.fdlock, fcntl.LOCK_UN)
  240.         except IOError:
  241.             raise GlobalLockError('Unlock of file "%s" failed\n' % self.name)
  242.  
  243.         self.is_locked = False
  244.  
  245.     
  246.     def _errnoOf(self, message):
  247.         match = self.RE_ERROR_MSG.search(str(message))
  248.         if match:
  249.             return int(match.group(1))
  250.         raise Exception('Malformed error message "%s"' % message)
  251.  
  252.  
  253.  
  254. def test():
  255.     print 'Testing glock.py...'
  256.     lockName = 'myFirstLock'
  257.     l = GlobalLock(lockName)
  258.     if not _windows:
  259.         if not posixpath.exists(lockName):
  260.             raise AssertionError
  261.     
  262.     l.acquire()
  263.     l.acquire()
  264.     l.release()
  265.     l.release()
  266.     
  267.     try:
  268.         l.release()
  269.     except NotOwner:
  270.         pass
  271.  
  272.     raise Exception('should have raised a NotOwner exception')
  273.     import threading
  274.     import time
  275.     thread = threading.Thread(target = threadMain, args = (l,))
  276.     print 'main: locking...',
  277.     l.acquire()
  278.     print ' done.'
  279.     thread.start()
  280.     time.sleep(3)
  281.     print '\nmain: unlocking...',
  282.     l.release()
  283.     print ' done.'
  284.     time.sleep(0.1)
  285.     print '=> Test of glock.py passed.'
  286.     return l
  287.  
  288.  
  289. def threadMain(lock):
  290.     print 'thread started(%s).' % lock
  291.     
  292.     try:
  293.         lock.acquire(blocking = False)
  294.     except LockAlreadyAcquired:
  295.         pass
  296.  
  297.     raise Exception('should have raised LockAlreadyAcquired')
  298.     print 'thread: locking (should stay blocked for ~ 3 sec)...',
  299.     lock.acquire()
  300.     print 'thread: locking done.'
  301.     print 'thread: unlocking...',
  302.     lock.release()
  303.     print ' done.'
  304.     print 'thread ended.'
  305.  
  306. if __name__ == '__main__':
  307.     l = test()
  308.  
  309.