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
		
			
				
	
	
		
			257 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Synchronization metaclass.
 | |
| 
 | |
| This metaclass  makes it possible to declare synchronized methods.
 | |
| 
 | |
| """
 | |
| 
 | |
| import thread
 | |
| 
 | |
| # First we need to define a reentrant lock.
 | |
| # This is generally useful and should probably be in a standard Python
 | |
| # library module.  For now, we in-line it.
 | |
| 
 | |
| class Lock:
 | |
| 
 | |
|     """Reentrant lock.
 | |
| 
 | |
|     This is a mutex-like object which can be acquired by the same
 | |
|     thread more than once.  It keeps a reference count of the number
 | |
|     of times it has been acquired by the same thread.  Each acquire()
 | |
|     call must be matched by a release() call and only the last
 | |
|     release() call actually releases the lock for acquisition by
 | |
|     another thread.
 | |
| 
 | |
|     The implementation uses two locks internally:
 | |
| 
 | |
|     __mutex is a short term lock used to protect the instance variables
 | |
|     __wait is the lock for which other threads wait
 | |
| 
 | |
|     A thread intending to acquire both locks should acquire __wait
 | |
|     first.
 | |
| 
 | |
|    The implementation uses two other instance variables, protected by
 | |
|    locking __mutex:
 | |
| 
 | |
|     __tid is the thread ID of the thread that currently has the lock
 | |
|     __count is the number of times the current thread has acquired it
 | |
| 
 | |
|     When the lock is released, __tid is None and __count is zero.
 | |
| 
 | |
|     """
 | |
| 
 | |
|     def __init__(self):
 | |
|         """Constructor.  Initialize all instance variables."""
 | |
|         self.__mutex = thread.allocate_lock()
 | |
|         self.__wait = thread.allocate_lock()
 | |
|         self.__tid = None
 | |
|         self.__count = 0
 | |
| 
 | |
|     def acquire(self, flag=1):
 | |
|         """Acquire the lock.
 | |
| 
 | |
|         If the optional flag argument is false, returns immediately
 | |
|         when it cannot acquire the __wait lock without blocking (it
 | |
|         may still block for a little while in order to acquire the
 | |
|         __mutex lock).
 | |
| 
 | |
|         The return value is only relevant when the flag argument is
 | |
|         false; it is 1 if the lock is acquired, 0 if not.
 | |
| 
 | |
|         """
 | |
|         self.__mutex.acquire()
 | |
|         try:
 | |
|             if self.__tid == thread.get_ident():
 | |
|                 self.__count = self.__count + 1
 | |
|                 return 1
 | |
|         finally:
 | |
|             self.__mutex.release()
 | |
|         locked = self.__wait.acquire(flag)
 | |
|         if not flag and not locked:
 | |
|             return 0
 | |
|         try:
 | |
|             self.__mutex.acquire()
 | |
|             assert self.__tid == None
 | |
|             assert self.__count == 0
 | |
|             self.__tid = thread.get_ident()
 | |
|             self.__count = 1
 | |
|             return 1
 | |
|         finally:
 | |
|             self.__mutex.release()
 | |
| 
 | |
|     def release(self):
 | |
|         """Release the lock.
 | |
| 
 | |
|         If this thread doesn't currently have the lock, an assertion
 | |
|         error is raised.
 | |
| 
 | |
|         Only allow another thread to acquire the lock when the count
 | |
|         reaches zero after decrementing it.
 | |
| 
 | |
