1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005-2010 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
48
from bzrlib.hooks import HookPoint, Hooks
48
from bzrlib.hooks import Hooks
49
from bzrlib.i18n import gettext
51
51
class LockHooks(Hooks):
53
53
def __init__(self):
55
self.create_hook(HookPoint('lock_acquired',
56
"Called with a bzrlib.lock.LockResult when a physical lock is "
57
"acquired.", (1, 8), None))
58
self.create_hook(HookPoint('lock_released',
59
"Called with a bzrlib.lock.LockResult when a physical lock is "
60
"released.", (1, 8), None))
61
self.create_hook(HookPoint('lock_broken',
62
"Called with a bzrlib.lock.LockResult when a physical lock is "
63
"broken.", (1, 15), None))
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 "
66
66
class Lock(object):
84
84
return self.lock_url == other.lock_url and self.details == other.details
86
86
def __repr__(self):
87
return '%s(%s%s)' % (self.__class__.__name__,
87
return '%s(%s, %s)' % (self.__class__.__name__,
88
88
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)
91
105
def cant_unlock_not_held(locked_object):
92
106
"""An attempt to unlock failed because the object was not locked.
190
198
if self.filename in _fcntl_WriteLock._open_locks:
192
200
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'
194
209
self._open(self.filename, 'rb+')
195
210
# reserve a slot for this lock - even if the lockf call fails,
196
# at thisi point unlock() will be called, because self.f is set.
211
# at this point unlock() will be called, because self.f is set.
197
212
# TODO: make this fully threadsafe, if we decide we care.
198
213
_fcntl_WriteLock._open_locks.add(self.filename)
220
235
def __init__(self, filename):
221
236
super(_fcntl_ReadLock, self).__init__()
222
237
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'
223
246
_fcntl_ReadLock._open_locks.setdefault(self.filename, 0)
224
247
_fcntl_ReadLock._open_locks[self.filename] += 1
225
248
self._open(filename, 'rb')
418
441
DWORD, # dwFlagsAndAttributes
419
442
HANDLE # hTemplateFile
420
443
)((_function_name, ctypes.windll.kernel32))
422
445
INVALID_HANDLE_VALUE = -1
424
447
GENERIC_READ = 0x80000000
425
448
GENERIC_WRITE = 0x40000000
426
449
FILE_SHARE_READ = 1
428
451
FILE_ATTRIBUTE_NORMAL = 128
430
453
ERROR_ACCESS_DENIED = 5
431
454
ERROR_SHARING_VIOLATION = 32
503
526
# We default to using the first available lock class.
504
527
_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(gettext('{0!r} was {1} locked again'), self, type_name)
548
self._prev_lock = lock_type