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)