Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 1 | from . import util as test_util |
| 2 | |
| 3 | init = test_util.import_importlib('importlib') |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 4 | |
Antoine Pitrou | 5b9eccb | 2012-08-28 20:10:18 +0200 | [diff] [blame] | 5 | import sys |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 6 | import time |
| 7 | import unittest |
| 8 | import weakref |
| 9 | |
| 10 | from test import support |
| 11 | |
| 12 | try: |
| 13 | import threading |
| 14 | except ImportError: |
| 15 | threading = None |
| 16 | else: |
| 17 | from test import lock_tests |
| 18 | |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 19 | if threading is not None: |
Brett Cannon | c516815 | 2013-10-18 16:55:15 -0400 | [diff] [blame] | 20 | class ModuleLockAsRLockTests: |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 21 | locktype = classmethod(lambda cls: cls.LockType("some_lock")) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 22 | |
| 23 | # _is_owned() unsupported |
| 24 | test__is_owned = None |
| 25 | # acquire(blocking=False) unsupported |
| 26 | test_try_acquire = None |
| 27 | test_try_acquire_contended = None |
| 28 | # `with` unsupported |
| 29 | test_with = None |
| 30 | # acquire(timeout=...) unsupported |
| 31 | test_timeout = None |
| 32 | # _release_save() unsupported |
| 33 | test_release_save_unacquired = None |
Raymond Hettinger | 62f4dad | 2014-05-25 18:22:35 -0700 | [diff] [blame] | 34 | # lock status in repr unsupported |
| 35 | test_repr = None |
| 36 | test_locked_repr = None |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 37 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 38 | LOCK_TYPES = {kind: splitinit._bootstrap._ModuleLock |
| 39 | for kind, splitinit in init.items()} |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 40 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 41 | (Frozen_ModuleLockAsRLockTests, |
| 42 | Source_ModuleLockAsRLockTests |
| 43 | ) = test_util.test_both(ModuleLockAsRLockTests, lock_tests.RLockTests, |
| 44 | LockType=LOCK_TYPES) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 45 | else: |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 46 | LOCK_TYPES = {} |
| 47 | |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 48 | class Frozen_ModuleLockAsRLockTests(unittest.TestCase): |
| 49 | pass |
| 50 | |
| 51 | class Source_ModuleLockAsRLockTests(unittest.TestCase): |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 52 | pass |
| 53 | |
| 54 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 55 | if threading is not None: |
| 56 | class DeadlockAvoidanceTests: |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 57 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 58 | def setUp(self): |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 59 | try: |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 60 | self.old_switchinterval = sys.getswitchinterval() |
| 61 | sys.setswitchinterval(0.000001) |
| 62 | except AttributeError: |
| 63 | self.old_switchinterval = None |
| 64 | |
| 65 | def tearDown(self): |
| 66 | if self.old_switchinterval is not None: |
| 67 | sys.setswitchinterval(self.old_switchinterval) |
| 68 | |
| 69 | def run_deadlock_avoidance_test(self, create_deadlock): |
| 70 | NLOCKS = 10 |
| 71 | locks = [self.LockType(str(i)) for i in range(NLOCKS)] |
| 72 | pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)] |
| 73 | if create_deadlock: |
| 74 | NTHREADS = NLOCKS |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 75 | else: |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 76 | NTHREADS = NLOCKS - 1 |
| 77 | barrier = threading.Barrier(NTHREADS) |
| 78 | results = [] |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 79 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 80 | def _acquire(lock): |
| 81 | """Try to acquire the lock. Return True on success, |
| 82 | False on deadlock.""" |
| 83 | try: |
| 84 | lock.acquire() |
| 85 | except self.DeadlockError: |
| 86 | return False |
| 87 | else: |
| 88 | return True |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 89 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 90 | def f(): |
| 91 | a, b = pairs.pop() |
| 92 | ra = _acquire(a) |
| 93 | barrier.wait() |
| 94 | rb = _acquire(b) |
| 95 | results.append((ra, rb)) |
| 96 | if rb: |
| 97 | b.release() |
| 98 | if ra: |
| 99 | a.release() |
| 100 | lock_tests.Bunch(f, NTHREADS).wait_for_finished() |
| 101 | self.assertEqual(len(results), NTHREADS) |
| 102 | return results |
| 103 | |
| 104 | def test_deadlock(self): |
| 105 | results = self.run_deadlock_avoidance_test(True) |
| 106 | # At least one of the threads detected a potential deadlock on its |
| 107 | # second acquire() call. It may be several of them, because the |
| 108 | # deadlock avoidance mechanism is conservative. |
| 109 | nb_deadlocks = results.count((True, False)) |
| 110 | self.assertGreaterEqual(nb_deadlocks, 1) |
| 111 | self.assertEqual(results.count((True, True)), len(results) - nb_deadlocks) |
| 112 | |
| 113 | def test_no_deadlock(self): |
| 114 | results = self.run_deadlock_avoidance_test(False) |
| 115 | self.assertEqual(results.count((True, False)), 0) |
| 116 | self.assertEqual(results.count((True, True)), len(results)) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 117 | |
| 118 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 119 | DEADLOCK_ERRORS = {kind: splitinit._bootstrap._DeadlockError |
| 120 | for kind, splitinit in init.items()} |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 121 | |
Berker Peksag | f7eaa0c | 2014-07-03 06:25:10 +0300 | [diff] [blame] | 122 | (Frozen_DeadlockAvoidanceTests, |
| 123 | Source_DeadlockAvoidanceTests |
| 124 | ) = test_util.test_both(DeadlockAvoidanceTests, |
| 125 | LockType=LOCK_TYPES, |
| 126 | DeadlockError=DEADLOCK_ERRORS) |
| 127 | else: |
| 128 | DEADLOCK_ERRORS = {} |
| 129 | |
| 130 | class Frozen_DeadlockAvoidanceTests(unittest.TestCase): |
| 131 | pass |
| 132 | |
| 133 | class Source_DeadlockAvoidanceTests(unittest.TestCase): |
| 134 | pass |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 135 | |
| 136 | |
| 137 | class LifetimeTests: |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 138 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 139 | @property |
| 140 | def bootstrap(self): |
| 141 | return self.init._bootstrap |
| 142 | |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 143 | def test_lock_lifetime(self): |
| 144 | name = "xyzzy" |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 145 | self.assertNotIn(name, self.bootstrap._module_locks) |
| 146 | lock = self.bootstrap._get_module_lock(name) |
| 147 | self.assertIn(name, self.bootstrap._module_locks) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 148 | wr = weakref.ref(lock) |
| 149 | del lock |
| 150 | support.gc_collect() |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 151 | self.assertNotIn(name, self.bootstrap._module_locks) |
Eric V. Smith | b109515 | 2012-06-28 06:15:01 -0400 | [diff] [blame] | 152 | self.assertIsNone(wr()) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 153 | |
| 154 | def test_all_locks(self): |
| 155 | support.gc_collect() |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 156 | self.assertEqual(0, len(self.bootstrap._module_locks), |
| 157 | self.bootstrap._module_locks) |
| 158 | |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 159 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 160 | (Frozen_LifetimeTests, |
| 161 | Source_LifetimeTests |
| 162 | ) = test_util.test_both(LifetimeTests, init=init) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 163 | |
| 164 | |
| 165 | @support.reap_threads |
| 166 | def test_main(): |
Brett Cannon | 6a57dd8 | 2013-10-18 15:12:21 -0400 | [diff] [blame] | 167 | support.run_unittest(Frozen_ModuleLockAsRLockTests, |
| 168 | Source_ModuleLockAsRLockTests, |
| 169 | Frozen_DeadlockAvoidanceTests, |
| 170 | Source_DeadlockAvoidanceTests, |
| 171 | Frozen_LifetimeTests, |
| 172 | Source_LifetimeTests) |
Antoine Pitrou | ea3eb88 | 2012-05-17 18:55:59 +0200 | [diff] [blame] | 173 | |
| 174 | |
| 175 | if __name__ == '__main__': |
| 176 | test_main() |