1- use super :: { Context , PyConfig , VirtualMachine , setting:: Settings , thread} ;
1+ use super :: { Context , PyConfig , PyGlobalState , VirtualMachine , setting:: Settings , thread} ;
22use crate :: {
33 PyResult , builtins, common:: rc:: PyRc , getpath, stdlib:: atexit, vm:: PyBaseExceptionRef ,
44} ;
@@ -16,10 +16,9 @@ type InitFunc = Box<dyn FnOnce(&mut VirtualMachine)>;
1616/// ```
1717/// use rustpython_vm::Interpreter;
1818///
19- /// let interp = Interpreter::builder()
20- /// .settings(Default::default())
21- /// .add_modules(rustpython_stdlib::stdlib_module_defs())
22- /// .build();
19+ /// let builder = Interpreter::builder(Default::default());
20+ /// // In practice, add stdlib: builder.add_native_modules(&stdlib_module_defs(&builder.ctx))
21+ /// let interp = builder.build();
2322/// ```
2423pub struct InterpreterBuilder {
2524 settings : Settings ,
@@ -35,37 +34,111 @@ fn initialize_main_vm<F>(
3534 module_defs : Vec < & ' static builtins:: PyModuleDef > ,
3635 init_hooks : Vec < InitFunc > ,
3736 init : F ,
38- ) -> VirtualMachine
37+ ) -> ( VirtualMachine , PyRc < PyGlobalState > )
3938where
4039 F : FnOnce ( & mut VirtualMachine ) ,
4140{
41+ use crate :: codecs:: CodecsRegistry ;
42+ use crate :: common:: hash:: HashSecret ;
43+ use crate :: common:: lock:: PyMutex ;
44+ use crate :: warn:: WarningsState ;
45+ use crossbeam_utils:: atomic:: AtomicCell ;
46+ use std:: sync:: atomic:: AtomicBool ;
4247 let paths = getpath:: init_path_config ( & settings) ;
4348 let config = PyConfig :: new ( settings, paths) ;
4449
4550 crate :: types:: TypeZoo :: extend ( & ctx) ;
4651 crate :: exceptions:: ExceptionZoo :: extend ( & ctx) ;
4752
48- let mut vm = VirtualMachine :: new ( config, ctx) ;
53+ // Build module_defs map from builtin modules + additional modules
54+ let mut all_module_defs: std:: collections:: BTreeMap <
55+ & ' static str ,
56+ & ' static builtins:: PyModuleDef ,
57+ > = crate :: stdlib:: builtin_module_defs ( & ctx)
58+ . into_iter ( )
59+ . map ( |def| ( def. name . as_str ( ) , def) )
60+ . collect ( ) ;
4961
50- // Register module definitions
62+ // Add additional module definitions
5163 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) ;
64+ all_module_defs. insert ( def. name . as_str ( ) , def) ;
5665 }
5766
58- // Execute initialization hooks
67+ // Register sysconfigdata under platform-specific name as well
68+ if let Some ( & sysconfigdata_def) = all_module_defs. get ( "_sysconfigdata" ) {
69+ let sysconfigdata_name = crate :: stdlib:: sys:: sysconfigdata_name ( ) ;
70+ // Leak the string to get a 'static lifetime for the key
71+ let leaked_name: & ' static str = Box :: leak ( sysconfigdata_name. into_boxed_str ( ) ) ;
72+ all_module_defs. insert ( leaked_name, sysconfigdata_def) ;
73+ }
74+
75+ // Create hash secret
76+ let seed = match config. settings . hash_seed {
77+ Some ( seed) => seed,
78+ None => super :: process_hash_secret_seed ( ) ,
79+ } ;
80+ let hash_secret = HashSecret :: new ( seed) ;
81+
82+ // Create codec registry and warnings state
83+ let codec_registry = CodecsRegistry :: new ( & ctx) ;
84+ let warnings = WarningsState :: init_state ( & ctx) ;
85+
86+ // Create int_max_str_digits
87+ let int_max_str_digits = AtomicCell :: new ( match config. settings . int_max_str_digits {
88+ -1 => 4300 ,
89+ other => other,
90+ } as usize ) ;
91+
92+ // Initialize frozen modules
93+ let frozen = super :: core_frozen_inits ( ) . collect ( ) ;
94+
95+ // Create PyGlobalState
96+ let global_state = PyRc :: new ( PyGlobalState {
97+ config,
98+ module_defs : all_module_defs,
99+ frozen,
100+ stacksize : AtomicCell :: new ( 0 ) ,
101+ thread_count : AtomicCell :: new ( 0 ) ,
102+ hash_secret,
103+ atexit_funcs : PyMutex :: default ( ) ,
104+ codec_registry,
105+ finalizing : AtomicBool :: new ( false ) ,
106+ warnings,
107+ override_frozen_modules : AtomicCell :: new ( 0 ) ,
108+ before_forkers : PyMutex :: default ( ) ,
109+ after_forkers_child : PyMutex :: default ( ) ,
110+ after_forkers_parent : PyMutex :: default ( ) ,
111+ int_max_str_digits,
112+ switch_interval : AtomicCell :: new ( 0.005 ) ,
113+ global_trace_func : PyMutex :: default ( ) ,
114+ global_profile_func : PyMutex :: default ( ) ,
115+ #[ cfg( feature = "threading" ) ]
116+ main_thread_ident : AtomicCell :: new ( 0 ) ,
117+ #[ cfg( feature = "threading" ) ]
118+ thread_frames : parking_lot:: Mutex :: new ( std:: collections:: HashMap :: new ( ) ) ,
119+ #[ cfg( feature = "threading" ) ]
120+ thread_handles : parking_lot:: Mutex :: new ( Vec :: new ( ) ) ,
121+ #[ cfg( feature = "threading" ) ]
122+ shutdown_handles : parking_lot:: Mutex :: new ( Vec :: new ( ) ) ,
123+ } ) ;
124+
125+ // Create VM with the global state
126+ // Note: Don't clone here - init_hooks need exclusive access to mutate state
127+ let mut vm = VirtualMachine :: new ( ctx, global_state) ;
128+
129+ // Execute initialization hooks (can mutate vm.state)
59130 for hook in init_hooks {
60131 hook ( & mut vm) ;
61132 }
62133
63- // Call custom init function
134+ // Call custom init function (can mutate vm.state)
64135 init ( & mut vm) ;
65136
66137 vm. initialize ( ) ;
67138
68- vm
139+ // Clone global_state for Interpreter after all initialization is done
140+ let global_state = vm. state . clone ( ) ;
141+ ( vm, global_state)
69142}
70143
71144impl InterpreterBuilder {
@@ -91,17 +164,13 @@ impl InterpreterBuilder {
91164 ///
92165 /// # Example
93166 /// ```
94- /// use rustpython_vm::Interpreter;
167+ /// use rustpython_vm::{ Interpreter, builtins::PyModuleDef} ;
95168 ///
96- /// let interp = Interpreter::builder()
97- /// .init_hook(|vm| {
98- /// let def = mymodule::module_def(&vm.ctx);
99- /// rustpython_vm::common::rc::PyRc::get_mut(&mut vm.state)
100- /// .unwrap()
101- /// .module_defs
102- /// .insert(def.name.as_str(), def);
103- /// })
104- /// .build();
169+ /// let builder = Interpreter::builder(Default::default());
170+ /// // Note: In practice, use module_def from your #[pymodule]
171+ /// // let def = mymodule::module_def(&builder.ctx);
172+ /// // let interp = builder.add_native_module(def).build();
173+ /// let interp = builder.build();
105174 /// ```
106175 pub fn add_native_module ( self , def : & ' static builtins:: PyModuleDef ) -> Self {
107176 self . add_native_modules ( & [ def] )
@@ -113,9 +182,11 @@ impl InterpreterBuilder {
113182 /// ```
114183 /// use rustpython_vm::Interpreter;
115184 ///
116- /// let builder = Interpreter::builder();
117- /// let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
118- /// let interp = builder.add_native_modules(&defs).build();
185+ /// let builder = Interpreter::builder(Default::default());
186+ /// // In practice, use module_defs from rustpython_stdlib:
187+ /// // let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
188+ /// // let interp = builder.add_native_modules(&defs).build();
189+ /// let interp = builder.build();
119190 /// ```
120191 pub fn add_native_modules ( mut self , defs : & [ & ' static builtins:: PyModuleDef ] ) -> Self {
121192 self . module_defs . extend_from_slice ( defs) ;
@@ -132,7 +203,7 @@ impl InterpreterBuilder {
132203 /// ```
133204 /// use rustpython_vm::Interpreter;
134205 ///
135- /// let interp = Interpreter::builder()
206+ /// let interp = Interpreter::builder(Default::default() )
136207 /// .init_hook(|vm| {
137208 /// // Custom initialization
138209 /// })
@@ -155,8 +226,8 @@ impl InterpreterBuilder {
155226 /// ```
156227 /// use rustpython_vm::Interpreter;
157228 ///
158- /// let interp = Interpreter::builder()
159- /// .with_frozen(rustpython_pylib::FROZEN_STDLIB)
229+ /// let interp = Interpreter::builder(Default::default() )
230+ /// // In practice: .with_frozen(rustpython_pylib::FROZEN_STDLIB)
160231 /// .build();
161232 /// ```
162233 pub fn with_frozen < I > ( self , frozen : I ) -> Self
@@ -172,14 +243,14 @@ impl InterpreterBuilder {
172243 ///
173244 /// This consumes the configuration and returns a fully initialized Interpreter.
174245 pub fn build ( self ) -> Interpreter {
175- let vm = initialize_main_vm (
246+ let ( vm , global_state ) = initialize_main_vm (
176247 self . settings ,
177248 self . ctx ,
178249 self . module_defs ,
179250 self . init_hooks ,
180251 |_| { } , // No additional init needed
181252 ) ;
182- Interpreter { vm }
253+ Interpreter { global_state , vm }
183254 }
184255
185256 /// Alias for `build()` for compatibility with the `interpreter()` pattern.
@@ -213,6 +284,7 @@ impl Default for InterpreterBuilder {
213284/// });
214285/// ```
215286pub struct Interpreter {
287+ pub global_state : PyRc < PyGlobalState > ,
216288 vm : VirtualMachine ,
217289}
218290
@@ -223,9 +295,9 @@ impl Interpreter {
223295 /// ```
224296 /// use rustpython_vm::Interpreter;
225297 ///
226- /// let interp = Interpreter::builder(Default::default())
227- /// .add_native_modules(rustpython_stdlib:: stdlib_module_defs())
228- /// .build();
298+ /// let builder = Interpreter::builder(Default::default());
299+ /// // In practice, add stdlib: builder .add_native_modules(& stdlib_module_defs(&builder.ctx ))
300+ /// let interp = builder .build();
229301 /// ```
230302 pub fn builder ( settings : Settings ) -> InterpreterBuilder {
231303 InterpreterBuilder :: new ( ) . settings ( settings)
@@ -241,27 +313,19 @@ impl Interpreter {
241313
242314 /// Create with initialize function taking mutable vm reference.
243315 ///
244- /// Note: This is a legacy API. To add stdlib, use `Interpreter::builder()` instead:
245- /// ```
246- /// use rustpython_vm::Interpreter;
247- /// let builder = Interpreter::builder(Default::default());
248- /// let defs = rustpython_stdlib::stdlib_module_defs(&builder.ctx);
249- /// builder.add_native_modules(&defs).build().enter(|vm| {
250- /// vm.run_code_string(vm.new_scope_with_builtins(), "print(1)", "<...>".to_owned());
251- /// });
252- /// ```
316+ /// Note: This is a legacy API. To add stdlib, use `Interpreter::builder()` instead.
253317 pub fn with_init < F > ( settings : Settings , init : F ) -> Self
254318 where
255319 F : FnOnce ( & mut VirtualMachine ) ,
256320 {
257- let vm = initialize_main_vm (
321+ let ( vm , global_state ) = initialize_main_vm (
258322 settings,
259323 Context :: genesis ( ) . clone ( ) ,
260324 Vec :: new ( ) , // No module_defs
261325 Vec :: new ( ) , // No init_hooks
262326 init,
263327 ) ;
264- Self { vm }
328+ Self { global_state , vm }
265329 }
266330
267331 /// Run a function with the main virtual machine and return a PyResult of the result.
0 commit comments