@@ -32,6 +32,90 @@ pub(super) const INTERNAL_CAST_ADDR: usize = 1;
3232pub ( super ) const INTERNAL_STRING_AT_ADDR : usize = 2 ;
3333pub ( super ) const INTERNAL_WSTRING_AT_ADDR : usize = 3 ;
3434
35+ // Thread-local errno storage for ctypes
36+ std:: thread_local! {
37+ /// Thread-local storage for ctypes errno
38+ /// This is separate from the system errno - ctypes swaps them during FFI calls
39+ /// when use_errno=True is specified.
40+ static CTYPES_LOCAL_ERRNO : std:: cell:: Cell <i32 > = const { std:: cell:: Cell :: new( 0 ) } ;
41+ }
42+
43+ /// Get ctypes thread-local errno value
44+ pub ( super ) fn get_errno_value ( ) -> i32 {
45+ CTYPES_LOCAL_ERRNO . with ( |e| e. get ( ) )
46+ }
47+
48+ /// Set ctypes thread-local errno value, returns old value
49+ pub ( super ) fn set_errno_value ( value : i32 ) -> i32 {
50+ CTYPES_LOCAL_ERRNO . with ( |e| {
51+ let old = e. get ( ) ;
52+ e. set ( value) ;
53+ old
54+ } )
55+ }
56+
57+ /// Save and restore errno around FFI call (called when use_errno=True)
58+ /// Before: restore thread-local errno to system
59+ /// After: save system errno to thread-local
60+ #[ cfg( not( windows) ) ]
61+ fn save_and_restore_errno < F , R > ( f : F ) -> R
62+ where
63+ F : FnOnce ( ) -> R ,
64+ {
65+ // Before call: restore thread-local errno to system
66+ let saved = CTYPES_LOCAL_ERRNO . with ( |e| e. get ( ) ) ;
67+ errno:: set_errno ( errno:: Errno ( saved) ) ;
68+
69+ // Call the function
70+ let result = f ( ) ;
71+
72+ // After call: save system errno to thread-local
73+ let new_error = errno:: errno ( ) . 0 ;
74+ CTYPES_LOCAL_ERRNO . with ( |e| e. set ( new_error) ) ;
75+
76+ result
77+ }
78+
79+ #[ cfg( windows) ]
80+ std:: thread_local! {
81+ /// Thread-local storage for ctypes last_error (Windows only)
82+ static CTYPES_LOCAL_LAST_ERROR : std:: cell:: Cell <u32 > = const { std:: cell:: Cell :: new( 0 ) } ;
83+ }
84+
85+ #[ cfg( windows) ]
86+ pub ( super ) fn get_last_error_value ( ) -> u32 {
87+ CTYPES_LOCAL_LAST_ERROR . with ( |e| e. get ( ) )
88+ }
89+
90+ #[ cfg( windows) ]
91+ pub ( super ) fn set_last_error_value ( value : u32 ) -> u32 {
92+ CTYPES_LOCAL_LAST_ERROR . with ( |e| {
93+ let old = e. get ( ) ;
94+ e. set ( value) ;
95+ old
96+ } )
97+ }
98+
99+ /// Save and restore last_error around FFI call (called when use_last_error=True)
100+ #[ cfg( windows) ]
101+ fn save_and_restore_last_error < F , R > ( f : F ) -> R
102+ where
103+ F : FnOnce ( ) -> R ,
104+ {
105+ // Before call: restore thread-local last_error to Windows
106+ let saved = CTYPES_LOCAL_LAST_ERROR . with ( |e| e. get ( ) ) ;
107+ unsafe { windows_sys:: Win32 :: Foundation :: SetLastError ( saved) } ;
108+
109+ // Call the function
110+ let result = f ( ) ;
111+
112+ // After call: save Windows last_error to thread-local
113+ let new_error = unsafe { windows_sys:: Win32 :: Foundation :: GetLastError ( ) } ;
114+ CTYPES_LOCAL_LAST_ERROR . with ( |e| e. set ( new_error) ) ;
115+
116+ result
117+ }
118+
35119type FP = unsafe extern "C" fn ( ) ;
36120
37121/// Get FFI type for a ctypes type code
@@ -1624,23 +1708,19 @@ impl Callable for PyCFuncPtr {
16241708 // 7. Get flags to check for use_last_error
16251709 let flags = PyCFuncPtr :: _flags_ ( zelf, vm) ;
16261710
1627- // 8. Call the function (with use_last_error handling on Windows )
1711+ // 8. Call the function (with use_last_error/use_errno handling)
16281712 #[ cfg( windows) ]
16291713 let raw_result = {
16301714 if flags & super :: base:: StgInfoFlags :: FUNCFLAG_USE_LASTERROR . bits ( ) != 0 {
1631- super :: _ctypes:: save_and_restore_last_error ( || {
1632- ctypes_callproc ( code_ptr, & arguments, & call_info)
1633- } )
1715+ save_and_restore_last_error ( || ctypes_callproc ( code_ptr, & arguments, & call_info) )
16341716 } else {
16351717 ctypes_callproc ( code_ptr, & arguments, & call_info)
16361718 }
16371719 } ;
16381720 #[ cfg( not( windows) ) ]
16391721 let raw_result = {
16401722 if flags & super :: base:: StgInfoFlags :: FUNCFLAG_USE_ERRNO . bits ( ) != 0 {
1641- super :: _ctypes:: save_and_restore_errno ( || {
1642- ctypes_callproc ( code_ptr, & arguments, & call_info)
1643- } )
1723+ save_and_restore_errno ( || ctypes_callproc ( code_ptr, & arguments, & call_info) )
16441724 } else {
16451725 ctypes_callproc ( code_ptr, & arguments, & call_info)
16461726 }
0 commit comments