| 426 | self.assertEqual((b, c), (1, 0)) |
| 427 | |
| 428 | def test_trashcan(self): |
| 429 | class Ouch: |
| 430 | n = 0 |
| 431 | def __del__(self): |
| 432 | Ouch.n = Ouch.n + 1 |
| 433 | if Ouch.n % 17 == 0: |
| 434 | gc.collect() |
| 435 | |
| 436 | # "trashcan" is a hack to prevent stack overflow when deallocating |
| 437 | # very deeply nested tuples etc. It works in part by abusing the |
| 438 | # type pointer and refcount fields, and that can yield horrible |
| 439 | # problems when gc tries to traverse the structures. |
| 440 | # If this test fails (as it does in 2.0, 2.1 and 2.2), it will |
| 441 | # most likely die via segfault. |
| 442 | |
| 443 | # Note: In 2.3 the possibility for compiling without cyclic gc was |
| 444 | # removed, and that in turn allows the trashcan mechanism to work |
| 445 | # via much simpler means (e.g., it never abuses the type pointer or |
| 446 | # refcount fields anymore). Since it's much less likely to cause a |
| 447 | # problem now, the various constants in this expensive (we force a lot |
| 448 | # of full collections) test are cut back from the 2.2 version. |
| 449 | gc.enable() |
| 450 | N = 150 |
| 451 | for count in range(2): |
| 452 | t = [] |
| 453 | for i in range(N): |
| 454 | t = [t, Ouch()] |
| 455 | u = [] |
| 456 | for i in range(N): |
| 457 | u = [u, Ouch()] |
| 458 | v = {} |
| 459 | for i in range(N): |
| 460 | v = {1: v, 2: Ouch()} |
| 461 | gc.disable() |
| 462 | |
| 463 | @threading_helper.requires_working_threading() |
| 464 | def test_trashcan_threads(self): |