1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
42
41
from bzrlib import (
48
from bzrlib.hooks import Hooks
46
from bzrlib.hooks import HookPoint, Hooks
51
49
class LockHooks(Hooks):
53
51
def __init__(self):
54
Hooks.__init__(self, "bzrlib.lock", "Lock.hooks")
55
self.add_hook('lock_acquired',
56
"Called with a bzrlib.lock.LockResult when a physical lock is "
58
self.add_hook('lock_released',
59
"Called with a bzrlib.lock.LockResult when a physical lock is "
61
self.add_hook('lock_broken',
62
"Called with a bzrlib.lock.LockResult when a physical lock is "
53
self.create_hook(HookPoint('lock_acquired',
54
"Called with a bzrlib.lock.LockResult when a physical lock is "
55
"acquired.", (1, 8), None))
56
self.create_hook(HookPoint('lock_released',
57
"Called with a bzrlib.lock.LockResult when a physical lock is "
58
"released.", (1, 8), None))
59
self.create_hook(HookPoint('lock_broken',
60
"Called with a bzrlib.lock.LockResult when a physical lock is "
61
"broken.", (1, 15), None))
66
64
class Lock(object):
84
82
return self.lock_url == other.lock_url and self.details == other.details
86
84
def __repr__(self):
87
return '%s(%s, %s)' % (self.__class__.__name__,
85
return '%s(%s%s)' % (self.__class__.__name__,
88
86
self.lock_url, self.details)
91
class LogicalLockResult(object):
92
"""The result of a lock_read/lock_write/lock_tree_write call on lockables.
94
:ivar unlock: A callable which will unlock the lock.
97
def __init__(self, unlock):
101
return "LogicalLockResult(%s)" % (self.unlock)
105
def cant_unlock_not_held(locked_object):
106
"""An attempt to unlock failed because the object was not locked.
108
This provides a policy point from which we can generate either a warning
111
# This is typically masking some other error and called from a finally
112
# block, so it's useful to have the option not to generate a new error
113
# here. You can use -Werror to make it fatal. It should possibly also
115
if 'unlock' in debug.debug_flags:
116
warnings.warn("%r is already unlocked" % (locked_object,),
119
raise errors.LockNotHeld(locked_object)
198
171
if self.filename in _fcntl_WriteLock._open_locks:
200
173
raise errors.LockContention(self.filename)
201
if self.filename in _fcntl_ReadLock._open_locks:
202
if 'strict_locks' in debug.debug_flags:
204
raise errors.LockContention(self.filename)
206
trace.mutter('Write lock taken w/ an open read lock on: %s'
209
175
self._open(self.filename, 'rb+')
210
176
# reserve a slot for this lock - even if the lockf call fails,
211
# at this point unlock() will be called, because self.f is set.
177
# at thisi point unlock() will be called, because self.f is set.
212
178
# TODO: make this fully threadsafe, if we decide we care.
213
179
_fcntl_WriteLock._open_locks.add(self.filename)
235
201
def __init__(self, filename):
236
202
super(_fcntl_ReadLock, self).__init__()
237
203
self.filename = osutils.realpath(filename)
238
if self.filename in _fcntl_WriteLock._open_locks:
239
if 'strict_locks' in debug.debug_flags:
240
# We raise before calling _open so we don't need to
242
raise errors.LockContention(self.filename)
244
trace.mutter('Read lock taken w/ an open write lock on: %s'
246
204
_fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
247
205
_fcntl_ReadLock._open_locks[self.filename] += 1
248
206
self._open(filename, 'rb')
441
399
DWORD, # dwFlagsAndAttributes
442
400
HANDLE # hTemplateFile
443
401
)((_function_name, ctypes.windll.kernel32))
445
403
INVALID_HANDLE_VALUE = -1
447
405
GENERIC_READ = 0x80000000
448
406
GENERIC_WRITE = 0x40000000
449
407
FILE_SHARE_READ = 1
451
409
FILE_ATTRIBUTE_NORMAL = 128
453
411
ERROR_ACCESS_DENIED = 5
454
412
ERROR_SHARING_VIOLATION = 32
526
484
# We default to using the first available lock class.
527
485
_lock_type, WriteLock, ReadLock = _lock_classes[0]
530
class _RelockDebugMixin(object):
531
"""Mixin support for -Drelock flag.
533
Add this as a base class then call self._note_lock with 'r' or 'w' when
534
acquiring a read- or write-lock. If this object was previously locked (and
535
locked the same way), and -Drelock is set, then this will trace.note a
541
def _note_lock(self, lock_type):
542
if 'relock' in debug.debug_flags and self._prev_lock == lock_type:
547
trace.note('%r was %s locked again', self, type_name)
548
self._prev_lock = lock_type