github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/test/lock_tests.py (about) 1 """ 2 Various tests for synchronization primitives. 3 """ 4 5 import sys 6 import time 7 from thread import start_new_thread, get_ident 8 import threading 9 import unittest 10 11 from test import test_support as support 12 13 14 def _wait(): 15 # A crude wait/yield function not relying on synchronization primitives. 16 time.sleep(0.01) 17 18 class Bunch(object): 19 """ 20 A bunch of threads. 21 """ 22 def __init__(self, f, n, wait_before_exit=False): 23 """ 24 Construct a bunch of `n` threads running the same function `f`. 25 If `wait_before_exit` is True, the threads won't terminate until 26 do_finish() is called. 27 """ 28 self.f = f 29 self.n = n 30 self.started = [] 31 self.finished = [] 32 self._can_exit = not wait_before_exit 33 def task(): 34 tid = get_ident() 35 self.started.append(tid) 36 try: 37 f() 38 finally: 39 self.finished.append(tid) 40 while not self._can_exit: 41 _wait() 42 try: 43 for i in range(n): 44 start_new_thread(task, ()) 45 except: 46 self._can_exit = True 47 raise 48 49 def wait_for_started(self): 50 while len(self.started) < self.n: 51 _wait() 52 53 def wait_for_finished(self): 54 while len(self.finished) < self.n: 55 _wait() 56 57 def do_finish(self): 58 self._can_exit = True 59 60 61 class BaseTestCase(unittest.TestCase): 62 def setUp(self): 63 self._threads = support.threading_setup() 64 65 def tearDown(self): 66 support.threading_cleanup(*self._threads) 67 support.reap_children() 68 69 70 class BaseLockTests(BaseTestCase): 71 """ 72 Tests for both recursive and non-recursive locks. 73 """ 74 75 def test_constructor(self): 76 lock = self.locktype() 77 del lock 78 79 def test_acquire_destroy(self): 80 lock = self.locktype() 81 lock.acquire() 82 del lock 83 84 def test_acquire_release(self): 85 lock = self.locktype() 86 lock.acquire() 87 lock.release() 88 del lock 89 90 def test_try_acquire(self): 91 lock = self.locktype() 92 self.assertTrue(lock.acquire(False)) 93 lock.release() 94 95 def test_try_acquire_contended(self): 96 lock = self.locktype() 97 lock.acquire() 98 result = [] 99 def f(): 100 result.append(lock.acquire(False)) 101 Bunch(f, 1).wait_for_finished() 102 self.assertFalse(result[0]) 103 lock.release() 104 105 def test_acquire_contended(self): 106 lock = self.locktype() 107 lock.acquire() 108 N = 5 109 def f(): 110 lock.acquire() 111 lock.release() 112 113 b = Bunch(f, N) 114 b.wait_for_started() 115 _wait() 116 self.assertEqual(len(b.finished), 0) 117 lock.release() 118 b.wait_for_finished() 119 self.assertEqual(len(b.finished), N) 120 121 def test_with(self): 122 lock = self.locktype() 123 def f(): 124 lock.acquire() 125 lock.release() 126 def _with(err=None): 127 with lock: 128 if err is not None: 129 raise err 130 _with() 131 # Check the lock is unacquired 132 Bunch(f, 1).wait_for_finished() 133 self.assertRaises(TypeError, _with, TypeError) 134 # Check the lock is unacquired 135 Bunch(f, 1).wait_for_finished() 136 137 def test_thread_leak(self): 138 # The lock shouldn't leak a Thread instance when used from a foreign 139 # (non-threading) thread. 140 lock = self.locktype() 141 def f(): 142 lock.acquire() 143 lock.release() 144 n = len(threading.enumerate()) 145 # We run many threads in the hope that existing threads ids won't 146 # be recycled. 147 Bunch(f, 15).wait_for_finished() 148 self.assertEqual(n, len(threading.enumerate())) 149 150 151 class LockTests(BaseLockTests): 152 """ 153 Tests for non-recursive, weak locks 154 (which can be acquired and released from different threads). 155 """ 156 def test_reacquire(self): 157 # Lock needs to be released before re-acquiring. 158 lock = self.locktype() 159 phase = [] 160 def f(): 161 lock.acquire() 162 phase.append(None) 163 lock.acquire() 164 phase.append(None) 165 start_new_thread(f, ()) 166 while len(phase) == 0: 167 _wait() 168 _wait() 169 self.assertEqual(len(phase), 1) 170 lock.release() 171 while len(phase) == 1: 172 _wait() 173 self.assertEqual(len(phase), 2) 174 175 def test_different_thread(self): 176 # Lock can be released from a different thread. 177 lock = self.locktype() 178 lock.acquire() 179 def f(): 180 lock.release() 181 b = Bunch(f, 1) 182 b.wait_for_finished() 183 lock.acquire() 184 lock.release() 185 186 187 class RLockTests(BaseLockTests): 188 """ 189 Tests for recursive locks. 190 """ 191 def test_reacquire(self): 192 lock = self.locktype() 193 lock.acquire() 194 lock.acquire() 195 lock.release() 196 lock.acquire() 197 lock.release() 198 lock.release() 199 200 def test_release_unacquired(self): 201 # Cannot release an unacquired lock 202 lock = self.locktype() 203 self.assertRaises(RuntimeError, lock.release) 204 lock.acquire() 205 lock.acquire() 206 lock.release() 207 lock.acquire() 208 lock.release() 209 lock.release() 210 self.assertRaises(RuntimeError, lock.release) 211 212 def test_different_thread(self): 213 # Cannot release from a different thread 214 lock = self.locktype() 215 def f(): 216 lock.acquire() 217 b = Bunch(f, 1, True) 218 try: 219 self.assertRaises(RuntimeError, lock.release) 220 finally: 221 b.do_finish() 222 223 def test__is_owned(self): 224 lock = self.locktype() 225 self.assertFalse(lock._is_owned()) 226 lock.acquire() 227 self.assertTrue(lock._is_owned()) 228 lock.acquire() 229 self.assertTrue(lock._is_owned()) 230 result = [] 231 def f(): 232 result.append(lock._is_owned()) 233 Bunch(f, 1).wait_for_finished() 234 self.assertFalse(result[0]) 235 lock.release() 236 self.assertTrue(lock._is_owned()) 237 lock.release() 238 self.assertFalse(lock._is_owned()) 239 240 241 class EventTests(BaseTestCase): 242 """ 243 Tests for Event objects. 244 """ 245 246 def test_is_set(self): 247 evt = self.eventtype() 248 self.assertFalse(evt.is_set()) 249 evt.set() 250 self.assertTrue(evt.is_set()) 251 evt.set() 252 self.assertTrue(evt.is_set()) 253 evt.clear() 254 self.assertFalse(evt.is_set()) 255 evt.clear() 256 self.assertFalse(evt.is_set()) 257 258 def _check_notify(self, evt): 259 # All threads get notified 260 N = 5 261 results1 = [] 262 results2 = [] 263 def f(): 264 results1.append(evt.wait()) 265 results2.append(evt.wait()) 266 b = Bunch(f, N) 267 b.wait_for_started() 268 _wait() 269 self.assertEqual(len(results1), 0) 270 evt.set() 271 b.wait_for_finished() 272 self.assertEqual(results1, [True] * N) 273 self.assertEqual(results2, [True] * N) 274 275 def test_notify(self): 276 evt = self.eventtype() 277 self._check_notify(evt) 278 # Another time, after an explicit clear() 279 evt.set() 280 evt.clear() 281 self._check_notify(evt) 282 283 def test_timeout(self): 284 evt = self.eventtype() 285 results1 = [] 286 results2 = [] 287 N = 5 288 def f(): 289 results1.append(evt.wait(0.0)) 290 t1 = time.time() 291 r = evt.wait(0.2) 292 t2 = time.time() 293 results2.append((r, t2 - t1)) 294 Bunch(f, N).wait_for_finished() 295 self.assertEqual(results1, [False] * N) 296 for r, dt in results2: 297 self.assertFalse(r) 298 self.assertTrue(dt >= 0.2, dt) 299 # The event is set 300 results1 = [] 301 results2 = [] 302 evt.set() 303 Bunch(f, N).wait_for_finished() 304 self.assertEqual(results1, [True] * N) 305 for r, dt in results2: 306 self.assertTrue(r) 307 308 @unittest.skip('grumpy') 309 def test_reset_internal_locks(self): 310 evt = self.eventtype() 311 old_lock = evt._Event__cond._Condition__lock 312 evt._reset_internal_locks() 313 new_lock = evt._Event__cond._Condition__lock 314 self.assertIsNot(new_lock, old_lock) 315 self.assertIs(type(new_lock), type(old_lock)) 316 317 318 class ConditionTests(BaseTestCase): 319 """ 320 Tests for condition variables. 321 """ 322 323 def test_acquire(self): 324 cond = self.condtype() 325 # Be default we have an RLock: the condition can be acquired multiple 326 # times. 327 cond.acquire() 328 cond.acquire() 329 cond.release() 330 cond.release() 331 lock = threading.Lock() 332 cond = self.condtype(lock) 333 cond.acquire() 334 self.assertFalse(lock.acquire(False)) 335 cond.release() 336 self.assertTrue(lock.acquire(False)) 337 self.assertFalse(cond.acquire(False)) 338 lock.release() 339 with cond: 340 self.assertFalse(lock.acquire(False)) 341 342 def test_unacquired_wait(self): 343 cond = self.condtype() 344 self.assertRaises(RuntimeError, cond.wait) 345 346 def test_unacquired_notify(self): 347 cond = self.condtype() 348 self.assertRaises(RuntimeError, cond.notify) 349 350 def _check_notify(self, cond): 351 # Note that this test is sensitive to timing. If the worker threads 352 # don't execute in a timely fashion, the main thread may think they 353 # are further along then they are. The main thread therefore issues 354 # _wait() statements to try to make sure that it doesn't race ahead 355 # of the workers. 356 # Secondly, this test assumes that condition variables are not subject 357 # to spurious wakeups. The absence of spurious wakeups is an implementation 358 # detail of Condition Cariables in current CPython, but in general, not 359 # a guaranteed property of condition variables as a programming 360 # construct. In particular, it is possible that this can no longer 361 # be conveniently guaranteed should their implementation ever change. 362 N = 5 363 ready = [] 364 results1 = [] 365 results2 = [] 366 phase_num = 0 367 def f(): 368 cond.acquire() 369 ready.append(phase_num) 370 cond.wait() 371 cond.release() 372 results1.append(phase_num) 373 cond.acquire() 374 ready.append(phase_num) 375 cond.wait() 376 cond.release() 377 results2.append(phase_num) 378 b = Bunch(f, N) 379 b.wait_for_started() 380 # first wait, to ensure all workers settle into cond.wait() before 381 # we continue. See issues #8799 and #30727. 382 while len(ready) < 5: 383 _wait() 384 ready = [] 385 self.assertEqual(results1, []) 386 # Notify 3 threads at first 387 cond.acquire() 388 cond.notify(3) 389 _wait() 390 phase_num = 1 391 cond.release() 392 while len(results1) < 3: 393 _wait() 394 self.assertEqual(results1, [1] * 3) 395 self.assertEqual(results2, []) 396 # make sure all awaken workers settle into cond.wait() 397 while len(ready) < 3: 398 _wait() 399 # Notify 5 threads: they might be in their first or second wait 400 cond.acquire() 401 cond.notify(5) 402 _wait() 403 phase_num = 2 404 cond.release() 405 while len(results1) + len(results2) < 8: 406 _wait() 407 self.assertEqual(results1, [1] * 3 + [2] * 2) 408 self.assertEqual(results2, [2] * 3) 409 # make sure all workers settle into cond.wait() 410 while len(ready) < 5: 411 _wait() 412 # Notify all threads: they are all in their second wait 413 cond.acquire() 414 cond.notify_all() 415 _wait() 416 phase_num = 3 417 cond.release() 418 while len(results2) < 5: 419 _wait() 420 self.assertEqual(results1, [1] * 3 + [2] * 2) 421 self.assertEqual(results2, [2] * 3 + [3] * 2) 422 b.wait_for_finished() 423 424 def test_notify(self): 425 cond = self.condtype() 426 self._check_notify(cond) 427 # A second time, to check internal state is still ok. 428 self._check_notify(cond) 429 430 def test_timeout(self): 431 cond = self.condtype() 432 results = [] 433 N = 5 434 def f(): 435 cond.acquire() 436 t1 = time.time() 437 cond.wait(0.2) 438 t2 = time.time() 439 cond.release() 440 results.append(t2 - t1) 441 Bunch(f, N).wait_for_finished() 442 self.assertEqual(len(results), 5) 443 for dt in results: 444 self.assertTrue(dt >= 0.2, dt) 445 446 447 class BaseSemaphoreTests(BaseTestCase): 448 """ 449 Common tests for {bounded, unbounded} semaphore objects. 450 """ 451 452 def test_constructor(self): 453 self.assertRaises(ValueError, self.semtype, value = -1) 454 self.assertRaises(ValueError, self.semtype, value = -sys.maxint) 455 456 def test_acquire(self): 457 sem = self.semtype(1) 458 sem.acquire() 459 sem.release() 460 sem = self.semtype(2) 461 sem.acquire() 462 sem.acquire() 463 sem.release() 464 sem.release() 465 466 def test_acquire_destroy(self): 467 sem = self.semtype() 468 sem.acquire() 469 del sem 470 471 def test_acquire_contended(self): 472 sem = self.semtype(7) 473 sem.acquire() 474 N = 10 475 results1 = [] 476 results2 = [] 477 phase_num = 0 478 def f(): 479 sem.acquire() 480 results1.append(phase_num) 481 sem.acquire() 482 results2.append(phase_num) 483 b = Bunch(f, 10) 484 b.wait_for_started() 485 while len(results1) + len(results2) < 6: 486 _wait() 487 self.assertEqual(results1 + results2, [0] * 6) 488 phase_num = 1 489 for i in range(7): 490 sem.release() 491 while len(results1) + len(results2) < 13: 492 _wait() 493 self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7) 494 phase_num = 2 495 for i in range(6): 496 sem.release() 497 while len(results1) + len(results2) < 19: 498 _wait() 499 self.assertEqual(sorted(results1 + results2), [0] * 6 + [1] * 7 + [2] * 6) 500 # The semaphore is still locked 501 self.assertFalse(sem.acquire(False)) 502 # Final release, to let the last thread finish 503 sem.release() 504 b.wait_for_finished() 505 506 def test_try_acquire(self): 507 sem = self.semtype(2) 508 self.assertTrue(sem.acquire(False)) 509 self.assertTrue(sem.acquire(False)) 510 self.assertFalse(sem.acquire(False)) 511 sem.release() 512 self.assertTrue(sem.acquire(False)) 513 514 def test_try_acquire_contended(self): 515 sem = self.semtype(4) 516 sem.acquire() 517 results = [] 518 def f(): 519 results.append(sem.acquire(False)) 520 results.append(sem.acquire(False)) 521 Bunch(f, 5).wait_for_finished() 522 # There can be a thread switch between acquiring the semaphore and 523 # appending the result, therefore results will not necessarily be 524 # ordered. 525 self.assertEqual(sorted(results), [False] * 7 + [True] * 3 ) 526 527 def test_default_value(self): 528 # The default initial value is 1. 529 sem = self.semtype() 530 sem.acquire() 531 def f(): 532 sem.acquire() 533 sem.release() 534 b = Bunch(f, 1) 535 b.wait_for_started() 536 _wait() 537 self.assertFalse(b.finished) 538 sem.release() 539 b.wait_for_finished() 540 541 def test_with(self): 542 sem = self.semtype(2) 543 def _with(err=None): 544 with sem: 545 self.assertTrue(sem.acquire(False)) 546 sem.release() 547 with sem: 548 self.assertFalse(sem.acquire(False)) 549 if err: 550 raise err 551 _with() 552 self.assertTrue(sem.acquire(False)) 553 sem.release() 554 self.assertRaises(TypeError, _with, TypeError) 555 self.assertTrue(sem.acquire(False)) 556 sem.release() 557 558 class SemaphoreTests(BaseSemaphoreTests): 559 """ 560 Tests for unbounded semaphores. 561 """ 562 563 def test_release_unacquired(self): 564 # Unbounded releases are allowed and increment the semaphore's value 565 sem = self.semtype(1) 566 sem.release() 567 sem.acquire() 568 sem.acquire() 569 sem.release() 570 571 572 class BoundedSemaphoreTests(BaseSemaphoreTests): 573 """ 574 Tests for bounded semaphores. 575 """ 576 577 def test_release_unacquired(self): 578 # Cannot go past the initial value 579 sem = self.semtype() 580 self.assertRaises(ValueError, sem.release) 581 sem.acquire() 582 sem.release() 583 self.assertRaises(ValueError, sem.release)