Rev 4478: (Martin <gzlist>) Use CreateFile rather than LockFileEx for OS locks. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Jun 25 18:36:34 BST 2009
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 4478 [merge]
revision-id: pqm at pqm.ubuntu.com-20090625173629-yw2y6x938qnr0hr4
parent: pqm at pqm.ubuntu.com-20090625163519-mkzk2ohzadj749h3
parent: john at arbash-meinel.com-20090625154112-tgg8jq0ldhaizseg
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-06-25 18:36:29 +0100
message:
(Martin <gzlist>) Use CreateFile rather than LockFileEx for OS locks.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/lock.py lock.py-20050527050856-ec090bb51bc03349
=== modified file 'NEWS'
--- a/NEWS 2009-06-25 14:58:00 +0000
+++ b/NEWS 2009-06-25 17:36:29 +0000
@@ -94,6 +94,11 @@
parameter to permit cross-format fetching to incrementally pack the
converted data. (Robert Collins)
+* OS file locks are now taken out using ``CreateFile`` rather than
+ ``LockFileEx`` on Windows. The locking remains exclusive with
+ ``LockFileEx`` but now it also works on older versions of Windows (such
+ as Win98). (Martin <gzlist>)
+
* pack <=> pack fetching is now done via a ``PackStreamSource`` rather
than the ``Packer`` code. The user visible change is that we now
properly fetch the minimum number of texts for non-smart fetching.
=== modified file 'bzrlib/lock.py'
--- a/bzrlib/lock.py 2009-06-10 03:56:49 +0000
+++ b/bzrlib/lock.py 2009-06-19 10:04:02 +0000
@@ -35,6 +35,7 @@
"""
import errno
+import os
import sys
from bzrlib import (
@@ -96,7 +97,7 @@
if sys.platform == 'win32':
import msvcrt
try:
- import win32con, win32file, pywintypes, winerror
+ import win32file, pywintypes, winerror
have_pywin32 = True
except ImportError:
pass
@@ -151,10 +152,6 @@
if have_fcntl:
- LOCK_SH = fcntl.LOCK_SH
- LOCK_NB = fcntl.LOCK_NB
- lock_EX = fcntl.LOCK_EX
-
class _fcntl_FileLock(_OSLock):
@@ -304,44 +301,35 @@
if have_pywin32 and sys.platform == 'win32':
- LOCK_SH = 0 # the default
- LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
- LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
-
class _w32c_FileLock(_OSLock):
- def _lock(self, filename, openmode, lockmode):
- self._open(filename, openmode)
-
- self.hfile = msvcrt.get_osfhandle(self.f.fileno())
- overlapped = pywintypes.OVERLAPPED()
+ def _open(self, filename, access, share, cflags, pymode):
+ self.filename = osutils.realpath(filename)
try:
- win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
- overlapped)
+ self._handle = win32file.CreateFile(filename, access, share,
+ None, win32file.OPEN_ALWAYS,
+ win32file.FILE_ATTRIBUTE_NORMAL, None)
except pywintypes.error, e:
- self._clear_f()
- if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
- raise errors.LockContention(filename)
- ## import pdb; pdb.set_trace()
+ if e.args[0] == winerror.ERROR_ACCESS_DENIED:
+ raise errors.LockFailed(filename, e)
+ if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
+ raise errors.LockContention(filename, e)
raise
- except Exception, e:
- self._clear_f()
- raise errors.LockContention(filename, e)
+ fd = win32file._open_osfhandle(self._handle, cflags)
+ self.f = os.fdopen(fd, pymode)
+ return self.f
def unlock(self):
- overlapped = pywintypes.OVERLAPPED()
- try:
- win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
- self._clear_f()
- except Exception, e:
- raise errors.LockContention(self.filename, e)
+ self._clear_f()
+ self._handle = None
class _w32c_ReadLock(_w32c_FileLock):
def __init__(self, filename):
super(_w32c_ReadLock, self).__init__()
- self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
+ self._open(filename, win32file.GENERIC_READ,
+ win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
def temporary_write_lock(self):
"""Try to grab a write lock on the file.
@@ -366,7 +354,9 @@
class _w32c_WriteLock(_w32c_FileLock):
def __init__(self, filename):
super(_w32c_WriteLock, self).__init__()
- self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
+ self._open(filename,
+ win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,
+ os.O_RDWR, "rb+")
def restore_read_lock(self):
"""Restore the original ReadLock."""
@@ -380,92 +370,67 @@
if have_ctypes_win32:
- # These constants were copied from the win32con.py module.
- LOCKFILE_FAIL_IMMEDIATELY = 1
- LOCKFILE_EXCLUSIVE_LOCK = 2
- # Constant taken from winerror.py module
- ERROR_LOCK_VIOLATION = 33
-
- LOCK_SH = 0
- LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
- LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
- _LockFileEx = ctypes.windll.kernel32.LockFileEx
- _UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
-
- ### Define the OVERLAPPED structure.
- # http://msdn2.microsoft.com/en-us/library/ms684342.aspx
- # typedef struct _OVERLAPPED {
- # ULONG_PTR Internal;
- # ULONG_PTR InternalHigh;
- # union {
- # struct {
- # DWORD Offset;
- # DWORD OffsetHigh;
- # };
- # PVOID Pointer;
- # };
- # HANDLE hEvent;
- # } OVERLAPPED,
-
- class _inner_struct(ctypes.Structure):
- _fields_ = [('Offset', ctypes.c_uint), # DWORD
- ('OffsetHigh', ctypes.c_uint), # DWORD
- ]
-
- class _inner_union(ctypes.Union):
- _fields_ = [('anon_struct', _inner_struct), # struct
- ('Pointer', ctypes.c_void_p), # PVOID
- ]
-
- class OVERLAPPED(ctypes.Structure):
- _fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
- ('InternalHigh', ctypes.c_void_p), # ULONG_PTR
- ('_inner_union', _inner_union),
- ('hEvent', ctypes.c_void_p), # HANDLE
- ]
+ from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
+ LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
+ HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
+ if os.path.supports_unicode_filenames:
+ _function_name = "CreateFileW"
+ LPTSTR = LPCWSTR
+ else:
+ _function_name = "CreateFileA"
+ class LPTSTR(LPCSTR):
+ def __new__(cls, obj):
+ return LPCSTR.__new__(cls, obj.encode("mbcs"))
+
+ # CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
+ _CreateFile = ctypes.WINFUNCTYPE(
+ HANDLE, # return value
+ LPTSTR, # lpFileName
+ DWORD, # dwDesiredAccess
+ DWORD, # dwShareMode
+ LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
+ DWORD, # dwCreationDisposition
+ DWORD, # dwFlagsAndAttributes
+ HANDLE # hTemplateFile
+ )((_function_name, ctypes.windll.kernel32))
+
+ INVALID_HANDLE_VALUE = -1
+
+ GENERIC_READ = 0x80000000
+ GENERIC_WRITE = 0x40000000
+ FILE_SHARE_READ = 1
+ OPEN_ALWAYS = 4
+ FILE_ATTRIBUTE_NORMAL = 128
+
+ ERROR_ACCESS_DENIED = 5
+ ERROR_SHARING_VIOLATION = 32
class _ctypes_FileLock(_OSLock):
- def _lock(self, filename, openmode, lockmode):
- self._open(filename, openmode)
-
- self.hfile = msvcrt.get_osfhandle(self.f.fileno())
- overlapped = OVERLAPPED()
- result = _LockFileEx(self.hfile, # HANDLE hFile
- lockmode, # DWORD dwFlags
- 0, # DWORD dwReserved
- 0x7fffffff, # DWORD nNumberOfBytesToLockLow
- 0x00000000, # DWORD nNumberOfBytesToLockHigh
- ctypes.byref(overlapped), # lpOverlapped
- )
- if result == 0:
- last_err = ctypes.GetLastError()
- self._clear_f()
- if last_err in (ERROR_LOCK_VIOLATION,):
- raise errors.LockContention(filename)
- raise errors.LockContention(filename,
- 'Unknown locking error: %s' % (last_err,))
+ def _open(self, filename, access, share, cflags, pymode):
+ self.filename = osutils.realpath(filename)
+ handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0)
+ if handle in (INVALID_HANDLE_VALUE, 0):
+ e = ctypes.WinError()
+ if e.args[0] == ERROR_ACCESS_DENIED:
+ raise errors.LockFailed(filename, e)
+ if e.args[0] == ERROR_SHARING_VIOLATION:
+ raise errors.LockContention(filename, e)
+ raise e
+ fd = msvcrt.open_osfhandle(handle, cflags)
+ self.f = os.fdopen(fd, pymode)
+ return self.f
def unlock(self):
- overlapped = OVERLAPPED()
- result = _UnlockFileEx(self.hfile, # HANDLE hFile
- 0, # DWORD dwReserved
- 0x7fffffff, # DWORD nNumberOfBytesToLockLow
- 0x00000000, # DWORD nNumberOfBytesToLockHigh
- ctypes.byref(overlapped), # lpOverlapped
- )
- if result == 0:
- last_err = ctypes.GetLastError()
- self._clear_f()
- raise errors.LockContention(self.filename,
- 'Unknown unlocking error: %s' % (last_err,))
self._clear_f()
class _ctypes_ReadLock(_ctypes_FileLock):
def __init__(self, filename):
super(_ctypes_ReadLock, self).__init__()
- self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
+ self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
+ "rb")
def temporary_write_lock(self):
"""Try to grab a write lock on the file.
@@ -489,7 +454,8 @@
class _ctypes_WriteLock(_ctypes_FileLock):
def __init__(self, filename):
super(_ctypes_WriteLock, self).__init__()
- self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
+ self._open(filename, GENERIC_READ | GENERIC_WRITE, 0, os.O_RDWR,
+ "rb+")
def restore_read_lock(self):
"""Restore the original ReadLock."""
More information about the bazaar-commits
mailing list