2013-10-18 16:12:21 -03:00
|
|
|
from . import util
|
|
|
|
frozen_init, source_init = util.import_importlib('importlib')
|
|
|
|
frozen_bootstrap = frozen_init._bootstrap
|
|
|
|
source_bootstrap = source_init._bootstrap
|
|
|
|
|
2012-08-28 15:10:18 -03:00
|
|
|
import sys
|
2012-05-17 13:55:59 -03:00
|
|
|
import time
|
|
|
|
import unittest
|
|
|
|
import weakref
|
|
|
|
|
|
|
|
from test import support
|
|
|
|
|
|
|
|
try:
|
|
|
|
import threading
|
|
|
|
except ImportError:
|
|
|
|
threading = None
|
|
|
|
else:
|
|
|
|
from test import lock_tests
|
|
|
|
|
|
|
|
if threading is not None:
|
2013-10-18 17:55:15 -03:00
|
|
|
class ModuleLockAsRLockTests:
|
2013-10-18 16:12:21 -03:00
|
|
|
locktype = classmethod(lambda cls: cls.LockType("some_lock"))
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
# _is_owned() unsupported
|
|
|
|
test__is_owned = None
|
|
|
|
# acquire(blocking=False) unsupported
|
|
|
|
test_try_acquire = None
|
|
|
|
test_try_acquire_contended = None
|
|
|
|
# `with` unsupported
|
|
|
|
test_with = None
|
|
|
|
# acquire(timeout=...) unsupported
|
|
|
|
test_timeout = None
|
|
|
|
# _release_save() unsupported
|
|
|
|
test_release_save_unacquired = None
|
|
|
|
|
2013-10-18 16:12:21 -03:00
|
|
|
class Frozen_ModuleLockAsRLockTests(ModuleLockAsRLockTests, lock_tests.RLockTests):
|
|
|
|
LockType = frozen_bootstrap._ModuleLock
|
|
|
|
|
|
|
|
class Source_ModuleLockAsRLockTests(ModuleLockAsRLockTests, lock_tests.RLockTests):
|
|
|
|
LockType = source_bootstrap._ModuleLock
|
|
|
|
|
2012-05-17 13:55:59 -03:00
|
|
|
else:
|
2013-10-18 16:12:21 -03:00
|
|
|
class Frozen_ModuleLockAsRLockTests(unittest.TestCase):
|
2012-05-17 13:55:59 -03:00
|
|
|
pass
|
|
|
|
|
2013-10-18 16:12:21 -03:00
|
|
|
class Source_ModuleLockAsRLockTests(unittest.TestCase):
|
|
|
|
pass
|
2012-05-17 13:55:59 -03:00
|
|
|
|
2013-10-18 16:12:21 -03:00
|
|
|
|
|
|
|
class DeadlockAvoidanceTests:
|
2012-05-17 13:55:59 -03:00
|
|
|
|
2012-08-28 15:10:18 -03:00
|
|
|
def setUp(self):
|
|
|
|
try:
|
|
|
|
self.old_switchinterval = sys.getswitchinterval()
|
|
|
|
sys.setswitchinterval(0.000001)
|
|
|
|
except AttributeError:
|
|
|
|
self.old_switchinterval = None
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
if self.old_switchinterval is not None:
|
|
|
|
sys.setswitchinterval(self.old_switchinterval)
|
|
|
|
|
2012-05-17 13:55:59 -03:00
|
|
|
def run_deadlock_avoidance_test(self, create_deadlock):
|
|
|
|
NLOCKS = 10
|
2013-10-18 16:12:21 -03:00
|
|
|
locks = [self.LockType(str(i)) for i in range(NLOCKS)]
|
2012-05-17 13:55:59 -03:00
|
|
|
pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)]
|
|
|
|
if create_deadlock:
|
|
|
|
NTHREADS = NLOCKS
|
|
|
|
else:
|
|
|
|
NTHREADS = NLOCKS - 1
|
|
|
|
barrier = threading.Barrier(NTHREADS)
|
|
|
|
results = []
|
|
|
|
def _acquire(lock):
|
|
|
|
"""Try to acquire the lock. Return True on success, False on deadlock."""
|
|
|
|
try:
|
|
|
|
lock.acquire()
|
2013-10-18 16:12:21 -03:00
|
|
|
except self.DeadlockError:
|
2012-05-17 13:55:59 -03:00
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
def f():
|
|
|
|
a, b = pairs.pop()
|
|
|
|
ra = _acquire(a)
|
|
|
|
barrier.wait()
|
|
|
|
rb = _acquire(b)
|
|
|
|
results.append((ra, rb))
|
|
|
|
if rb:
|
|
|
|
b.release()
|
|
|
|
if ra:
|
|
|
|
a.release()
|
|
|
|
lock_tests.Bunch(f, NTHREADS).wait_for_finished()
|
|
|
|
self.assertEqual(len(results), NTHREADS)
|
|
|
|
return results
|
|
|
|
|
|
|
|
def test_deadlock(self):
|
|
|
|
results = self.run_deadlock_avoidance_test(True)
|
2012-08-28 15:10:18 -03:00
|
|
|
# At least one of the threads detected a potential deadlock on its
|
|
|
|
# second acquire() call. It may be several of them, because the
|
|
|
|
# deadlock avoidance mechanism is conservative.
|
|
|
|
nb_deadlocks = results.count((True, False))
|
|
|
|
self.assertGreaterEqual(nb_deadlocks, 1)
|
|
|
|
self.assertEqual(results.count((True, True)), len(results) - nb_deadlocks)
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
def test_no_deadlock(self):
|
|
|
|
results = self.run_deadlock_avoidance_test(False)
|
|
|
|
self.assertEqual(results.count((True, False)), 0)
|
|
|
|
self.assertEqual(results.count((True, True)), len(results))
|
|
|
|
|
2013-10-18 16:12:21 -03:00
|
|
|
@unittest.skipUnless(threading, "threads needed for this test")
|
|
|
|
class Frozen_DeadlockAvoidanceTests(DeadlockAvoidanceTests, unittest.TestCase):
|
|
|
|
LockType = frozen_bootstrap._ModuleLock
|
|
|
|
DeadlockError = frozen_bootstrap._DeadlockError
|
|
|
|
|
|
|
|
@unittest.skipUnless(threading, "threads needed for this test")
|
|
|
|
class Source_DeadlockAvoidanceTests(DeadlockAvoidanceTests, unittest.TestCase):
|
|
|
|
LockType = source_bootstrap._ModuleLock
|
|
|
|
DeadlockError = source_bootstrap._DeadlockError
|
2012-05-17 13:55:59 -03:00
|
|
|
|
2013-10-18 16:12:21 -03:00
|
|
|
|
|
|
|
class LifetimeTests:
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
def test_lock_lifetime(self):
|
|
|
|
name = "xyzzy"
|
2013-10-18 16:12:21 -03:00
|
|
|
self.assertNotIn(name, self.bootstrap._module_locks)
|
|
|
|
lock = self.bootstrap._get_module_lock(name)
|
|
|
|
self.assertIn(name, self.bootstrap._module_locks)
|
2012-05-17 13:55:59 -03:00
|
|
|
wr = weakref.ref(lock)
|
|
|
|
del lock
|
|
|
|
support.gc_collect()
|
2013-10-18 16:12:21 -03:00
|
|
|
self.assertNotIn(name, self.bootstrap._module_locks)
|
2012-06-28 07:15:01 -03:00
|
|
|
self.assertIsNone(wr())
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
def test_all_locks(self):
|
|
|
|
support.gc_collect()
|
2013-10-18 16:12:21 -03:00
|
|
|
self.assertEqual(0, len(self.bootstrap._module_locks),
|
|
|
|
self.bootstrap._module_locks)
|
|
|
|
|
|
|
|
class Frozen_LifetimeTests(LifetimeTests, unittest.TestCase):
|
|
|
|
bootstrap = frozen_bootstrap
|
|
|
|
|
|
|
|
class Source_LifetimeTests(LifetimeTests, unittest.TestCase):
|
|
|
|
bootstrap = source_bootstrap
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
|
|
|
|
@support.reap_threads
|
|
|
|
def test_main():
|
2013-10-18 16:12:21 -03:00
|
|
|
support.run_unittest(Frozen_ModuleLockAsRLockTests,
|
|
|
|
Source_ModuleLockAsRLockTests,
|
|
|
|
Frozen_DeadlockAvoidanceTests,
|
|
|
|
Source_DeadlockAvoidanceTests,
|
|
|
|
Frozen_LifetimeTests,
|
|
|
|
Source_LifetimeTests)
|
2012-05-17 13:55:59 -03:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
test_main()
|