@@ -11,10 +11,6 @@ import 'gen.dart';
1111export 'gen.dart' ;
1212
1313CPython ? _cpython;
14- // Keep a single interpreter per process; repeated init/finalize of CPython 3.12
15- // from an embedder is fragile and was crashing on second launch.
16- bool _pythonInitialized = false ;
17- Pointer <PyThreadState >? _mainThreadState;
1814
1915void _pyLog (String msg) {
2016 debugPrint ("[PY] ${DateTime .now ().toIso8601String ()} $msg " );
@@ -60,28 +56,21 @@ Future<String> runPythonProgramInIsolate(List<Object> arguments) async {
6056 _pyLog ("script provided: ${script .isNotEmpty } length=${script .length }" );
6157
6258 final cpython = getCPython (dynamicLibPath);
63- if (! _pythonInitialized) {
59+ final alreadyInit = cpython.Py_IsInitialized () != 0 ;
60+ _pyLog ("Py_IsInitialized: $alreadyInit " );
61+ if (! alreadyInit) {
6462 _pyLog ("calling Py_Initialize()" );
6563 cpython.Py_Initialize ();
66- // Release the GIL from the init thread so other threads can reacquire it.
67- _mainThreadState = cpython.PyEval_SaveThread ();
68- _pythonInitialized = true ;
69- _pyLog (
70- "after Py_Initialize(), saved thread state: ${_mainThreadState ?.address .toRadixString (16 )}" );
64+ _pyLog ("after Py_Initialize()" );
7165 } else {
7266 _pyLog ("Python already initialized; reusing interpreter" );
7367 }
7468
7569 var result = "" ;
7670
77- // Reacquire the GIL using the saved main thread state for this process.
78- final mainState = _mainThreadState;
79- if (mainState == null ) {
80- throw StateError ("Python main thread state is null after initialization" );
81- }
82-
83- _pyLog ("restoring thread state ${mainState .address .toRadixString (16 )}" );
84- cpython.PyEval_RestoreThread (mainState);
71+ // Ensure the calling thread owns the GIL; this is safe across isolates.
72+ final gilState = cpython.PyGILState_Ensure ();
73+ _pyLog ("PyGILState_Ensure -> $gilState " );
8574
8675 try {
8776 if (script != "" ) {
@@ -98,20 +87,19 @@ Future<String> runPythonProgramInIsolate(List<Object> arguments) async {
9887 // run program
9988 final moduleNamePtr = programModuleName.toNativeUtf8 ();
10089 _pyLog ("calling PyImport_ImportModule for $programModuleName " );
101- var modulePtr =
102- cpython.PyImport_ImportModule (moduleNamePtr.cast <Char >());
90+ var modulePtr = cpython.PyImport_ImportModule (moduleNamePtr.cast <Char >());
10391 if (modulePtr == nullptr) {
10492 result = getPythonError (cpython);
10593 } else {
106- _pyLog ("PyImport_ImportModule returned ${modulePtr .address .toRadixString (16 )}" );
94+ _pyLog (
95+ "PyImport_ImportModule returned ${modulePtr .address .toRadixString (16 )}" );
10796 }
10897 malloc.free (moduleNamePtr);
10998 }
11099 } finally {
111100 // Drop the GIL again so subsequent runs/threads can re-acquire it cleanly.
112- _mainThreadState = cpython.PyEval_SaveThread ();
113- _pyLog (
114- "saved thread state after run: ${_mainThreadState ?.address .toRadixString (16 )}" );
101+ _pyLog ("PyGILState_Release($gilState )" );
102+ cpython.PyGILState_Release (gilState);
115103 }
116104
117105 // cpython.Py_Finalize();
0 commit comments