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