|
27 | 27 | #include <deemon/arg.h> /* DeeArg_Unpack*, UNPxSIZ */ |
28 | 28 | #include <deemon/asm.h> /* ASM_RET_NONE, instruction_t */ |
29 | 29 | #include <deemon/bool.h> /* return_bool, return_false, return_true */ |
| 30 | +#include <deemon/system.h> /* return_bool, return_false, return_true */ |
30 | 31 | #include <deemon/class.h> /* instance_clear, instance_tclear */ |
31 | 32 | #include <deemon/code.h> /* DeeCodeObject, DeeCode_NAME, DeeCode_Type, DeeFunctionObject, DeeFunction_*, Dee_CODE_FFINALLY, instruction_t */ |
32 | 33 | #include <deemon/computed-operators.h> /* DEFIMPL, DEFIMPL_UNSUPPORTED */ |
|
73 | 74 | #define DBG_memset(dst, byte, n_bytes) (void)0 |
74 | 75 | #endif /* NDEBUG */ |
75 | 76 |
|
| 77 | +#if !defined(NDEBUG) && 0 |
| 78 | +#if 0 |
| 79 | +#define GC_TRACE(...) fprintf(stderr, __VA_ARGS__) |
| 80 | +#else |
| 81 | +#define GC_TRACE(...) Dee_DPRINTF(__VA_ARGS__) |
| 82 | +#endif |
| 83 | +#else |
| 84 | +#define GC_TRACE(...) (void)0 |
| 85 | +#define GC_TRACE_IS_NOOP |
| 86 | +#endif |
| 87 | + |
76 | 88 | DECL_BEGIN |
77 | 89 |
|
78 | 90 | #ifndef NDEBUG |
@@ -211,10 +223,16 @@ PRIVATE Dee_atomic_lock_t gc_lock = Dee_ATOMIC_LOCK_INIT; |
211 | 223 | #define gc_lock_available() Dee_atomic_lock_available(&gc_lock) |
212 | 224 | #define gc_lock_acquired() Dee_atomic_lock_acquired(&gc_lock) |
213 | 225 | #define gc_lock_tryacquire() Dee_atomic_lock_tryacquire(&gc_lock) |
214 | | -#define gc_lock_acquire() Dee_atomic_lock_acquire(&gc_lock) |
215 | 226 | #define gc_lock_waitfor() Dee_atomic_lock_waitfor(&gc_lock) |
216 | 227 | #define _gc_lock_release() Dee_atomic_lock_release(&gc_lock) |
217 | 228 |
|
| 229 | +PRIVATE void DCALL gc_lock_acquire(void) { |
| 230 | + while (!gc_lock_tryacquire()) { |
| 231 | + DeeThread_CheckInterruptNoInt(); |
| 232 | + SCHED_YIELD(); |
| 233 | + } |
| 234 | +} |
| 235 | + |
218 | 236 | /* Called to (try to) collect GC objects after "gg_collect_on" of some |
219 | 237 | * GC generation was reached. This function is must be called without |
220 | 238 | * the calling thread holding any (internal) locks, include locks |
@@ -445,11 +463,6 @@ PRIVATE void DCALL gc_lock_reap(unsigned int flags) { |
445 | 463 | gc_lock_reap_and_release(flags); |
446 | 464 | } |
447 | 465 |
|
448 | | -PRIVATE bool DCALL gc_lock_force_reap(unsigned int flags) { |
449 | | - gc_lock_acquire(); |
450 | | - return gc_lock_reap_and_release(flags); |
451 | | -} |
452 | | - |
453 | 466 | PRIVATE void DCALL gc_lock_acquire_and_reap(unsigned int flags) { |
454 | 467 | unsigned int status; |
455 | 468 | again: |
@@ -479,6 +492,14 @@ DeeGC_Track(DREF DeeObject *__restrict ob) { |
479 | 492 | bool must_collect; |
480 | 493 | struct Dee_gc_head *head = DeeGC_Head(ob); |
481 | 494 | ASSERT(!((uintptr_t)&head->gc_next & Dee_GC_FLAG_MASK)); |
| 495 | +#ifndef GC_TRACE_IS_NOOP |
| 496 | + if (atomic_read(&DeeThread_Self()->t_state) & Dee_THREAD_STATE_SHUTDOWNINTR) { |
| 497 | + GC_TRACE("%llu: %p: DeeGC_Track(%s, %p)\n", |
| 498 | + DeeSystem_GetWalltime(), DeeThread_Self(), |
| 499 | + ob->ob_type->tp_name, ob); |
| 500 | + } |
| 501 | +#endif /* !GC_TRACE_IS_NOOP */ |
| 502 | + |
482 | 503 | if (!gc_lock_tryacquire()) { |
483 | 504 | /* Setup as a pending insert */ |
484 | 505 | DeeObject *next; |
@@ -788,19 +809,30 @@ PRIVATE WUNUSED bool DCALL |
788 | 809 | gc_collect_acquire(bool allow_interrupts_and_errors) { |
789 | 810 | DeeObject *pending_remove; |
790 | 811 | DeeThreadObject *threads; |
| 812 | + GC_TRACE("%llu: %p: %s(%d) : HERE%s\n", DeeSystem_GetWalltime(), DeeThread_Self(), __FILE__, __LINE__, |
| 813 | + DeeThread_WasInterrupted(DeeThread_Self()) ? " [INTERRUPT]" : ""); |
791 | 814 | again: |
792 | 815 | /* Wait for "gc_lock" and "gc_remove_modifying" to settle. |
793 | 816 | * |
794 | 817 | * During this part, also try to make it so there's a low |
795 | 818 | * probability of the GC needing to be reaped once we've |
796 | 819 | * suspended other threads below! */ |
797 | 820 | for (;;) { |
798 | | - while (!gc_lock_available() || atomic_read(&gc_remove_modifying)) |
| 821 | + while (!gc_lock_available() || atomic_read(&gc_remove_modifying)) { |
| 822 | + if (allow_interrupts_and_errors) { |
| 823 | + if (DeeThread_CheckInterrupt()) |
| 824 | + goto err; |
| 825 | + } else { |
| 826 | + DeeThread_CheckInterruptNoInt(); |
| 827 | + } |
799 | 828 | SCHED_YIELD(); |
| 829 | + } |
800 | 830 | if (!atomic_read(&gc_mustreap)) |
801 | 831 | break; |
802 | | - if (!gc_lock_force_reap(DeeGC_TRACK_F_NOCOLLECT)) |
803 | | - break; |
| 832 | + if (!gc_lock_tryacquire()) |
| 833 | + continue; |
| 834 | + gc_lock_reap_and_release(DeeGC_TRACK_F_NOCOLLECT); |
| 835 | + break; |
804 | 836 | } |
805 | 837 |
|
806 | 838 | /* Suspend all other threads (or at least *try* to) */ |
@@ -861,11 +893,15 @@ gc_collect_acquire(bool allow_interrupts_and_errors) { |
861 | 893 | } |
862 | 894 |
|
863 | 895 | ASSERT(!DeeThread_IsMultiThreaded); |
| 896 | + GC_TRACE("%llu: %p: %s(%d) : HERE%s\n", DeeSystem_GetWalltime(), DeeThread_Self(), __FILE__, __LINE__, |
| 897 | + DeeThread_WasInterrupted(DeeThread_Self()) ? " [INTERRUPT]" : ""); |
864 | 898 | return true; |
865 | 899 | resume_threads_and_try_again: |
866 | 900 | DeeThread_ResumeAll(); |
867 | 901 | goto again; |
868 | 902 | err: |
| 903 | + GC_TRACE("%llu: %p: %s(%d) : HERE%s\n", DeeSystem_GetWalltime(), DeeThread_Self(), __FILE__, __LINE__, |
| 904 | + DeeThread_WasInterrupted(DeeThread_Self()) ? " [INTERRUPT]" : ""); |
869 | 905 | return false; |
870 | 906 | } |
871 | 907 |
|
@@ -1260,6 +1296,7 @@ continue_with_next_generation:; |
1260 | 1296 |
|
1261 | 1297 | /* Collect memory in GC generations */ |
1262 | 1298 | status = gc_collect_threshold_generations_r(&gc_gen0); |
| 1299 | + GC_TRACE("%llu: %p: %s(%d) : COLLECTED: %u\n", DeeSystem_GetWalltime(), DeeThread_Self(), __FILE__, __LINE__, status); |
1263 | 1300 | switch (status) { |
1264 | 1301 | case GC_GENERATION_COLLECT_OR_UNLOCK__NOTHING: |
1265 | 1302 | /* Nothing could be collected (must objects were moved as they should) */ |
@@ -1316,10 +1353,11 @@ PRIVATE ATTR_NOINLINE WUNUSED bool DCALL gc_trycollect_gen0(void) { |
1316 | 1353 | flags |= GC_GENERATION_COLLECT_OR_UNLOCK__F_MOVE_REACHABLE; |
1317 | 1354 | ASSERT(!DeeThread_IsMultiThreaded); |
1318 | 1355 | status = gc_generation_collect_or_unlock(iter, &count, flags); |
| 1356 | + GC_TRACE("%llu: %p: %s(%d) : COLLECTED: %u: %lu\n", DeeSystem_GetWalltime(), DeeThread_Self(), __FILE__, __LINE__, status, (unsigned long)count); |
1319 | 1357 | } else { |
1320 | | - /* Stop once all overflowing objects have been settled into appropriate generations */ |
1321 | | - status = GC_GENERATION_COLLECT_OR_UNLOCK__SUCCESS; |
| 1358 | + /* All done! */ |
1322 | 1359 | gc_collect_release(); |
| 1360 | + return true; |
1323 | 1361 | } |
1324 | 1362 | switch (status) { |
1325 | 1363 | case GC_GENERATION_COLLECT_OR_UNLOCK__NOTHING: |
|
0 commit comments