Skip to content

Commit 33f33b0

Browse files
author
Roberto De Ioris
committed
first public push for threading support
1 parent da14c45 commit 33f33b0

File tree

12 files changed

+142
-14
lines changed

12 files changed

+142
-14
lines changed

Source/PythonConsole/Private/PythonConsolePrivatePCH.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@
1111
#else
1212
#include <include/Python.h>
1313
#endif
14+

Source/PythonConsole/Private/SPythonLog.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class SPythonConsoleEditableTextBox : public SEditableTextBox
127127
SPythonConsoleInputBox::SPythonConsoleInputBox()
128128
: bIgnoreUIUpdate(false)
129129
{
130+
FScopePythonGIL gil;
130131
PyObject *main_module = PyImport_AddModule("__main__");
131132
main_dict = PyModule_GetDict(main_module);
132133
local_dict = PyDict_New();
@@ -179,8 +180,8 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
179180
bIgnoreUIUpdate = false;
180181

181182
// Here run the python code
182-
//FUnrealEnginePythonModule UnrealEnginePythonModule = FModuleManager::LoadModuleChecked<FUnrealEnginePythonModule>("UnrealEnginePython");
183-
//UnrealEnginePythonModule.PythonGILAcquire();
183+
//
184+
FScopePythonGIL gil;
184185

185186
PyObject *eval_ret = PyRun_String(TCHAR_TO_UTF8(*ExecString), Py_file_input, main_dict, local_dict);
186187

@@ -199,7 +200,6 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
199200

200201
if (!value) {
201202
PyErr_Clear();
202-
//UnrealEnginePythonModule.PythonGILRelease();
203203
OnConsoleCommandExecuted.ExecuteIfBound();
204204
return;
205205
}
@@ -212,7 +212,6 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
212212

213213
if (!msg) {
214214
PyErr_Clear();
215-
//UnrealEnginePythonModule.PythonGILRelease();
216215
OnConsoleCommandExecuted.ExecuteIfBound();
217216
return;
218217
}
@@ -222,15 +221,13 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
222221
// taken from uWSGI ;)
223222
if (!traceback) {
224223
PyErr_Clear();
225-
//UnrealEnginePythonModule.PythonGILRelease();
226224
OnConsoleCommandExecuted.ExecuteIfBound();
227225
return;
228226
}
229227

230228
PyObject *traceback_module = PyImport_ImportModule("traceback");
231229
if (!traceback_module) {
232230
PyErr_Clear();
233-
//UnrealEnginePythonModule.PythonGILRelease();
234231
OnConsoleCommandExecuted.ExecuteIfBound();
235232
return;
236233
}
@@ -242,7 +239,6 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
242239
PyObject *ret = PyObject_CallFunctionObjArgs(format_exception, type, value, traceback, NULL);
243240
if (!ret) {
244241
PyErr_Clear();
245-
//UnrealEnginePythonModule.PythonGILRelease();
246242
OnConsoleCommandExecuted.ExecuteIfBound();
247243
return;
248244
}
@@ -261,7 +257,6 @@ void SPythonConsoleInputBox::OnTextCommitted(const FText& InText, ETextCommit::T
261257
}
262258
PyErr_Clear();
263259
}
264-
//UnrealEnginePythonModule.PythonGILRelease();
265260
}
266261

267262
}

Source/PythonConsole/Private/SPythonLog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "BaseTextLayoutMarshaller.h"
55
#include "TextFilterExpressionEvaluator.h"
66

7+
#include "UnrealEnginePython/Public/UnrealEnginePython.h"
8+
79
class FPythonLogTextLayoutMarshaller;
810
class SSearchBox;
911

Source/PythonConsole/PythonConsole.Build.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public PythonConsole(TargetInfo Target)
3636
"SlateCore",
3737
"EditorStyle",
3838
"TargetPlatform",
39-
"DesktopPlatform",
40-
}
39+
"UnrealEnginePython"
40+
}
4141
);
4242

4343
if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))

Source/UnrealEnginePython/Private/UnrealEnginePython.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ void FUnrealEnginePythonModule::StartupModule()
4949
UE_LOG(LogPython, Log, TEXT("ue_site Python module successfully imported"));
5050
}
5151
else {
52+
// TODO gracefully manage the error
5253
unreal_engine_py_log_error();
5354
}
5455

55-
// TODO investigate python threads support
56-
//PythonGILRelease();
56+
// release the GIL
57+
PythonGILRelease();
5758
}
5859

5960
void FUnrealEnginePythonModule::ShutdownModule()
@@ -62,6 +63,7 @@ void FUnrealEnginePythonModule::ShutdownModule()
6263
// we call this function before unloading the module.
6364

6465
UE_LOG(LogPython, Log, TEXT("Goodbye Python"));
66+
PythonGILAcquire();
6567
Py_Finalize();
6668
}
6769

Source/UnrealEnginePython/Public/PyActor.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ APyActor::APyActor()
1010
PythonTickForceDisabled = false;
1111
PythonDisableAutoBinding = false;
1212

