diff roundup/backends/portalocker.py @ 1387:e975db910d9f

latest version of portalocker fixed for win98 and winnt, thanks James Kew
author Richard Jones <richard@users.sourceforge.net>
date Sun, 19 Jan 2003 23:14:42 +0000
parents 8dd4f736370b
children 1159963f769c
line wrap: on
line diff
--- a/roundup/backends/portalocker.py	Sun Jan 19 16:15:38 2003 +0000
+++ b/roundup/backends/portalocker.py	Sun Jan 19 23:14:42 2003 +0000
@@ -2,7 +2,7 @@
 #                  Requires python 1.5.2 or better.
 
 # ID line added by richard for Roundup file tracking
-# $Id: portalocker.py,v 1.2 2002-10-03 06:56:29 richard Exp $
+# $Id: portalocker.py,v 1.3 2003-01-19 23:14:42 richard Exp $
 
 """ Cross-platform (posix/nt) API for flock-style file locking.
 
@@ -43,51 +43,99 @@
 import os
 
 if os.name == 'nt':
-	import win32con
-	import win32file
-	import pywintypes
-	LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
-	LOCK_SH = 0 # the default
-	LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
-	# is there any reason not to reuse the following structure?
-	__overlapped = pywintypes.OVERLAPPED()
+    import win32con
+    import win32file
+    import pywintypes
+    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
+    LOCK_SH = 0 # the default
+    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
+    # is there any reason not to reuse the following structure?
+    __overlapped = pywintypes.OVERLAPPED()
 elif os.name == 'posix':
-	import fcntl
-	LOCK_EX = fcntl.LOCK_EX
-	LOCK_SH = fcntl.LOCK_SH
-	LOCK_NB = fcntl.LOCK_NB
+    import fcntl
+    LOCK_EX = fcntl.LOCK_EX
+    LOCK_SH = fcntl.LOCK_SH
+    LOCK_NB = fcntl.LOCK_NB
 else:
-	raise RuntimeError("PortaLocker only defined for nt and posix platforms")
+    raise RuntimeError("PortaLocker only defined for nt and posix platforms")
 
 if os.name == 'nt':
-	def lock(file, flags):
-		hfile = win32file._get_osfhandle(file.fileno())
-		win32file.LockFileEx(hfile, flags, 0, 0xffff0000, __overlapped)
-
-	def unlock(file):
-		hfile = win32file._get_osfhandle(file.fileno())
-		win32file.UnlockFileEx(hfile, 0, 0xffff0000, __overlapped)
+    def lock(file, flags):
+        hfile = win32file._get_osfhandle(file.fileno())
+        # LockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
+        # If it's not supported, win32file will raise an exception.
+        # Try LockFileEx first, as it has more functionality and handles
+        # blocking locks more efficiently.
+        try:
+            win32file.LockFileEx(hfile, flags, 0, 0xffff0000, __overlapped)
+        except win32file.error, e:
+            import winerror
+            # Propagate upwards all exceptions other than not-implemented.
+            if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
+                raise e
+            
+            # LockFileEx is not supported. Use LockFile.
+            # LockFile does not support shared locking -- always exclusive.
+            # Care: the low/high length params are reversed compared to LockFileEx.
+            if not flags & LOCK_EX:
+                import warnings
+                warnings.warn("PortaLocker does not support shared locking on Win9x", RuntimeWarning)
+            # LockFile only supports immediate-fail locking.
+            if flags & LOCK_NB:
+                win32file.LockFile(hfile, 0, 0, 0xffff0000, 0)
+            else:
+                # Emulate a blocking lock with a polling loop.
+                import time
+                while 1:
+                    # Attempt a lock.
+                    try:
+                        win32file.LockFile(hfile, 0, 0, 0xffff0000, 0)
+                        break
+                    except win32file.error, e:
+                        # Propagate upwards all exceptions other than lock violation.
+                        if e[0] != winerror.ERROR_LOCK_VIOLATION:
+                            raise e
+                    # Sleep and poll again.
+                    time.sleep(0.1)
+        # TODO: should this return the result of the lock?
+                    
+    def unlock(file):
+        hfile = win32file._get_osfhandle(file.fileno())
+        # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98, WinME).
+        # If it's not supported, win32file will raise an api_error exception.
+        try:
+            win32file.UnlockFileEx(hfile, 0, 0xffff0000, __overlapped)
+        except win32file.error, e:
+            import winerror
+            # Propagate upwards all exceptions other than not-implemented.
+            if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
+                raise e
+            
+            # UnlockFileEx is not supported. Use UnlockFile.
+            # Care: the low/high length params are reversed compared to UnLockFileEx.
+            win32file.UnlockFile(hfile, 0, 0, 0xffff0000, 0)
 
 elif os.name =='posix':
-	def lock(file, flags):
-		fcntl.flock(file.fileno(), flags)
+    def lock(file, flags):
+        fcntl.flock(file.fileno(), flags)
+        # TODO: should this return the result of the lock?
 
-	def unlock(file):
-		fcntl.flock(file.fileno(), fcntl.LOCK_UN)
+    def unlock(file):
+        fcntl.flock(file.fileno(), fcntl.LOCK_UN)
 
 if __name__ == '__main__':
-	from time import time, strftime, localtime
-	import sys
-	import portalocker
+    from time import time, strftime, localtime
+    import sys
+    import portalocker
 
-	log = open('log.txt', "a+")
-	portalocker.lock(log, portalocker.LOCK_EX)
+    log = open('log.txt', "a+")
+    portalocker.lock(log, portalocker.LOCK_EX)
 
-	timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
-	log.write( timestamp )
+    timestamp = strftime("%m/%d/%Y %H:%M:%S\n", localtime(time()))
+    log.write( timestamp )
 
-	print "Wrote lines. Hit enter to release lock."
-	dummy = sys.stdin.readline()
+    print "Wrote lines. Hit enter to release lock."
+    dummy = sys.stdin.readline()
 
-	log.close()
+    log.close()
 

Roundup Issue Tracker: http://roundup-tracker.org/