From bf272861e6ad94eb0b95fd997de0f1814f2a75c6 Mon Sep 17 00:00:00 2001 From: sunxilin Date: Tue, 3 Nov 2026 17:54:30 +0800 Subject: [PATCH 1/3] fix: race condition in python binding --- .../ten_runtime/global_thread_manager.py | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py b/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py index 1e68ed874c..e80d2ebc5c 100644 --- a/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py +++ b/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py @@ -18,24 +18,24 @@ class GlobalThreadManager: _instance: "GlobalThreadManager | None" = None _lock: threading.Lock = threading.Lock() + _ref_count: int + _main_thread: threading.Thread | None + _main_loop: asyncio.AbstractEventLoop | None + _stop_event: asyncio.Event + _loop_ready_event: threading.Event + def __new__(cls): - if cls._instance is None: - with cls._lock: - if cls._instance is None: - cls._instance = super().__new__(cls) - cls._instance._initialized = False - return cls._instance - - def __init__(self): - if self._initialized: - return - - self._ref_count: int = 0 - self._main_thread: threading.Thread | None = None - self._main_loop: asyncio.AbstractEventLoop | None = None - self._stop_event: asyncio.Event = asyncio.Event() - self._loop_ready_event: threading.Event = threading.Event() - self._initialized: bool = True + with cls._lock: + if cls._instance is None: + instance = super().__new__(cls) + instance._ref_count = 0 + instance._main_thread = None + instance._main_loop = None + instance._stop_event = asyncio.Event() + instance._loop_ready_event = threading.Event() + # Publish only after initialization, while still holding the lock. + cls._instance = instance + return cls._instance def reset(self): with self._lock: @@ -44,7 +44,6 @@ def reset(self): self._main_loop = None self._stop_event = asyncio.Event() self._loop_ready_event = threading.Event() - self._initialized = True def get_or_start_thread( self, ten_env: "TenEnv" From d9e21ef6ebe59f796ee8fae205dfe192bc3f79b0 Mon Sep 17 00:00:00 2001 From: sunxilin Date: Tue, 3 Nov 2026 18:23:05 +0800 Subject: [PATCH 2/3] fix: refine workflow --- .github/workflows/mac_arm64.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mac_arm64.yml b/.github/workflows/mac_arm64.yml index c5a8fecd63..38dcbcf946 100644 --- a/.github/workflows/mac_arm64.yml +++ b/.github/workflows/mac_arm64.yml @@ -33,6 +33,7 @@ jobs: if: ${{ needs.call-check-pr-status.outputs.should_continue == 'true' }} runs-on: macos-latest strategy: + fail-fast: false matrix: build_type: [debug, release] steps: From d9311f1bd4000dfaff006a87a4c6319a510c7f1c Mon Sep 17 00:00:00 2001 From: sunxilin Date: Tue, 3 Nov 2026 18:40:50 +0800 Subject: [PATCH 3/3] fix: refine code --- .../ten_runtime/global_thread_manager.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py b/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py index e80d2ebc5c..a46b30b21a 100644 --- a/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py +++ b/core/src/ten_runtime/binding/python/interface/ten_runtime/global_thread_manager.py @@ -25,17 +25,18 @@ class GlobalThreadManager: _loop_ready_event: threading.Event def __new__(cls): - with cls._lock: - if cls._instance is None: - instance = super().__new__(cls) - instance._ref_count = 0 - instance._main_thread = None - instance._main_loop = None - instance._stop_event = asyncio.Event() - instance._loop_ready_event = threading.Event() - # Publish only after initialization, while still holding the lock. - cls._instance = instance - return cls._instance + if cls._instance is None: + with cls._lock: + if cls._instance is None: + instance = super().__new__(cls) + instance._ref_count = 0 + instance._main_thread = None + instance._main_loop = None + instance._stop_event = asyncio.Event() + instance._loop_ready_event = threading.Event() + # Publish only after initialization, while holding the lock. + cls._instance = instance + return cls._instance def reset(self): with self._lock: