Skip to content

Commit 8de7445

Browse files
authored
Merge pull request 20tab#692 from dfb/pr_split_housekeeper
Split PythonHouseKeeper
2 parents 83fea2d + 8ed4abc commit 8de7445

File tree

3 files changed

+309
-289
lines changed

3 files changed

+309
-289
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
#pragma once
2+
3+
#include "PythonHouseKeeper.h"
4+
5+
void FUnrealEnginePythonHouseKeeper::AddReferencedObjects(FReferenceCollector& InCollector)
6+
{
7+
InCollector.AddReferencedObjects(PythonTrackedObjects);
8+
}
9+
10+
FUnrealEnginePythonHouseKeeper *FUnrealEnginePythonHouseKeeper::Get()
11+
{
12+
static FUnrealEnginePythonHouseKeeper *Singleton;
13+
if (!Singleton)
14+
{
15+
Singleton = new FUnrealEnginePythonHouseKeeper();
16+
// register a new delegate for the GC
17+
#if ENGINE_MINOR_VERSION >= 18
18+
FCoreUObjectDelegates::GetPostGarbageCollect().AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
19+
#else
20+
FCoreUObjectDelegates::PostGarbageCollect.AddRaw(Singleton, &FUnrealEnginePythonHouseKeeper::RunGCDelegate);
21+
#endif
22+
}
23+
return Singleton;
24+
}
25+
26+
void FUnrealEnginePythonHouseKeeper::RunGCDelegate()
27+
{
28+
FScopePythonGIL gil;
29+
RunGC();
30+
}
31+
32+
int32 FUnrealEnginePythonHouseKeeper::RunGC()
33+
{
34+
int32 Garbaged = PyUObjectsGC();
35+
Garbaged += DelegatesGC();
36+
return Garbaged;
37+
}
38+
39+
bool FUnrealEnginePythonHouseKeeper::IsValidPyUObject(ue_PyUObject *PyUObject)
40+
{
41+
if (!PyUObject)
42+
return false;
43+
44+
UObject *Object = PyUObject->ue_object;
45+
FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
46+
if (!Tracker)
47+
{
48+
return false;
49+
}
50+
51+
if (!Tracker->Owner.IsValid())
52+
return false;
53+
54+
return true;
55+
56+
}
57+
58+
void FUnrealEnginePythonHouseKeeper::TrackUObject(UObject *Object)
59+
{
60+
FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
61+
if (!Tracker)
62+
{
63+
return;
64+
}
65+
if (Tracker->bPythonOwned)
66+
return;
67+
Tracker->bPythonOwned = true;
68+
// when a new ue_PyUObject spawns, it has a reference counting of two
69+
Py_DECREF(Tracker->PyUObject);
70+
Tracker->PyUObject->owned = 1;
71+
PythonTrackedObjects.Add(Object);
72+
}
73+
74+
void FUnrealEnginePythonHouseKeeper::UntrackUObject(UObject *Object)
75+
{
76+
PythonTrackedObjects.Remove(Object);
77+
}
78+
79+
void FUnrealEnginePythonHouseKeeper::RegisterPyUObject(UObject *Object, ue_PyUObject *InPyUObject)
80+
{
81+
UObjectPyMapping.Add(Object, FPythonUOjectTracker(Object, InPyUObject));
82+
}
83+
84+
void FUnrealEnginePythonHouseKeeper::UnregisterPyUObject(UObject *Object)
85+
{
86+
UObjectPyMapping.Remove(Object);
87+
}
88+
89+
ue_PyUObject *FUnrealEnginePythonHouseKeeper::GetPyUObject(UObject *Object)
90+
{
91+
FPythonUOjectTracker *Tracker = UObjectPyMapping.Find(Object);
92+
if (!Tracker)
93+
{
94+
return nullptr;
95+
}
96+
97+
if (!Tracker->Owner.IsValid(true))
98+
{
99+
#if defined(UEPY_MEMORY_DEBUG)
100+
UE_LOG(LogPython, Warning, TEXT("DEFREF'ing UObject at %p (refcnt: %d)"), Object, Tracker->PyUObject->ob_base.ob_refcnt);
101+
#endif
102+
if (!Tracker->bPythonOwned)
103+
Py_DECREF((PyObject *)Tracker->PyUObject);
104+
UnregisterPyUObject(Object);
105+
return nullptr;
106+
}
107+
108+
return Tracker->PyUObject;
109+
}
110+
111+
uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC()
112+
{
113+
uint32 Garbaged = 0;
114+
TArray<UObject *> BrokenList;
115+
for (auto &UObjectPyItem : UObjectPyMapping)
116+
{
117+
UObject *Object = UObjectPyItem.Key;
118+
FPythonUOjectTracker &Tracker = UObjectPyItem.Value;
119+
#if defined(UEPY_MEMORY_DEBUG)
120+
UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object);
121+
#endif
122+
if (!Tracker.Owner.IsValid(true))
123+
{
124+
#if defined(UEPY_MEMORY_DEBUG)
125+
UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt);
126+
#endif
127+
BrokenList.Add(Object);
128+
Garbaged++;
129+
}
130+
else
131+
{
132+
#if defined(UEPY_MEMORY_DEBUG)
133+
UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName());
134+
#endif
135+
}
136+
}
137+
138+
for (UObject *Object : BrokenList)
139+
{
140+
FPythonUOjectTracker &Tracker = UObjectPyMapping[Object];
141+
if (!Tracker.bPythonOwned)
142+
Py_DECREF((PyObject *)Tracker.PyUObject);
143+
UnregisterPyUObject(Object);
144+
}
145+
146+
return Garbaged;
147+
148+
}
149+
150+
151+
int32 FUnrealEnginePythonHouseKeeper::DelegatesGC()
152+
{
153+
int32 Garbaged = 0;
154+
#if defined(UEPY_MEMORY_DEBUG)
155+
UE_LOG(LogPython, Display, TEXT("Garbage collecting %d UObject delegates"), PyDelegatesTracker.Num());
156+
#endif
157+
for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
158+
{
159+
FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
160+
if (!Tracker.Owner.IsValid(true))
161+
{
162+
Tracker.Delegate->RemoveFromRoot();
163+
PyDelegatesTracker.RemoveAt(i);
164+
Garbaged++;
165+
}
166+
167+
}
168+
169+
#if defined(UEPY_MEMORY_DEBUG)
170+
UE_LOG(LogPython, Display, TEXT("Garbage collecting %d Slate delegates"), PySlateDelegatesTracker.Num());
171+
#endif
172+
173+
for (int32 i = PySlateDelegatesTracker.Num() - 1; i >= 0; --i)
174+
{
175+
FPythonSWidgetDelegateTracker &Tracker = PySlateDelegatesTracker[i];
176+
if (!Tracker.Owner.IsValid())
177+
{
178+
PySlateDelegatesTracker.RemoveAt(i);
179+
Garbaged++;
180+
}
181+
182+
}
183+
return Garbaged;
184+
}
185+
186+
UPythonDelegate *FUnrealEnginePythonHouseKeeper::FindDelegate(UObject *Owner, PyObject *PyCallable)
187+
{
188+
for (int32 i = PyDelegatesTracker.Num() - 1; i >= 0; --i)
189+
{
190+
FPythonDelegateTracker &Tracker = PyDelegatesTracker[i];
191+
if (Tracker.Owner.Get() == Owner && Tracker.Delegate->UsesPyCallable(PyCallable))
192+
return Tracker.Delegate;
193+
}
194+
return nullptr;
195+
}
196+
197+
UPythonDelegate *FUnrealEnginePythonHouseKeeper::NewDelegate(UObject *Owner, PyObject *PyCallable, UFunction *Signature)
198+
{
199+
UPythonDelegate *Delegate = NewObject<UPythonDelegate>();
200+
201+
Delegate->AddToRoot();
202+
Delegate->SetPyCallable(PyCallable);
203+
Delegate->SetSignature(Signature);
204+
205+
FPythonDelegateTracker Tracker(Delegate, Owner);
206+
PyDelegatesTracker.Add(Tracker);
207+
208+
return Delegate;
209+
}
210+
211+
TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewSlateDelegate(TSharedRef<SWidget> Owner, PyObject *PyCallable)
212+
{
213+
TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
214+
Delegate->SetPyCallable(PyCallable);
215+
216+
FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
217+
PySlateDelegatesTracker.Add(Tracker);
218+
219+
return Delegate;
220+
}
221+
222+
TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewDeferredSlateDelegate(PyObject *PyCallable)
223+
{
224+
TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
225+
Delegate->SetPyCallable(PyCallable);
226+
227+
return Delegate;
228+
}
229+
230+
TSharedRef<FPythonSmartDelegate> FUnrealEnginePythonHouseKeeper::NewPythonSmartDelegate(PyObject *PyCallable)
231+
{
232+
TSharedRef<FPythonSmartDelegate> Delegate = MakeShareable(new FPythonSmartDelegate());
233+
Delegate->SetPyCallable(PyCallable);
234+
235+
PyStaticSmartDelegatesTracker.Add(Delegate);
236+
237+
return Delegate;
238+
}
239+
240+
void FUnrealEnginePythonHouseKeeper::TrackDeferredSlateDelegate(TSharedRef<FPythonSlateDelegate> Delegate, TSharedRef<SWidget> Owner)
241+
{
242+
FPythonSWidgetDelegateTracker Tracker(Delegate, Owner);
243+
PySlateDelegatesTracker.Add(Tracker);
244+
}
245+
246+
TSharedRef<FPythonSlateDelegate> FUnrealEnginePythonHouseKeeper::NewStaticSlateDelegate(PyObject *PyCallable)
247+
{
248+
TSharedRef<FPythonSlateDelegate> Delegate = MakeShareable(new FPythonSlateDelegate());
249+
Delegate->SetPyCallable(PyCallable);
250+
251+
PyStaticSlateDelegatesTracker.Add(Delegate);
252+
253+
return Delegate;
254+
}
255+

0 commit comments

Comments
 (0)