These files are a subset of the python-2.7.2.tgz distribution from python.org. Changed files from PyMod-2.7.2 have been copied into the corresponding directories of this tree, replacing the original files in the distribution. Signed-off-by: daryl.mcdaniel@intel.com git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13197 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			281 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""CVS locking algorithm.
 | 
						|
 | 
						|
CVS locking strategy
 | 
						|
====================
 | 
						|
 | 
						|
As reverse engineered from the CVS 1.3 sources (file lock.c):
 | 
						|
 | 
						|
- Locking is done on a per repository basis (but a process can hold
 | 
						|
write locks for multiple directories); all lock files are placed in
 | 
						|
the repository and have names beginning with "#cvs.".
 | 
						|
 | 
						|
- Before even attempting to lock, a file "#cvs.tfl.<pid>" is created
 | 
						|
(and removed again), to test that we can write the repository.  [The
 | 
						|
algorithm can still be fooled (1) if the repository's mode is changed
 | 
						|
while attempting to lock; (2) if this file exists and is writable but
 | 
						|
the directory is not.]
 | 
						|
 | 
						|
- While creating the actual read/write lock files (which may exist for
 | 
						|
a long time), a "meta-lock" is held.  The meta-lock is a directory
 | 
						|
named "#cvs.lock" in the repository.  The meta-lock is also held while
 | 
						|
a write lock is held.
 | 
						|
 | 
						|
- To set a read lock:
 | 
						|
 | 
						|
        - acquire the meta-lock
 | 
						|
        - create the file "#cvs.rfl.<pid>"
 | 
						|
        - release the meta-lock
 | 
						|
 | 
						|
- To set a write lock:
 | 
						|
 | 
						|
        - acquire the meta-lock
 | 
						|
        - check that there are no files called "#cvs.rfl.*"
 | 
						|
                - if there are, release the meta-lock, sleep, try again
 | 
						|
        - create the file "#cvs.wfl.<pid>"
 | 
						|
 | 
						|
- To release a write lock:
 | 
						|
 | 
						|
        - remove the file "#cvs.wfl.<pid>"
 | 
						|
        - rmdir the meta-lock
 | 
						|
 | 
						|
- To release a read lock:
 | 
						|
 | 
						|
        - remove the file "#cvs.rfl.<pid>"
 | 
						|
 | 
						|
 | 
						|
Additional notes
 | 
						|
----------------
 | 
						|
 | 
						|
- A process should read-lock at most one repository at a time.
 | 
						|
 | 
						|
- A process may write-lock as many repositories as it wishes (to avoid
 | 
						|
deadlocks, I presume it should always lock them top-down in the
 | 
						|
directory hierarchy).
 | 
						|
 | 
						|
- A process should make sure it removes all its lock files and
 | 
						|
directories when it crashes.
 | 
						|
 | 
						|
- Limitation: one user id should not be committing files into the same
 | 
						|
repository at the same time.
 | 
						|
 | 
						|
 | 
						|
Turn this into Python code
 | 
						|
--------------------------
 | 
						|
 | 
						|
rl = ReadLock(repository, waittime)
 | 
						|
 | 
						|
wl = WriteLock(repository, waittime)
 | 
						|
 | 
						|
list = MultipleWriteLock([repository1, repository2, ...], waittime)
 | 
						|
 | 
						|
