You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
3.0KB

  1. import unittest
  2. import sys
  3. import gc
  4. import time
  5. import weakref
  6. import greenlet
  7. import threading
  8. class ArgRefcountTests(unittest.TestCase):
  9. def test_arg_refs(self):
  10. args = ('a', 'b', 'c')
  11. refcount_before = sys.getrefcount(args)
  12. g = greenlet.greenlet(
  13. lambda *args: greenlet.getcurrent().parent.switch(*args))
  14. for i in range(100):
  15. g.switch(*args)
  16. self.assertEqual(sys.getrefcount(args), refcount_before)
  17. def test_kwarg_refs(self):
  18. kwargs = {}
  19. g = greenlet.greenlet(
  20. lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs))
  21. for i in range(100):
  22. g.switch(**kwargs)
  23. self.assertEqual(sys.getrefcount(kwargs), 2)
  24. if greenlet.GREENLET_USE_GC:
  25. # These only work with greenlet gc support
  26. def recycle_threads(self):
  27. # By introducing a thread that does sleep we allow other threads,
  28. # that have triggered their __block condition, but did not have a
  29. # chance to deallocate their thread state yet, to finally do so.
  30. # The way it works is by requiring a GIL switch (different thread),
  31. # which does a GIL release (sleep), which might do a GIL switch
  32. # to finished threads and allow them to clean up.
  33. def worker():
  34. time.sleep(0.001)
  35. t = threading.Thread(target=worker)
  36. t.start()
  37. time.sleep(0.001)
  38. t.join()
  39. def test_threaded_leak(self):
  40. gg = []
  41. def worker():
  42. # only main greenlet present
  43. gg.append(weakref.ref(greenlet.getcurrent()))
  44. for i in range(2):
  45. t = threading.Thread(target=worker)
  46. t.start()
  47. t.join()
  48. del t
  49. greenlet.getcurrent() # update ts_current
  50. self.recycle_threads()
  51. greenlet.getcurrent() # update ts_current
  52. gc.collect()
  53. greenlet.getcurrent() # update ts_current
  54. for g in gg:
  55. self.assertTrue(g() is None)
  56. def test_threaded_adv_leak(self):
  57. gg = []
  58. def worker():
  59. # main and additional *finished* greenlets
  60. ll = greenlet.getcurrent().ll = []
  61. def additional():
  62. ll.append(greenlet.getcurrent())
  63. for i in range(2):
  64. greenlet.greenlet(additional).switch()
  65. gg.append(weakref.ref(greenlet.getcurrent()))
  66. for i in range(2):
  67. t = threading.Thread(target=worker)
  68. t.start()
  69. t.join()
  70. del t
  71. greenlet.getcurrent() # update ts_current
  72. self.recycle_threads()
  73. greenlet.getcurrent() # update ts_current
  74. gc.collect()
  75. greenlet.getcurrent() # update ts_current
  76. for g in gg:
  77. self.assertTrue(g() is None)