diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2023-11-09 11:45:49 +0100 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2023-11-09 11:45:49 +0100 |
commit | ce53362f9808c9b0bba7382be926d8b9459f1bb7 (patch) | |
tree | 5b391360724a9eceee78e58d69c5e0f1f55c4c0e /modules/mono/csharp_script.cpp | |
parent | 432c75d6af8be64174969f593ddb96c37d25bdf2 (diff) | |
parent | 9750e49c57e79844c3696f789d4fa6275f8a3a0b (diff) | |
download | redot-engine-ce53362f9808c9b0bba7382be926d8b9459f1bb7.tar.gz |
Merge pull request #83670 from raulsntos/notification-predelete-cleanup
Add `NOTIFICATION_PREDELETE_CLEANUP` notification to fix C# `Dispose()`
Diffstat (limited to 'modules/mono/csharp_script.cpp')
-rw-r--r-- | modules/mono/csharp_script.cpp | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 3cc32bff10..56e4fa53d0 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1989,24 +1989,31 @@ const Variant CSharpInstance::get_rpc_config() const { void CSharpInstance::notification(int p_notification, bool p_reversed) { if (p_notification == Object::NOTIFICATION_PREDELETE) { - // When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose(). - // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed + if (base_ref_counted) { + // At this point, Dispose() was already called (manually or from the finalizer). + // The RefCounted wouldn't have reached 0 otherwise, since the managed side + // references it and Dispose() needs to be called to release it. + // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but + // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 + return; + } + } else if (p_notification == Object::NOTIFICATION_PREDELETE_CLEANUP) { + // When NOTIFICATION_PREDELETE_CLEANUP is sent, we also take the chance to call Dispose(). + // It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE_CLEANUP is guaranteed // to be sent at least once, which happens right before the call to the destructor. predelete_notified = true; if (base_ref_counted) { - // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0. - // At this point, Dispose() was already called (manually or from the finalizer) so - // that's not a problem. The refcount wouldn't have reached 0 otherwise, since the - // managed side references it and Dispose() needs to be called to release it. - // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but - // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 + // At this point, Dispose() was already called (manually or from the finalizer). + // The RefCounted wouldn't have reached 0 otherwise, since the managed side + // references it and Dispose() needs to be called to release it. return; } - _call_notification(p_notification, p_reversed); - + // NOTIFICATION_PREDELETE_CLEANUP is not sent to scripts. + // After calling Dispose() the C# instance can no longer be used, + // so it should be the last thing we do. GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose( gchandle.get_intptr(), /* okIfNull */ false); |