@@ -25,13 +25,9 @@ use pecos_engines::{
2525use pecos_qis_ffi_types:: { Operation , OperationCollector as OperationList , QuantumOp } ;
2626use pecos_rng:: PecosRng ;
2727use std:: collections:: BTreeMap ;
28- use std:: thread:: JoinHandle ;
29-
30- // These imports are only used by PersistentDynamicWorker (Linux only)
31- #[ cfg( not( target_os = "macos" ) ) ]
3228use std:: sync:: Mutex ;
33- #[ cfg( not( target_os = "macos" ) ) ]
3429use std:: sync:: mpsc:: { self , Receiver , Sender } ;
30+ use std:: thread:: JoinHandle ;
3531
3632/// Result from worker thread - returns both the operations and the interface
3733type WorkerResult = Result < ( OperationList , BoxedInterface ) , String > ;
@@ -49,15 +45,11 @@ struct DynamicExecutionState {
4945 execution_complete : bool ,
5046 /// Sync handle for main thread FFI calls
5147 /// Uses the same library instance (singleton) as the worker thread,
52- /// ensuring TLS consistency on macOS
48+ /// ensuring TLS consistency across platforms
5349 sync_handle : Option < Box < dyn DynamicSyncHandle > > ,
54- /// Worker thread handle (used on macOS where persistent worker causes issues)
55- #[ cfg( target_os = "macos" ) ]
56- worker_handle : Option < JoinHandle < WorkerResult > > ,
5750}
5851
5952/// Work item sent to the persistent dynamic worker thread
60- #[ cfg( not( target_os = "macos" ) ) ]
6153struct DynamicWorkItem {
6254 /// The interface to execute
6355 interface : BoxedInterface ,
@@ -69,7 +61,6 @@ struct DynamicWorkItem {
6961/// and TLS allocation issues that come from spawning a new thread per shot.
7062/// The thread waits for work items via a channel, executes `collect_operations()`,
7163/// and sends results back via another channel.
72- #[ cfg( not( target_os = "macos" ) ) ]
7364struct PersistentDynamicWorker {
7465 /// Channel to send work items to the worker
7566 work_tx : Sender < DynamicWorkItem > ,
@@ -79,7 +70,6 @@ struct PersistentDynamicWorker {
7970 _handle : JoinHandle < ( ) > ,
8071}
8172
82- #[ cfg( not( target_os = "macos" ) ) ]
8373impl PersistentDynamicWorker {
8474 /// Create a new persistent dynamic worker thread
8575 fn new ( ) -> Self {
@@ -202,7 +192,6 @@ pub struct QisEngine {
202192
203193 /// Persistent worker thread for dynamic execution (stays alive across shots)
204194 /// This avoids spawning a new thread per shot, which causes TLS allocation issues.
205- #[ cfg( not( target_os = "macos" ) ) ]
206195 persistent_worker : Option < PersistentDynamicWorker > ,
207196}
208197
@@ -230,7 +219,6 @@ impl QisEngine {
230219 program_bytes : None ,
231220 program_format : None ,
232221 interface_builder : None ,
233- #[ cfg( not( target_os = "macos" ) ) ]
234222 persistent_worker : None ,
235223 }
236224 }
@@ -304,7 +292,6 @@ impl QisEngine {
304292 program_bytes : None ,
305293 program_format : None ,
306294 interface_builder : None ,
307- #[ cfg( not( target_os = "macos" ) ) ]
308295 persistent_worker : None ,
309296 }
310297 }
@@ -474,7 +461,6 @@ impl Clone for QisEngine {
474461 . as_ref ( )
475462 . map ( |b| dyn_clone:: clone_box ( & * * b) ) ,
476463 // Create a new persistent worker for this clone (can't share threads across clones)
477- #[ cfg( not( target_os = "macos" ) ) ]
478464 persistent_worker : None ,
479465 }
480466 }
@@ -484,8 +470,8 @@ impl Clone for QisEngine {
484470impl QisEngine {
485471 /// Start the LLVM program execution in a worker thread
486472 ///
487- /// Uses a persistent worker thread on Linux to avoid glibc TLS allocation issues.
488- /// On macOS, uses per-shot spawning with a sync handle that uses the singleton library .
473+ /// Uses a persistent worker thread to avoid TLS allocation issues from
474+ /// spawning a new thread per shot .
489475 fn start_dynamic_worker ( & mut self ) -> Result < ( ) , PecosError > {
490476 debug ! ( "Starting dynamic execution" ) ;
491477
@@ -516,55 +502,23 @@ impl QisEngine {
516502 PecosError :: Generic ( "No interface available for dynamic execution" . to_string ( ) )
517503 } ) ?;
518504
519- // Platform-specific worker spawning:
520- // - On Linux: Use persistent worker to avoid glibc TLS allocation issues
521- // - On macOS: Use per-shot spawning (persistent worker causes segfaults)
522- #[ cfg( not( target_os = "macos" ) ) ]
523- {
524- // Create persistent worker if it doesn't exist
525- if self . persistent_worker . is_none ( ) {
526- debug ! ( "Creating new persistent dynamic worker thread" ) ;
527- self . persistent_worker = Some ( PersistentDynamicWorker :: new ( ) ) ;
528- }
529-
530- // Send work to persistent worker
531- self . persistent_worker
532- . as_ref ( )
533- . expect ( "persistent worker was just created" )
534- . execute ( interface) ?;
535-
536- // Initialize dynamic state
537- self . dynamic_state = Some ( DynamicExecutionState {
538- sync_handle,
539- execution_complete : false ,
540- } ) ;
505+ // Create persistent worker if it doesn't exist
506+ if self . persistent_worker . is_none ( ) {
507+ debug ! ( "Creating new persistent dynamic worker thread" ) ;
508+ self . persistent_worker = Some ( PersistentDynamicWorker :: new ( ) ) ;
541509 }
542510
543- #[ cfg( target_os = "macos" ) ]
544- {
545- // Spawn worker thread that runs the LLVM program (per-shot)
546- let worker_handle = std:: thread:: spawn ( move || {
547- let mut interface = interface; // Shadow with mutable binding
548- debug ! ( "Worker thread: starting collect_operations" ) ;
549- let result = interface. collect_operations ( ) ;
550- debug ! ( "Worker thread: collect_operations returned" ) ;
551-
552- // Disable dynamic mode before returning
553- let _ = interface. disable_dynamic_mode ( ) ;
554-
555- // Return both the result and the interface
556- result
557- . map ( |collector| ( collector, interface) )
558- . map_err ( |e| e. to_string ( ) )
559- } ) ;
560-
561- // Initialize dynamic state with worker handle
562- self . dynamic_state = Some ( DynamicExecutionState {
563- sync_handle,
564- execution_complete : false ,
565- worker_handle : Some ( worker_handle) ,
566- } ) ;
567- }
511+ // Send work to persistent worker
512+ self . persistent_worker
513+ . as_ref ( )
514+ . expect ( "persistent worker was just created" )
515+ . execute ( interface) ?;
516+
517+ // Initialize dynamic state
518+ self . dynamic_state = Some ( DynamicExecutionState {
519+ sync_handle,
520+ execution_complete : false ,
521+ } ) ;
568522
569523 Ok ( ( ) )
570524 }
@@ -633,38 +587,12 @@ impl QisEngine {
633587 return true ;
634588 }
635589
636- // Platform-specific result checking - get result outside of borrow
637- #[ cfg( not( target_os = "macos" ) ) ]
590+ // Check if persistent worker has a result ready
638591 let result: Option < WorkerResult > = self
639592 . persistent_worker
640593 . as_ref ( )
641594 . and_then ( PersistentDynamicWorker :: try_recv_result) ;
642595
643- #[ cfg( target_os = "macos" ) ]
644- let result: Option < WorkerResult > = {
645- if let Some ( ref mut state) = self . dynamic_state {
646- if let Some ( handle) = state. worker_handle . take ( ) {
647- if handle. is_finished ( ) {
648- if let Ok ( r) = handle. join ( ) {
649- Some ( r)
650- } else {
651- log:: error!( "Worker panicked" ) ;
652- state. execution_complete = true ;
653- return true ;
654- }
655- } else {
656- // Put handle back if not finished
657- state. worker_handle = Some ( handle) ;
658- None
659- }
660- } else {
661- None
662- }
663- } else {
664- None
665- }
666- } ;
667-
668596 // Process result if we got one
669597 if let Some ( result) = result {
670598 match result {
0 commit comments