[utils] Improve file locking

* Implement non-blocking locks for windows
* Don't raise error when closing a closed file
This commit is contained in:
pukkandan 2022-03-03 18:57:38 +05:30
parent acea8d7cfb
commit 747c0bd127
No known key found for this signature in database
GPG Key ID: 7EEE9E1E817D0A39

View File

@ -2122,22 +2122,22 @@ class OVERLAPPED(ctypes.Structure):
whole_low = 0xffffffff whole_low = 0xffffffff
whole_high = 0x7fffffff whole_high = 0x7fffffff
def _lock_file(f, exclusive, block): # todo: block unused on win32 def _lock_file(f, exclusive, block):
overlapped = OVERLAPPED() overlapped = OVERLAPPED()
overlapped.Offset = 0 overlapped.Offset = 0
overlapped.OffsetHigh = 0 overlapped.OffsetHigh = 0
overlapped.hEvent = 0 overlapped.hEvent = 0
f._lock_file_overlapped_p = ctypes.pointer(overlapped) f._lock_file_overlapped_p = ctypes.pointer(overlapped)
handle = msvcrt.get_osfhandle(f.fileno())
if not LockFileEx(handle, 0x2 if exclusive else 0x0, 0, if not LockFileEx(msvcrt.get_osfhandle(f.fileno()),
whole_low, whole_high, f._lock_file_overlapped_p): (0x2 if exclusive else 0x0) | (0x0 if block else 0x1),
raise OSError('Locking file failed: %r' % ctypes.FormatError()) 0, whole_low, whole_high, f._lock_file_overlapped_p):
raise BlockingIOError('Locking file failed: %r' % ctypes.FormatError())
def _unlock_file(f): def _unlock_file(f):
assert f._lock_file_overlapped_p assert f._lock_file_overlapped_p
handle = msvcrt.get_osfhandle(f.fileno()) handle = msvcrt.get_osfhandle(f.fileno())
if not UnlockFileEx(handle, 0, if not UnlockFileEx(handle, 0, whole_low, whole_high, f._lock_file_overlapped_p):
whole_low, whole_high, f._lock_file_overlapped_p):
raise OSError('Unlocking file failed: %r' % ctypes.FormatError()) raise OSError('Unlocking file failed: %r' % ctypes.FormatError())
else: else:
@ -2175,6 +2175,8 @@ def _unlock_file(f):
class locked_file(object): class locked_file(object):
_closed = False
def __init__(self, filename, mode, block=True, encoding=None): def __init__(self, filename, mode, block=True, encoding=None):
assert mode in ['r', 'rb', 'a', 'ab', 'w', 'wb'] assert mode in ['r', 'rb', 'a', 'ab', 'w', 'wb']
self.f = io.open(filename, mode, encoding=encoding) self.f = io.open(filename, mode, encoding=encoding)
@ -2192,9 +2194,11 @@ def __enter__(self):
def __exit__(self, etype, value, traceback): def __exit__(self, etype, value, traceback):
try: try:
if not self._closed:
_unlock_file(self.f) _unlock_file(self.f)
finally: finally:
self.f.close() self.f.close()
self._closed = True
def __iter__(self): def __iter__(self):
return iter(self.f) return iter(self.f)