|
1 | | -use super::{Context, PyConfig, VirtualMachine, setting::Settings, thread}; |
| 1 | +use super::{Context, PyConfig, PyGlobalState, VirtualMachine, setting::Settings, thread}; |
2 | 2 | use crate::{ |
3 | 3 | PyResult, builtins, common::rc::PyRc, getpath, stdlib::atexit, vm::PyBaseExceptionRef, |
4 | 4 | }; |
@@ -35,37 +35,111 @@ fn initialize_main_vm<F>( |
35 | 35 | module_defs: Vec<&'static builtins::PyModuleDef>, |
36 | 36 | init_hooks: Vec<InitFunc>, |
37 | 37 | init: F, |
38 | | -) -> VirtualMachine |
| 38 | +) -> (VirtualMachine, PyRc<PyGlobalState>) |
39 | 39 | where |
40 | 40 | F: FnOnce(&mut VirtualMachine), |
41 | 41 | { |
| 42 | + use crate::codecs::CodecsRegistry; |
| 43 | + use crate::common::hash::HashSecret; |
| 44 | + use crate::common::lock::PyMutex; |
| 45 | + use crate::warn::WarningsState; |
| 46 | + use crossbeam_utils::atomic::AtomicCell; |
| 47 | + use std::sync::atomic::AtomicBool; |
42 | 48 | let paths = getpath::init_path_config(&settings); |
43 | 49 | let config = PyConfig::new(settings, paths); |
44 | 50 |
|
45 | 51 | crate::types::TypeZoo::extend(&ctx); |
46 | 52 | crate::exceptions::ExceptionZoo::extend(&ctx); |
47 | 53 |
|
48 | | - let mut vm = VirtualMachine::new(config, ctx); |
| 54 | + // Build module_defs map from builtin modules + additional modules |
| 55 | + let mut all_module_defs: std::collections::BTreeMap< |
| 56 | + &'static str, |
| 57 | + &'static builtins::PyModuleDef, |
| 58 | + > = crate::stdlib::builtin_module_defs(&ctx) |
| 59 | + .into_iter() |
| 60 | + .map(|def| (def.name.as_str(), def)) |
| 61 | + .collect(); |
49 | 62 |
|
50 | | - // Register module definitions |
| 63 | + // Add additional module definitions |
51 | 64 | for def in module_defs { |
52 | | - PyRc::get_mut(&mut vm.state) |
53 | | - .expect("there should not be multiple threads during initialization") |
54 | | - .module_defs |
55 | | - .insert(def.name.as_str(), def); |
| 65 | + all_module_defs.insert(def.name.as_str(), def); |
56 | 66 | } |
57 | 67 |
|
58 | | - // Execute initialization hooks |
| 68 | + // Register sysconfigdata under platform-specific name as well |
| 69 | + if let Some(&sysconfigdata_def) = all_module_defs.get("_sysconfigdata") { |
| 70 | + let sysconfigdata_name = crate::stdlib::sys::sysconfigdata_name(); |
| 71 | + // Leak the string to get a 'static lifetime for the key |
| 72 | + let leaked_name: &'static str = Box::leak(sysconfigdata_name.into_boxed_str()); |
| 73 | + all_module_defs.insert(leaked_name, sysconfigdata_def); |
| 74 | + } |
| 75 | + |
| 76 | + // Create hash secret |
| 77 | + let seed = match config.settings.hash_seed { |
| 78 | + Some(seed) => seed, |
| 79 | + None => super::process_hash_secret_seed(), |
| 80 | + }; |
| 81 | + let hash_secret = HashSecret::new(seed); |
| 82 | + |
| 83 | + // Create codec registry and warnings state |
| 84 | + let codec_registry = CodecsRegistry::new(&ctx); |
| 85 | + let warnings = WarningsState::init_state(&ctx); |
| 86 | + |
| 87 | + // Create int_max_str_digits |
| 88 | + let int_max_str_digits = AtomicCell::new(match config.settings.int_max_str_digits { |
| 89 | + -1 => 4300, |
| 90 | + other => other, |
| 91 | + } as usize); |
| 92 | + |
| 93 | + // Initialize frozen modules |
| 94 | + let frozen = super::core_frozen_inits().collect(); |
| 95 | + |
| 96 | + // Create PyGlobalState |
| 97 | + let global_state = PyRc::new(PyGlobalState { |
| 98 | + config, |
| 99 | + module_defs: all_module_defs, |
| 100 | + frozen, |
| 101 | + stacksize: AtomicCell::new(0), |
| 102 | + thread_count: AtomicCell::new(0), |
| 103 | + hash_secret, |
| 104 | + atexit_funcs: PyMutex::default(), |
| 105 | + codec_registry, |
| 106 | + finalizing: AtomicBool::new(false), |
| 107 | + warnings, |
| 108 | + override_frozen_modules: AtomicCell::new(0), |
| 109 | + before_forkers: PyMutex::default(), |
| 110 | + after_forkers_child: PyMutex::default(), |
| 111 | + after_forkers_parent: PyMutex::default(), |
| 112 | + int_max_str_digits, |
| 113 | + switch_interval: AtomicCell::new(0.005), |
| 114 | + global_trace_func: PyMutex::default(), |
| 115 | + global_profile_func: PyMutex::default(), |
| 116 | + #[cfg(feature = "threading")] |
| 117 | + main_thread_ident: AtomicCell::new(0), |
| 118 | + #[cfg(feature = "threading")] |
| 119 | + thread_frames: parking_lot::Mutex::new(std::collections::HashMap::new()), |
| 120 | + #[cfg(feature = "threading")] |
| 121 | + thread_handles: parking_lot::Mutex::new(Vec::new()), |
| 122 | + #[cfg(feature = "threading")] |
| 123 | + shutdown_handles: parking_lot::Mutex::new(Vec::new()), |
| 124 | + }); |
| 125 | + |
| 126 | + // Create VM with the global state |
| 127 | + // Note: Don't clone here - init_hooks need exclusive access to mutate state |
| 128 | + let mut vm = VirtualMachine::new(ctx, global_state); |
| 129 | + |
| 130 | + // Execute initialization hooks (can mutate vm.state) |
59 | 131 | for hook in init_hooks { |
60 | 132 | hook(&mut vm); |
61 | 133 | } |
62 | 134 |
|
63 | | - // Call custom init function |
| 135 | + // Call custom init function (can mutate vm.state) |
64 | 136 | init(&mut vm); |
65 | 137 |
|
66 | 138 | vm.initialize(); |
67 | 139 |
|
68 | | - vm |
| 140 | + // Clone global_state for Interpreter after all initialization is done |
| 141 | + let global_state = vm.state.clone(); |
| 142 | + (vm, global_state) |
69 | 143 | } |
70 | 144 |
|
71 | 145 | impl InterpreterBuilder { |
@@ -172,14 +246,14 @@ impl InterpreterBuilder { |
172 | 246 | /// |
173 | 247 | /// This consumes the configuration and returns a fully initialized Interpreter. |
174 | 248 | pub fn build(self) -> Interpreter { |
175 | | - let vm = initialize_main_vm( |
| 249 | + let (vm, global_state) = initialize_main_vm( |
176 | 250 | self.settings, |
177 | 251 | self.ctx, |
178 | 252 | self.module_defs, |
179 | 253 | self.init_hooks, |
180 | 254 | |_| {}, // No additional init needed |
181 | 255 | ); |
182 | | - Interpreter { vm } |
| 256 | + Interpreter { global_state, vm } |
183 | 257 | } |
184 | 258 |
|
185 | 259 | /// Alias for `build()` for compatibility with the `interpreter()` pattern. |
@@ -213,6 +287,7 @@ impl Default for InterpreterBuilder { |
213 | 287 | /// }); |
214 | 288 | /// ``` |
215 | 289 | pub struct Interpreter { |
| 290 | + pub global_state: PyRc<PyGlobalState>, |
216 | 291 | vm: VirtualMachine, |
217 | 292 | } |
218 | 293 |
|
@@ -254,14 +329,14 @@ impl Interpreter { |
254 | 329 | where |
255 | 330 | F: FnOnce(&mut VirtualMachine), |
256 | 331 | { |
257 | | - let vm = initialize_main_vm( |
| 332 | + let (vm, global_state) = initialize_main_vm( |
258 | 333 | settings, |
259 | 334 | Context::genesis().clone(), |
260 | 335 | Vec::new(), // No module_defs |
261 | 336 | Vec::new(), // No init_hooks |
262 | 337 | init, |
263 | 338 | ); |
264 | | - Self { vm } |
| 339 | + Self { global_state, vm } |
265 | 340 | } |
266 | 341 |
|
267 | 342 | /// Run a function with the main virtual machine and return a PyResult of the result. |
|
0 commit comments