Skip to main content

ri/
py_runtime.rs

1// Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//
3// This file is part of Ri.
4// The Ri project belongs to the Dunimd Team.
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10//     http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Global Tokio runtime shared by language bindings and sync-async bridges.
19//!
20//! Python extension modules are loaded into whatever interpreter thread the
21//! host application happens to be on; there is no guarantee that a Tokio
22//! reactor is running (and `Handle::current()` panics when there is none).
23//! The same holds for synchronous constructors and `Drop` implementations
24//! in core code that need to drive async Ri APIs. This module provides a
25//! lazily-initialized, process-wide multi-thread runtime for those cases.
26
27use std::sync::OnceLock;
28use tokio::runtime::Runtime;
29
30static PY_RUNTIME: OnceLock<Runtime> = OnceLock::new();
31
32/// Returns the process-wide Tokio runtime used by PyO3 bindings.
33///
34/// The runtime is created on first use and shared for the lifetime of the
35/// process. Runtime creation failure is extremely unlikely (it only happens
36/// when the OS refuses to spawn worker threads); in that case we panic since
37/// there is no meaningful way to continue.
38pub fn py_runtime() -> &'static Runtime {
39    PY_RUNTIME.get_or_init(|| {
40        Runtime::new().expect("Ri: failed to create global pyo3 tokio runtime")
41    })
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn py_runtime_is_shared() {
50        let a = py_runtime() as *const Runtime;
51        let b = py_runtime() as *const Runtime;
52        assert_eq!(a, b);
53    }
54
55    #[test]
56    fn py_runtime_can_block_on() {
57        let value = py_runtime().block_on(async { 41 + 1 });
58        assert_eq!(value, 42);
59    }
60}