@@ -706,23 +706,50 @@ mod _multiprocessing {
706706
707707 // if (res < 0 && errno == EAGAIN && blocking)
708708 if res < 0 && Errno :: last ( ) == Errno :: EAGAIN && blocking {
709- // Couldn't acquire immediately, need to block
709+ // Couldn't acquire immediately, need to block.
710+ //
711+ // Save errno inside the allow_threads closure, before
712+ // attach_thread() runs — matches CPython which saves
713+ // `err = errno` before Py_END_ALLOW_THREADS.
714+ let mut saved_errno = Errno :: UnknownErrno ;
715+
710716 #[ cfg( not( target_vendor = "apple" ) ) ]
711717 {
712718 loop {
713719 let sem_ptr = self . handle . as_ptr ( ) ;
714720 // Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS
715- res = if let Some ( ref dl) = deadline {
716- vm. allow_threads ( || unsafe { libc:: sem_timedwait ( sem_ptr, dl) } )
721+ let ( r, e) = if let Some ( ref dl) = deadline {
722+ vm. allow_threads ( || {
723+ let r = unsafe { libc:: sem_timedwait ( sem_ptr, dl) } ;
724+ (
725+ r,
726+ if r < 0 {
727+ Errno :: last ( )
728+ } else {
729+ Errno :: from_raw ( 0 )
730+ } ,
731+ )
732+ } )
717733 } else {
718- vm. allow_threads ( || unsafe { libc:: sem_wait ( sem_ptr) } )
734+ vm. allow_threads ( || {
735+ let r = unsafe { libc:: sem_wait ( sem_ptr) } ;
736+ (
737+ r,
738+ if r < 0 {
739+ Errno :: last ( )
740+ } else {
741+ Errno :: from_raw ( 0 )
742+ } ,
743+ )
744+ } )
719745 } ;
746+ res = r;
747+ saved_errno = e;
720748
721749 if res >= 0 {
722750 break ;
723751 }
724- let err = Errno :: last ( ) ;
725- if err == Errno :: EINTR {
752+ if saved_errno == Errno :: EINTR {
726753 vm. check_signals ( ) ?;
727754 continue ;
728755 }
@@ -751,29 +778,47 @@ mod _multiprocessing {
751778 // No timeout: use sem_wait (available on macOS)
752779 loop {
753780 let sem_ptr = self . handle . as_ptr ( ) ;
754- res = vm. allow_threads ( || unsafe { libc:: sem_wait ( sem_ptr) } ) ;
781+ let ( r, e) = vm. allow_threads ( || {
782+ let r = unsafe { libc:: sem_wait ( sem_ptr) } ;
783+ (
784+ r,
785+ if r < 0 {
786+ Errno :: last ( )
787+ } else {
788+ Errno :: from_raw ( 0 )
789+ } ,
790+ )
791+ } ) ;
792+ res = r;
793+ saved_errno = e;
755794 if res >= 0 {
756795 break ;
757796 }
758- let err = Errno :: last ( ) ;
759- if err == Errno :: EINTR {
797+ if saved_errno == Errno :: EINTR {
760798 vm. check_signals ( ) ?;
761799 continue ;
762800 }
763801 break ;
764802 }
765803 }
766804 }
767- }
768805
769- // result handling:
770- if res < 0 {
806+ // result handling — use saved_errno, not Errno::last()
807+ if res < 0 {
808+ match saved_errno {
809+ Errno :: EAGAIN | Errno :: ETIMEDOUT => return Ok ( false ) ,
810+ Errno :: EINTR => {
811+ return vm. check_signals ( ) . map ( |_| false ) ;
812+ }
813+ _ => return Err ( os_error ( vm, saved_errno) ) ,
814+ }
815+ }
816+ } else if res < 0 {
817+ // Non-blocking path failed, or blocking=false
771818 let err = Errno :: last ( ) ;
772819 match err {
773820 Errno :: EAGAIN | Errno :: ETIMEDOUT => return Ok ( false ) ,
774821 Errno :: EINTR => {
775- // EINTR should be handled by the check_signals() loop above
776- // If we reach here, check signals again and propagate any exception
777822 return vm. check_signals ( ) . map ( |_| false ) ;
778823 }
779824 _ => return Err ( os_error ( vm, err) ) ,
0 commit comments