From 8ed4abccdc503f91154ff8bd791e464292319a47 Mon Sep 17 00:00:00 2001 From: dave Date: Thu, 14 Mar 2019 10:05:50 -0600 Subject: [PATCH] Split PythonHouseKeeper into .h and .cpp file for easier debugging --- .../Private/PythonHouseKeeper.cpp | 255 +++++++++++++ .../Public/PythonHouseKeeper.h | 340 +++--------------- .../UnrealEnginePython.Build.cs | 3 - 3 files changed, 309 insertions(+), 289 deletions(-) create mode 100644 Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp diff --git a/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp new file mode 100644 index 000000000..ea9d5dda3 --- /dev/null +++ b/Source/UnrealEnginePython/Private/PythonHouseKeeper.cpp @@ -0,0 +1,255 @@ +#pragma once + +#include "PythonHouseKeeper.h" + +void FUnrealEnginePythonHouseKeeper::AddReferencedObjects(FReferenceCollector& InCollector) +{ + InCollector.AddReferencedObjects(PythonTrackedObjects); +} + +FUnrealEnginePythonHouseKeeper *FUnrealEnginePythonHouseKeeper::Get() +{ + static FUnrealEnginePythonHouseKeeper *Singleton; + if (!Singleton) + { + Singleton = new FUnrealEnginePythonHouseKeeper(); + // register a new delegate for the GC +#if ENGINE_MINOR_VERSION >= 18 + FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); +#else + FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); +#endif + } + return Singleton; +} + +void FUnrealEnginePythonHouseKeeper::RunGCDelegate() +{ + FScopePythonGIL gil; + RunGC(); +} + +int32 FUnrealEnginePythonHouseKeeper::RunGC() +{ + int32 Garbaged = PyUObjectsGC(); + Garbaged += DelegatesGC(); + return Garbaged; +} + +bool FUnrealEnginePythonHouseKeeper::IsValidPyUObject(ue_PyUObject *PyUObject) +{ + if (!PyUObject) + return false; + + UObject *Object = PyUObject->ue_object; + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return false; + } + + if (!Tracker->Owner.IsValid()) + return false; + + return true; + +} + +void FUnrealEnginePythonHouseKeeper::TrackUObject(UObject *Object) +{ + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return; + } + if (Tracker->bPythonOwned) + return; + Tracker->bPythonOwned = true; + // when a new ue_PyUObject spawns, it has a reference counting of two + Py_DECREF(Tracker->PyUObject); + Tracker->PyUObject->owned = 1; + PythonTrackedObjects.Add(Object); +} + +void FUnrealEnginePythonHouseKeeper::UntrackUObject(UObject *Object) +{ + PythonTrackedObjects.Remove(Object); +} + +void FUnrealEnginePythonHouseKeeper::RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject) +{ + UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject)); +} + +void FUnrealEnginePythonHouseKeeper::UnregisterPyUObject(UObject *Object) +{ + UObjectPyMapping.Remove(Object); +} + +ue_PyUObject *FUnrealEnginePythonHouseKeeper::GetPyUObject(UObject *Object) +{ + FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); + if (!Tracker) + { + return nullptr; + } + + if (!Tracker->Owner.IsValid(true)) + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt); +#endif + if (!Tracker->bPythonOwned) + Py_DECREF((PyObject *)Tracker->PyUObject); + UnregisterPyUObject(Object); + return nullptr; +} + + return Tracker->PyUObject; +} + +uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC() +{ + uint32 Garbaged = 0; + TArray BrokenList; + for (auto &UObjectPyItem : UObjectPyMapping) + { + UObject *Object = UObjectPyItem.Key; + FPythonUOjectTracker &Tracker = UObjectPyItem.Value; +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object); +#endif + if (!Tracker.Owner.IsValid(true)) + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt); +#endif + BrokenList.Add(Object); + Garbaged++; + } + else + { +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName()); +#endif +} + } + + for (UObject *Object : BrokenList) + { + FPythonUOjectTracker &Tracker = UObjectPyMapping[Object]; + if (!Tracker.bPythonOwned) + Py_DECREF((PyObject *)Tracker.PyUObject); + UnregisterPyUObject(Object); + } + + return Garbaged; + +} + + +int32 FUnrealEnginePythonHouseKeeper::DelegatesGC() +{ + int32 Garbaged = 0; +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num()); +#endif + for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; + if (!Tracker.Owner.IsValid(true)) + { + Tracker.Delegate->RemoveFromRoot(); + PyDelegatesTracker.RemoveAt(i); + Garbaged++; + } + + } + +#if defined(UEPY_MEMORY_DEBUG) + UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num()); +#endif + + for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i]; + if (!Tracker.Owner.IsValid()) + { + PySlateDelegatesTracker.RemoveAt(i); + Garbaged++; + } + + } + return Garbaged; + } + +UPythonDelegate *FUnrealEnginePythonHouseKeeper::FindDelegate(UObject *Owner, PyObject *PyCallable) +{ + for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) + { + FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; + if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable)) + return Tracker.Delegate; + } + return nullptr; +} + +UPythonDelegate *FUnrealEnginePythonHouseKeeper::NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature) +{ + UPythonDelegate *Delegate = NewObject(); + + Delegate->AddToRoot(); + Delegate->SetPyCallable(PyCallable); + Delegate->SetSignature(Signature); + + FPythonDelegateTracker Tracker(Delegate, Owner); + PyDelegatesTracker.Add(Tracker); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); + PySlateDelegatesTracker.Add(Tracker); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewDeferredSlateDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + return Delegate; +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewPythonSmartDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSmartDelegate()); + Delegate->SetPyCallable(PyCallable); + + PyStaticSmartDelegatesTracker.Add(Delegate); + + return Delegate; +} + +void FUnrealEnginePythonHouseKeeper::TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner) +{ + FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); + PySlateDelegatesTracker.Add(Tracker); +} + +TSharedRef FUnrealEnginePythonHouseKeeper::NewStaticSlateDelegate(PyObject *PyCallable) +{ + TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); + Delegate->SetPyCallable(PyCallable); + + PyStaticSlateDelegatesTracker.Add(Delegate); + + return Delegate; +} + diff --git a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h index dcde4d3a7..ccd9edb01 100644 --- a/Source/UnrealEnginePython/Public/PythonHouseKeeper.h +++ b/Source/UnrealEnginePython/Public/PythonHouseKeeper.h @@ -11,304 +11,72 @@ class FUnrealEnginePythonHouseKeeper : public FGCObject { - - struct FPythonUOjectTracker - { - FWeakObjectPtr Owner; - ue_PyUObject *PyUObject; - bool bPythonOwned; - - FPythonUOjectTracker(UObject *Object, ue_PyUObject *InPyUObject) - { - Owner = FWeakObjectPtr(Object); - PyUObject = InPyUObject; - bPythonOwned = false; - } - }; - - struct FPythonDelegateTracker - { - FWeakObjectPtr Owner; - UPythonDelegate *Delegate; - - FPythonDelegateTracker(UPythonDelegate *DelegateToTrack, UObject *DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) - { - } - - ~FPythonDelegateTracker() - { - } - }; - - - struct FPythonSWidgetDelegateTracker - { - TWeakPtr Owner; - TSharedPtr Delegate; - - FPythonSWidgetDelegateTracker(TSharedRef DelegateToTrack, TSharedRef DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) - { - } - - ~FPythonSWidgetDelegateTracker() - { - } - }; - -public: - - virtual void AddReferencedObjects(FReferenceCollector& InCollector) override - { - InCollector.AddReferencedObjects(PythonTrackedObjects); - } - - static FUnrealEnginePythonHouseKeeper *Get() - { - static FUnrealEnginePythonHouseKeeper *Singleton; - if (!Singleton) - { - Singleton = new FUnrealEnginePythonHouseKeeper(); - // register a new delegate for the GC -#if ENGINE_MINOR_VERSION >= 18 - FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); -#else - FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate); -#endif - } - return Singleton; - } - - void RunGCDelegate() - { - FScopePythonGIL gil; - RunGC(); - } - - int32 RunGC() - { - int32 Garbaged = PyUObjectsGC(); - Garbaged += DelegatesGC(); - return Garbaged; - } - - bool IsValidPyUObject(ue_PyUObject *PyUObject) - { - if (!PyUObject) - return false; - - UObject *Object = PyUObject->ue_object; - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return false; - } - - if (!Tracker->Owner.IsValid()) - return false; - - return true; - - } - - void TrackUObject(UObject *Object) - { - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return; - } - if (Tracker->bPythonOwned) - return; - Tracker->bPythonOwned = true; - // when a new ue_PyUObject spawns, it has a reference counting of two - Py_DECREF(Tracker->PyUObject); - Tracker->PyUObject->owned = 1; - PythonTrackedObjects.Add(Object); - } - - void UntrackUObject(UObject *Object) - { - PythonTrackedObjects.Remove(Object); - } - - void RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject) - { - UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject)); - } - - void UnregisterPyUObject(UObject *Object) - { - UObjectPyMapping.Remove(Object); - } - - ue_PyUObject *GetPyUObject(UObject *Object) - { - FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object); - if (!Tracker) - { - return nullptr; - } - - if (!Tracker->Owner.IsValid(true)) - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt); -#endif - if (!Tracker->bPythonOwned) - Py_DECREF((PyObject *)Tracker->PyUObject); - UnregisterPyUObject(Object); - return nullptr; - } - - return Tracker->PyUObject; -} - - uint32 PyUObjectsGC() - { - uint32 Garbaged = 0; - TArray BrokenList; - for (auto &UObjectPyItem : UObjectPyMapping) - { - UObject *Object = UObjectPyItem.Key; - FPythonUOjectTracker &Tracker = UObjectPyItem.Value; -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object); -#endif - if (!Tracker.Owner.IsValid(true)) - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt); -#endif - BrokenList.Add(Object); - Garbaged++; - } - else - { -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName()); -#endif - } - } - - for (UObject *Object : BrokenList) - { - FPythonUOjectTracker &Tracker = UObjectPyMapping[Object]; - if (!Tracker.bPythonOwned) - Py_DECREF((PyObject *)Tracker.PyUObject); - UnregisterPyUObject(Object); - } - - return Garbaged; - - } - - - int32 DelegatesGC() - { - int32 Garbaged = 0; -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num()); -#endif - for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; - if (!Tracker.Owner.IsValid(true)) - { - Tracker.Delegate->RemoveFromRoot(); - PyDelegatesTracker.RemoveAt(i); - Garbaged++; - } - - } - -#if defined(UEPY_MEMORY_DEBUG) - UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num()); -#endif - - for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i]; - if (!Tracker.Owner.IsValid()) - { - PySlateDelegatesTracker.RemoveAt(i); - Garbaged++; - } - - } - return Garbaged; - } - - UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable) + struct FPythonUOjectTracker { - for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i) - { - FPythonDelegateTracker &Tracker = PyDelegatesTracker[i]; - if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable)) - return Tracker.Delegate; + FWeakObjectPtr Owner; + ue_PyUObject *PyUObject; + bool bPythonOwned; + + FPythonUOjectTracker(UObject *Object, ue_PyUObject *InPyUObject) + { + Owner = FWeakObjectPtr(Object); + PyUObject = InPyUObject; + bPythonOwned = false; } - return nullptr; - } - - UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature) - { - UPythonDelegate *Delegate = NewObject(); - - Delegate->AddToRoot(); - Delegate->SetPyCallable(PyCallable); - Delegate->SetSignature(Signature); - - FPythonDelegateTracker Tracker(Delegate, Owner); - PyDelegatesTracker.Add(Tracker); + }; - return Delegate; - } - - TSharedRef NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); - - FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); - PySlateDelegatesTracker.Add(Tracker); - - return Delegate; - } - - TSharedRef NewDeferredSlateDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); - - return Delegate; - } + struct FPythonDelegateTracker + { + FWeakObjectPtr Owner; + UPythonDelegate *Delegate; - TSharedRef NewPythonSmartDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSmartDelegate()); - Delegate->SetPyCallable(PyCallable); + FPythonDelegateTracker(UPythonDelegate *DelegateToTrack, UObject *DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) + { + } - PyStaticSmartDelegatesTracker.Add(Delegate); + ~FPythonDelegateTracker() + { + } + }; - return Delegate; - } + struct FPythonSWidgetDelegateTracker + { + TWeakPtr Owner; + TSharedPtr Delegate; - void TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner) - { - FPythonSWidgetDelegateTracker Tracker(Delegate, Owner); - PySlateDelegatesTracker.Add(Tracker); - } + FPythonSWidgetDelegateTracker(TSharedRef DelegateToTrack, TSharedRef DelegateOwner) : Owner(DelegateOwner), Delegate(DelegateToTrack) + { + } - TSharedRef NewStaticSlateDelegate(PyObject *PyCallable) - { - TSharedRef Delegate = MakeShareable(new FPythonSlateDelegate()); - Delegate->SetPyCallable(PyCallable); + ~FPythonSWidgetDelegateTracker() + { + } + }; - PyStaticSlateDelegatesTracker.Add(Delegate); +public: - return Delegate; - } + virtual void AddReferencedObjects(FReferenceCollector& InCollector) override; + static FUnrealEnginePythonHouseKeeper *Get(); + int32 RunGC(); + bool IsValidPyUObject(ue_PyUObject *PyUObject); + void TrackUObject(UObject *Object); + void UntrackUObject(UObject *Object); + void RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject); + void UnregisterPyUObject(UObject *Object); + ue_PyUObject *GetPyUObject(UObject *Object); + UPythonDelegate *FindDelegate(UObject *Owner, PyObject *PyCallable); + UPythonDelegate *NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature); + TSharedRef NewSlateDelegate(TSharedRef Owner, PyObject *PyCallable); + TSharedRef NewDeferredSlateDelegate(PyObject *PyCallable); + TSharedRef NewPythonSmartDelegate(PyObject *PyCallable); + void TrackDeferredSlateDelegate(TSharedRef Delegate, TSharedRef Owner); + TSharedRef NewStaticSlateDelegate(PyObject *PyCallable); private: + void RunGCDelegate(); + uint32 PyUObjectsGC(); + int32 DelegatesGC(); + TMap UObjectPyMapping; TArray PyDelegatesTracker; diff --git a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs index 48d6618c1..51394b033 100644 --- a/Source/UnrealEnginePython/UnrealEnginePython.Build.cs +++ b/Source/UnrealEnginePython/UnrealEnginePython.Build.cs @@ -107,9 +107,6 @@ public UnrealEnginePython(TargetInfo Target) PrivateIncludePaths.AddRange( new string[] { -#if !UE_4_22_OR_LATER - "UnrealEnginePython/Private", -#endif // ... add other private include paths required here ... } );