|         """
 | |
|         self.__mutex.acquire()
 | |
|         try:
 | |
|             assert self.__tid == thread.get_ident()
 | |
|             assert self.__count > 0
 | |
|             self.__count = self.__count - 1
 | |
|             if self.__count == 0:
 | |
|                 self.__tid = None
 | |
|                 self.__wait.release()
 | |
|         finally:
 | |
|             self.__mutex.release()
 | |
| 
 | |
| 
 | |
| def _testLock():
 | |
| 
 | |
|     done = []
 | |
| 
 | |
|     def f2(lock, done=done):
 | |
|         lock.acquire()
 | |
|         print "f2 running in thread %d\n" % thread.get_ident(),
 | |
|         lock.release()
 | |
|         done.append(1)
 | |
| 
 | |
|     def f1(lock, f2=f2, done=done):
 | |
|         lock.acquire()
 | |
|         print "f1 running in thread %d\n" % thread.get_ident(),
 | |
|         try:
 | |
|             f2(lock)
 | |
|         finally:
 | |
|             lock.release()
 | |
|         done.append(1)
 | |
| 
 | |
|     lock = Lock()
 | |
|     lock.acquire()
 | |
|     f1(lock)                            # Adds 2 to done
 | |
|     lock.release()
 | |
| 
 | |
|     lock.acquire()
 | |
| 
 | |
|     thread.start_new_thread(f1, (lock,)) # Adds 2
 | |
|     thread.start_new_thread(f1, (lock, f1)) # Adds 3
 | |
|     thread.start_new_thread(f2, (lock,)) # Adds 1
 | |
|     thread.start_new_thread(f2, (lock,)) # Adds 1
 | |
| 
 | |
|     lock.release()
 | |
|     import time
 | |
|     while len(done) < 9:
 | |
|         print len(done)
 | |
|         time.sleep(0.001)
 | |
|     print len(done)
 | |
| 
 | |
| 
 | |
| # Now, the Locking metaclass is a piece of cake.
 | |
| # As an example feature, methods whose name begins with exactly one
 | |
| # underscore are not synchronized.
 | |
| 
 | |
| from Meta import MetaClass, MetaHelper, MetaMethodWrapper
 | |
| 
 | |
| class LockingMethodWrapper(MetaMethodWrapper):
 | |
|     def __call__(self, *args, **kw):
 | |
|         if self.__name__[:1] == '_' and self.__name__[1:] != '_':
 | |
|             return apply(self.func, (self.inst,) + args, kw)
 | |
|         self.inst.__lock__.acquire()
 | |
|         try:
 | |
|             return apply(self.func, (self.inst,) + args, kw)
 | |
|         finally:
 | |
|             self.inst.__lock__.release()
 | |
| 
 | |
| class LockingHelper(MetaHelper):
 | |
|     __methodwrapper__ = LockingMethodWrapper
 | |
|     def __helperinit__(self, formalclass):
 | |
|         MetaHelper.__helperinit__(self, formalclass)
 | |
|         self.__lock__ = Lock()
 | |
| 
 | |
| class LockingMetaClass(MetaClass):
 | |
|     __helper__ = LockingHelper
 | |
| 
 | |
| Locking = LockingMetaClass('Locking', (), {})
 | |
| 
 | |
| def _test():
 | |
|     # For kicks, take away the Locking base class and see it die
 | |
|     class Buffer(Locking):
 | |
|         def __init__(self, initialsize):
 | |
|             assert initialsize > 0
 | |
|             self.size = initialsize
 | |
|             self.buffer = [None]*self.size
 | |
|             self.first = self.last = 0
 | |
|         def put(self, item):
 | |
|             # Do we need to grow the buffer?
 | |
|             if (self.last+1) % self.size != self.first:
 | |
|                 # Insert the new item
 | |
|                 self.buffer[self.last] = item
 | |
|                 self.last = (self.last+1) % self.size
 | |
|                 return
 | |
|             # Double the buffer size
 | |
|             # First normalize it so that first==0 and last==size-1
 | |
|             print "buffer =", self.buffer
 | |
|             print "first = %d, last = %d, size = %d" % (
 | |
|                 self.first, self.last, self.size)
 | |
|             if self.first <= self.last:
 | |
|                 temp = self.buffer[self.first:self.last]
 | |
|             else:
 | |
|                 temp = self.buffer[self.first:] + self.buffer[:self.last]
 | |
|             print "temp =", temp
 | |
|             self.buffer = temp + [None]*(self.size+1)
 | |
|             self.first = 0
 | |
|             self.last = self.size-1
 | |
|             self.size = self.size*2
 | |
|             print "Buffer size doubled to", self.size
 | |
|             print "new buffer =", self.buffer
 | |
|             print "first = %d, last = %d, size = %d" % (
 | |
|                 self.first, self.last, self.size)
 | |
|             self.put(item)              # Recursive call to test the locking
 | |
|         def get(self):
 | |
|             # Is the buffer empty?
 | |
|             if self.first == self.last:
 | |
|                 raise EOFError          # Avoid defining a new exception
 | |
|             item = self.buffer[self.first]
 | |
|             self.first = (self.first+1) % self.size
 | |
|             return item
 | |
| 
 | |
|     def producer(buffer, wait, n=1000):
 | |
|         import time
 | |
|         i = 0
 | |
|         while i < n:
 | |
|             print "put", i
 | |
|             buffer.put(i)
 | |
|             i = i+1
 | |
|         print "Producer: done producing", n, "items"
 | |
|         wait.release()
 | |
| 
 | |
|     def consumer(buffer, wait, n=1000):
 | |
|         import time
 | |
|         i = 0
 | |
|         tout = 0.001
 | |
|         while i < n:
 | |
|             try:
 | |
|                 x = buffer.get()
 | |
|                 if x != i:
 | |
|                     raise AssertionError, \
 | |
|                           "get() returned %s, expected %s" % (x, i)
 | |
|                 print "got", i
 | |
|                 i = i+1
 | |
|                 tout = 0.001
 | |
|             except EOFError:
 | |
|                 time.sleep(tout)
 | |
|                 tout = tout*2
 | |
|         print "Consumer: done consuming", n, "items"
 | |
|         wait.release()
 | |
| 
 | |
|     pwait = thread.allocate_lock()
 | |
|     pwait.acquire()
 | |
|     cwait = thread.allocate_lock()
 | |
|     cwait.acquire()
 | |
|     buffer = Buffer(1)
 | |
|     n = 1000
 | |
|     thread.start_new_thread(consumer, (buffer, cwait, n))
 | |
|     thread.start_new_thread(producer, (buffer, pwait, n))
 | |
|     pwait.acquire()
 | |
|     print "Producer done"
 | |
|     cwait.acquire()
 | |
|     print "All done"
 | |
|     print "buffer size ==", len(buffer.buffer)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     _testLock()
 | |
|     _test()
 |