diff --git a/openstack/common/lockutils.py b/openstack/common/lockutils.py index 7345891..15be0d9 100644 --- a/openstack/common/lockutils.py +++ b/openstack/common/lockutils.py @@ -75,7 +75,7 @@ class _InterProcessLock(object): self.lockfile = None self.fname = name - def __enter__(self): + def acquire(self): basedir = os.path.dirname(self.fname) if not os.path.exists(basedir): @@ -92,7 +92,7 @@ class _InterProcessLock(object): # to have a laughable 10 attempts "blocking" mechanism. self.trylock() LOG.debug(_('Got file lock "%s"'), self.fname) - return self + return True except IOError as e: if e.errno in (errno.EACCES, errno.EAGAIN): # external locks synchronise things like iptables @@ -101,7 +101,11 @@ class _InterProcessLock(object): else: raise - def __exit__(self, exc_type, exc_val, exc_tb): + def __enter__(self): + self.acquire() + return self + + def release(self): try: self.unlock() self.lockfile.close() @@ -110,6 +114,9 @@ class _InterProcessLock(object): self.fname) LOG.debug(_('Released file lock "%s"'), self.fname) + def __exit__(self, exc_type, exc_val, exc_tb): + self.release() + def trylock(self): raise NotImplementedError() diff --git a/tests/unit/test_lockutils.py b/tests/unit/test_lockutils.py index 6090721..e4629f0 100644 --- a/tests/unit/test_lockutils.py +++ b/tests/unit/test_lockutils.py @@ -85,6 +85,50 @@ class LockTestCase(test.BaseTestCase): self.assertEqual(foo.__name__, 'foo', "Wrapped function's name " "got mangled") + def test_lock_acquire_release(self): + lock_dir = tempfile.mkdtemp() + lock_file = os.path.join(lock_dir, 'lock') + lock = lockutils.InterProcessLock(lock_file) + + def try_lock(): + lock.release() # child co-owns it before fork + try: + my_lock = lockutils.InterProcessLock(lock_file) + my_lock.lockfile = open(lock_file, 'w') + my_lock.trylock() + my_lock.unlock() + os._exit(1) + except IOError: + os._exit(0) + + def attempt_acquire(count): + children = [] + for i in range(count): + child = multiprocessing.Process(target=try_lock) + child.start() + children.append(child) + exit_codes = [] + for child in children: + child.join() + exit_codes.append(child.exitcode) + return sum(exit_codes) + + self.assertTrue(lock.acquire()) + try: + acquired_children = attempt_acquire(10) + self.assertEqual(0, acquired_children) + finally: + lock.release() + + try: + acquired_children = attempt_acquire(5) + self.assertNotEqual(0, acquired_children) + finally: + try: + shutil.rmtree(lock_dir) + except IOError: + pass + def test_lock_internally(self): """We can lock across multiple green threads.""" saved_sem_num = len(lockutils._semaphores)