"""
 | 
						|
 | 
						|
 | 
						|
import os
 | 
						|
import time
 | 
						|
import stat
 | 
						|
import pwd
 | 
						|
 | 
						|
 | 
						|
# Default wait time
 | 
						|
DELAY = 10
 | 
						|
 | 
						|
 | 
						|
# XXX This should be the same on all Unix versions
 | 
						|
EEXIST = 17
 | 
						|
 | 
						|
 | 
						|
# Files used for locking (must match cvs.h in the CVS sources)
 | 
						|
CVSLCK = "#cvs.lck"
 | 
						|
CVSRFL = "#cvs.rfl."
 | 
						|
CVSWFL = "#cvs.wfl."
 | 
						|
 | 
						|
 | 
						|
class Error:
 | 
						|
 | 
						|
    def __init__(self, msg):
 | 
						|
        self.msg = msg
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return repr(self.msg)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.msg)
 | 
						|
 | 
						|
 | 
						|
class Locked(Error):
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
class Lock:
 | 
						|
 | 
						|
    def __init__(self, repository = ".", delay = DELAY):
 | 
						|
        self.repository = repository
 | 
						|
        self.delay = delay
 | 
						|
        self.lockdir = None
 | 
						|
        self.lockfile = None
 | 
						|
        pid = repr(os.getpid())
 | 
						|
        self.cvslck = self.join(CVSLCK)
 | 
						|
        self.cvsrfl = self.join(CVSRFL + pid)
 | 
						|
        self.cvswfl = self.join(CVSWFL + pid)
 | 
						|
 | 
						|
    def __del__(self):
 | 
						|
        print "__del__"
 | 
						|
        self.unlock()
 | 
						|
 | 
						|
    def setlockdir(self):
 | 
						|
        while 1:
 | 
						|
            try:
 | 
						|
                self.lockdir = self.cvslck
 | 
						|
                os.mkdir(self.cvslck, 0777)
 | 
						|
                return
 | 
						|
            except os.error, msg:
 | 
						|
                self.lockdir = None
 | 
						|
                if msg[0] == EEXIST:
 | 
						|
                    try:
 | 
						|
                        st = os.stat(self.cvslck)
 | 
						|
                    except os.error:
 | 
						|
                        continue
 | 
						|
                    self.sleep(st)
 | 
						|
                    continue
 | 
						|
                raise Error("failed to lock %s: %s" % (
 | 
						|
                        self.repository, msg))
 | 
						|
 | 
						|
    def unlock(self):
 | 
						|
        self.unlockfile()
 | 
						|
        self.unlockdir()
 | 
						|
 | 
						|
    def unlockfile(self):
 | 
						|
        if self.lockfile:
 | 
						|
            print "unlink", self.lockfile
 | 
						|
            try:
 | 
						|
                os.unlink(self.lockfile)
 | 
						|
            except os.error:
 | 
						|
                pass
 | 
						|
            self.lockfile = None
 | 
						|
 | 
						|
    def unlockdir(self):
 | 
						|
        if self.lockdir:
 | 
						|
            print "rmdir", self.lockdir
 | 
						|
            try:
 | 
						|
                os.rmdir(self.lockdir)
 | 
						|
            except os.error:
 | 
						|
                pass
 | 
						|
            self.lockdir = None
 | 
						|
 | 
						|
    def sleep(self, st):
 | 
						|
        sleep(st, self.repository, self.delay)
 | 
						|
 | 
						|
    def join(self, name):
 | 
						|
        return os.path.join(self.repository, name)
 | 
						|
 | 
						|
 | 
						|
def sleep(st, repository, delay):
 | 
						|
    if delay <= 0:
 | 
						|
        raise Locked(st)
 | 
						|
    uid = st[stat.ST_UID]
 | 
						|
    try:
 | 
						|
        pwent = pwd.getpwuid(uid)
 | 
						|
        user = pwent[0]
 | 
						|
    except KeyError:
 | 
						|
        user = "uid %d" % uid
 | 
						|
    print "[%s]" % time.ctime(time.time())[11:19],
 | 
						|
    print "Waiting for %s's lock in" % user, repository
 | 
						|
    time.sleep(delay)
 | 
						|
 | 
						|
 | 
						|
class ReadLock(Lock):
 | 
						|
 | 
						|
    def __init__(self, repository, delay = DELAY):
 | 
						|
        Lock.__init__(self, repository, delay)
 | 
						|
        ok = 0
 | 
						|
        try:
 | 
						|
            self.setlockdir()
 | 
						|
            self.lockfile = self.cvsrfl
 | 
						|
            fp = open(self.lockfile, 'w')
 | 
						|
            fp.close()
 | 
						|
            ok = 1
 | 
						|
        finally:
 | 
						|
            if not ok:
 | 
						|
                self.unlockfile()
 | 
						|
            self.unlockdir()
 | 
						|
 | 
						|
 | 
						|
class WriteLock(Lock):
 | 
						|
 | 
						|
    def __init__(self, repository, delay = DELAY):
 | 
						|
        Lock.__init__(self, repository, delay)
 | 
						|
        self.setlockdir()
 | 
						|
        while 1:
 | 
						|
            uid = self.readers_exist()
 | 
						|
            if not uid:
 | 
						|
                break
 | 
						|
            self.unlockdir()
 | 
						|
            self.sleep(uid)
 | 
						|
        self.lockfile = self.cvswfl
 | 
						|
        fp = open(self.lockfile, 'w')
 | 
						|
        fp.close()
 | 
						|
 | 
						|
    def readers_exist(self):
 | 
						|
        n = len(CVSRFL)
 | 
						|
        for name in os.listdir(self.repository):
 | 
						|
            if name[:n] == CVSRFL:
 | 
						|
                try:
 | 
						|
                    st = os.stat(self.join(name))
 | 
						|
                except os.error:
 | 
						|
                    continue
 | 
						|
                return st
 | 
						|
        return None
 | 
						|
 | 
						|
 | 
						|
def MultipleWriteLock(repositories, delay = DELAY):
 | 
						|
    while 1:
 | 
						|
        locks = []
 | 
						|
        for r in repositories:
 | 
						|
            try:
 | 
						|
                locks.append(WriteLock(r, 0))
 | 
						|
            except Locked, instance:
 | 
						|
                del locks
 | 
						|
                break
 | 
						|
        else:
 | 
						|
            break
 | 
						|
        sleep(instance.msg, r, delay)
 | 
						|
    return list
 | 
						|
 | 
						|
 | 
						|
def test():
 | 
						|
    import sys
 | 
						|
    if sys.argv[1:]:
 | 
						|
        repository = sys.argv[1]
 | 
						|
    else:
 | 
						|
        repository = "."
 | 
						|
    rl = None
 | 
						|
    wl = None
 | 
						|
    try:
 | 
						|
        print "attempting write lock ..."
 | 
						|
        wl = WriteLock(repository)
 | 
						|
        print "got it."
 | 
						|
        wl.unlock()
 | 
						|
        print "attempting read lock ..."
 | 
						|
        rl = ReadLock(repository)
 | 
						|
        print "got it."
 | 
						|
        rl.unlock()
 | 
						|
    finally:
 | 
						|
        print [1]
 | 
						|
        sys.exc_traceback = None
 | 
						|
        print [2]
 | 
						|
        if rl:
 | 
						|
            rl.unlock()
 | 
						|
        print [3]
 | 
						|
        if wl:
 | 
						|
            wl.unlock()
 | 
						|
        print [4]
 | 
						|
        rl = None
 | 
						|
        print [5]
 | 
						|
        wl = None
 | 
						|
        print [6]
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    test()
 |