Workaround data race on cyclic collector deinit

This commit is contained in:
Svyatoslav Scherbina
2020-02-20 09:57:40 +03:00
committed by SvyatoslavScherbina
parent 60108071dd
commit b2d3bcf6fd
+35 -17
View File
@@ -134,6 +134,12 @@ class CyclicCollector {
CHECK_CALL(pthread_create(&gcThread_, nullptr, gcWorkerRoutine, this), "Cannot start collector thread") CHECK_CALL(pthread_create(&gcThread_, nullptr, gcWorkerRoutine, this), "Cannot start collector thread")
} }
void clear() {
Locker lock(&lock_);
rootset_.clear();
toRelease_.clear();
}
void terminate() { void terminate() {
{ {
Locker locker(&lock_); Locker locker(&lock_);
@@ -436,62 +442,74 @@ void cyclicDeinit() {
auto* local = cyclicCollector; auto* local = cyclicCollector;
local->terminate(); local->terminate();
cyclicCollector = nullptr; cyclicCollector = nullptr;
konanDestructInstance(local); // Workaround data race with threads non-atomically reading and then using [cyclicCollector].
// konanDestructInstance(local);
// Note: memory leaks here indeed, but usually it happens once per application.
// Make best effort to clean some memory:
local->clear();
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicAddWorker(void* worker) { void cyclicAddWorker(void* worker) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->addWorker(worker); if (local)
local->addWorker(worker);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicRemoveWorker(void* worker) { void cyclicRemoveWorker(void* worker) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->removeWorker(worker); if (local)
local->removeWorker(worker);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicCollectorCallback(void* worker) { void cyclicCollectorCallback(void* worker) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->collectorCallaback(worker); if (local)
local->collectorCallaback(worker);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicScheduleGarbageCollect() { void cyclicScheduleGarbageCollect() {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->scheduleGarbageCollect(); if (local)
local->scheduleGarbageCollect();
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicAddAtomicRoot(ObjHeader* obj) { void cyclicAddAtomicRoot(ObjHeader* obj) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->addRoot(obj); if (local)
local->addRoot(obj);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicRemoveAtomicRoot(ObjHeader* obj) { void cyclicRemoveAtomicRoot(ObjHeader* obj) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->removeRoot(obj); if (local)
local->removeRoot(obj);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicMutateAtomicRoot(ObjHeader* newValue) { void cyclicMutateAtomicRoot(ObjHeader* newValue) {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->mutateRoot(newValue); if (local)
local->mutateRoot(newValue);
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }
void cyclicLocalGC() { void cyclicLocalGC() {
#if WITH_WORKERS #if WITH_WORKERS
if (cyclicCollector) auto* local = cyclicCollector;
cyclicCollector->localGC(); if (local)
local->localGC();
#endif // WITH_WORKERS #endif // WITH_WORKERS
} }