13+
FScopePythonGIL gil;
1314
// pre-generate PyUObject (for performance)
1415
ue_get_python_wrapper(this);
1516
}
@@ -25,6 +26,8 @@ void APyActor::BeginPlay()
2526
if (PythonModule.IsEmpty())
2627
return;
2728

29+
FScopePythonGIL gil;
30+
2831
PyObject *py_actor_module = PyImport_ImportModule(TCHAR_TO_UTF8(*PythonModule));
2932
if (!py_actor_module) {
3033
unreal_engine_py_log_error();
@@ -96,6 +99,8 @@ void APyActor::Tick(float DeltaTime)
9699
if (!py_actor_instance)
97100
return;
98101

102+
FScopePythonGIL gil;
103+
99104
if (!PyObject_HasAttrString(py_actor_instance, "tick"))
100105
return;
101106

@@ -114,6 +119,8 @@ void APyActor::CallPythonActorMethod(FString method_name, FString args)
114119
if (!py_actor_instance)
115120
return;
116121

122+
FScopePythonGIL gil;
123+
117124
PyObject *ret = nullptr;
118125
if (args.IsEmpty()) {
119126
ret = PyObject_CallMethod(py_actor_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -134,6 +141,8 @@ bool APyActor::CallPythonActorMethodBool(FString method_name, FString args)
134141
if (!py_actor_instance)
135142
return false;
136143

144+
FScopePythonGIL gil;
145+
137146
PyObject *ret = nullptr;
138147
if (args.IsEmpty()) {
139148
ret = PyObject_CallMethod(py_actor_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -160,6 +169,8 @@ FString APyActor::CallPythonActorMethodString(FString method_name, FString args)
160169
if (!py_actor_instance)
161170
return FString();
162171

172+
FScopePythonGIL gil;
173+
163174
PyObject *ret = nullptr;
164175
if (args.IsEmpty()) {
165176
ret = PyObject_CallMethod(py_actor_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -190,6 +201,7 @@ FString APyActor::CallPythonActorMethodString(FString method_name, FString args)
190201

191202
APyActor::~APyActor()
192203
{
204+
FScopePythonGIL gil;
193205
#if UEPY_MEMORY_DEBUG
194206
if (py_actor_instance && py_actor_instance->ob_refcnt != 1) {
195207
UE_LOG(LogPython, Error, TEXT("Inconsistent Python AActor wrapper refcnt = %d"), py_actor_instance->ob_refcnt);

Source/UnrealEnginePython/Public/PyCharacter.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ APyCharacter::APyCharacter()
1010
PythonTickForceDisabled = false;
1111
PythonDisableAutoBinding = false;
1212

13+
FScopePythonGIL gil;
1314
// pre-generate PyUObject (for performance)
1415
ue_get_python_wrapper(this);
1516
}
@@ -18,13 +19,17 @@ APyCharacter::APyCharacter()
1819
// Called when the game starts
1920
void APyCharacter::BeginPlay()
2021
{
22+
23+
2124
Super::BeginPlay();
2225

2326
// ...
2427

2528
if (PythonModule.IsEmpty())
2629
return;
2730

31+
FScopePythonGIL gil;
32+
2833
PyObject *py_character_module = PyImport_ImportModule(TCHAR_TO_UTF8(*PythonModule));
2934
if (!py_character_module) {
3035
unreal_engine_py_log_error();
@@ -92,11 +97,15 @@ void APyCharacter::BeginPlay()
9297
// Called every frame
9398
void APyCharacter::Tick(float DeltaTime)
9499
{
100+
101+
95102
Super::Tick(DeltaTime);
96103

97104
if (!py_character_instance)
98105
return;
99106

107+
FScopePythonGIL gil;
108+
100109
// no need to check for method availability, we did it in begin_play
101110

102111
PyObject *ret = PyObject_CallMethod(py_character_instance, "tick", "f", DeltaTime);
@@ -110,9 +119,13 @@ void APyCharacter::Tick(float DeltaTime)
110119

111120
void APyCharacter::CallPyCharacterMethod(FString method_name, FString args)
112121
{
122+
123+
113124
if (!py_character_instance)
114125
return;
115126

127+
FScopePythonGIL gil;
128+
116129
PyObject *ret = nullptr;
117130
if (args.IsEmpty()) {
118131
ret = PyObject_CallMethod(py_character_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -130,9 +143,13 @@ void APyCharacter::CallPyCharacterMethod(FString method_name, FString args)
130143

131144
void APyCharacter::SetPythonAttrObject(FString attr, UObject *object)
132145
{
146+
147+
133148
if (!py_character_instance)
134149
return;
135150

151+
FScopePythonGIL gil;
152+
136153
ue_PyUObject *py_obj = ue_get_python_wrapper(object);
137154
if (!py_obj) {
138155
PyErr_Format(PyExc_Exception, "PyUObject is in invalid state");
@@ -147,58 +164,82 @@ void APyCharacter::SetPythonAttrObject(FString attr, UObject *object)
147164

148165
void APyCharacter::SetPythonAttrString(FString attr, FString s)
149166
{
167+
168+
150169
if (!py_character_instance)
151170
return;
152171

172+
FScopePythonGIL gil;
173+
153174
if (PyObject_SetAttrString(py_character_instance, TCHAR_TO_UTF8(*attr), PyUnicode_FromString(TCHAR_TO_UTF8(*s))) < 0) {
154175
UE_LOG(LogPython, Error, TEXT("Unable to set attribute %s"), *attr);
155176
}
156177
}
157178

158179
void APyCharacter::SetPythonAttrFloat(FString attr, float f)
159180
{
181+
182+
160183
if (!py_character_instance)
161184
return;
162185

186+
FScopePythonGIL gil;
187+
163188
if (PyObject_SetAttrString(py_character_instance, TCHAR_TO_UTF8(*attr), PyFloat_FromDouble(f)) < 0) {
164189
UE_LOG(LogPython, Error, TEXT("Unable to set attribute %s"), *attr);
165190
}
166191
}
167192

168193
void APyCharacter::SetPythonAttrInt(FString attr, int n)
169194
{
195+
196+
170197
if (!py_character_instance)
171198
return;
172199

200+
FScopePythonGIL gil;
201+
173202
if (PyObject_SetAttrString(py_character_instance, TCHAR_TO_UTF8(*attr), PyLong_FromLong(n)) < 0) {
174203
UE_LOG(LogPython, Error, TEXT("Unable to set attribute %s"), *attr);
175204
}
176205
}
177206

178207
void APyCharacter::SetPythonAttrVector(FString attr, FVector vec)
179208
{
209+
210+
180211
if (!py_character_instance)
181212
return;
182213

214+
FScopePythonGIL gil;
215+
183216
if (PyObject_SetAttrString(py_character_instance, TCHAR_TO_UTF8(*attr), py_ue_new_fvector(vec)) < 0) {
184217
UE_LOG(LogPython, Error, TEXT("Unable to set attribute %s"), *attr);
185218
}
186219
}
187220

188221
void APyCharacter::SetPythonAttrRotator(FString attr, FRotator rot)
189222
{
223+
224+
190225
if (!py_character_instance)
191226
return;
192227

228+
FScopePythonGIL gil;
229+
193230
if (PyObject_SetAttrString(py_character_instance, TCHAR_TO_UTF8(*attr), py_ue_new_frotator(rot)) < 0) {
194231
UE_LOG(LogPython, Error, TEXT("Unable to set attribute %s"), *attr);
195232
}
196233
}
197234

198235
void APyCharacter::SetPythonAttrBool(FString attr, bool b)
199236
{
237+
238+
200239
if (!py_character_instance)
201240
return;
241+
242+
FScopePythonGIL gil;
202243

203244
PyObject *py_bool = Py_False;
204245
if (b) {
@@ -212,9 +253,13 @@ void APyCharacter::SetPythonAttrBool(FString attr, bool b)
212253

213254
bool APyCharacter::CallPyCharacterMethodBool(FString method_name, FString args)
214255
{
256+
257+
215258
if (!py_character_instance)
216259
return false;
217260

261+
FScopePythonGIL gil;
262+
218263
PyObject *ret = nullptr;
219264
if (args.IsEmpty()) {
220265
ret = PyObject_CallMethod(py_character_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -240,9 +285,13 @@ bool APyCharacter::CallPyCharacterMethodBool(FString method_name, FString args)
240285

241286
float APyCharacter::CallPyCharacterMethodFloat(FString method_name, FString args)
242287
{
288+
289+
243290
if (!py_character_instance)
244291
return false;
245292

293+
FScopePythonGIL gil;
294+
246295
PyObject *ret = nullptr;
247296
if (args.IsEmpty()) {
248297
ret = PyObject_CallMethod(py_character_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -271,9 +320,13 @@ float APyCharacter::CallPyCharacterMethodFloat(FString method_name, FString args
271320

272321
FString APyCharacter::CallPyCharacterMethodString(FString method_name, FString args)
273322
{
323+
324+
274325
if (!py_character_instance)
275326
return FString();
276327

328+
FScopePythonGIL gil;
329+
277330
PyObject *ret = nullptr;
278331
if (args.IsEmpty()) {
279332
ret = PyObject_CallMethod(py_character_instance, TCHAR_TO_UTF8(*method_name), NULL);
@@ -312,6 +365,7 @@ void APyCharacter::SetupPlayerInputComponent(class UInputComponent* input)
312365

313366
APyCharacter::~APyCharacter()
314367
{
368+
FScopePythonGIL gil;
315369
#if UEPY_MEMORY_DEBUG
316370
if (py_character_instance && py_character_instance->ob_refcnt != 1) {
317371
UE_LOG(LogPython, Error, TEXT("Inconsistent Python ACharacter wrapper refcnt = %d"), py_character_instance->ob_refcnt);

0 commit comments

Comments
 (0)