@@ -617,24 +617,37 @@ pub(crate) mod _thread {
617617 impl Local {
618618 fn l_dict ( & self , vm : & VirtualMachine ) -> PyDictRef {
619619 let thread_id = std:: thread:: current ( ) . id ( ) ;
620- let mut data = self . inner . data . lock ( ) ;
621620
622- if let Some ( dict) = data. get ( & thread_id) {
623- return dict. clone ( ) ;
621+ // Fast path: check if dict exists under lock
622+ if let Some ( dict) = self . inner . data . lock ( ) . get ( & thread_id) . cloned ( ) {
623+ return dict;
624624 }
625625
626- // Create new dict for this thread
627- let dict = vm. ctx . new_dict ( ) ;
628- data. insert ( thread_id, dict. clone ( ) ) ;
626+ // Slow path: allocate dict outside lock to reduce lock hold time
627+ let new_dict = vm. ctx . new_dict ( ) ;
629628
630- // Register cleanup guard for this thread
631- let guard = LocalGuard {
632- local : std:: sync:: Arc :: downgrade ( & self . inner ) ,
633- thread_id,
629+ // Insert with double-check to handle races
630+ let mut data = self . inner . data . lock ( ) ;
631+ use std:: collections:: hash_map:: Entry ;
632+ let ( dict, need_guard) = match data. entry ( thread_id) {
633+ Entry :: Occupied ( e) => ( e. get ( ) . clone ( ) , false ) ,
634+ Entry :: Vacant ( e) => {
635+ e. insert ( new_dict. clone ( ) ) ;
636+ ( new_dict, true )
637+ }
634638 } ;
635- LOCAL_GUARDS . with ( |guards| {
636- guards. borrow_mut ( ) . push ( guard) ;
637- } ) ;
639+ drop ( data) ; // Release lock before TLS access
640+
641+ // Register cleanup guard only if we inserted a new entry
642+ if need_guard {
643+ let guard = LocalGuard {
644+ local : std:: sync:: Arc :: downgrade ( & self . inner ) ,
645+ thread_id,
646+ } ;
647+ LOCAL_GUARDS . with ( |guards| {
648+ guards. borrow_mut ( ) . push ( guard) ;
649+ } ) ;
650+ }
638651
639652 dict
640653 }
@@ -760,7 +773,14 @@ pub(crate) mod _thread {
760773
761774 #[ pymethod]
762775 fn join ( & self , timeout : OptionalArg < Option < f64 > > , vm : & VirtualMachine ) -> PyResult < ( ) > {
763- let _timeout_val = timeout. flatten ( ) . unwrap_or ( -1.0 ) ;
776+ // Validate timeout: None or negative means wait forever, positive is not supported
777+ if let OptionalArg :: Present ( Some ( t) ) = timeout
778+ && t > 0.0
779+ {
780+ return Err ( vm. new_value_error (
781+ "timeout parameter is not supported for _ThreadHandle.join()" . to_owned ( ) ,
782+ ) ) ;
783+ }
764784
765785 // Check for self-join and if already joined
766786 let join_handle = {
0 commit comments