Author: mattip <[email protected]>
Branch: 
Changeset: r75994:d0d5493cb5fe
Date: 2015-02-19 10:05 +0200
http://bitbucket.org/pypy/pypy/changeset/d0d5493cb5fe/

Log:    merge alt_errno which provides an alternative location for errno,
        LastError in calls to cffi, ctypes

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -26,3 +26,7 @@
 
 .. branch: framestate2
 Refactor rpython.flowspace.framestate.FrameState.
+
+.. branch alt_errno
+Add an alternative location to save LastError, errno around ctypes,
+cffi external calls so things like pdb will not overwrite it
diff --git a/pypy/module/_cffi_backend/ccallback.py 
b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -210,6 +210,6 @@
         space.threadlocals.leave_thread(space)
 
 def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
-    cerrno._errno_after(rffi.RFFI_ERR_ALL)
+    cerrno._errno_after(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
     _invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata)
-    cerrno._errno_before(rffi.RFFI_ERR_ALL)
+    cerrno._errno_before(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
diff --git a/pypy/module/_cffi_backend/cerrno.py 
b/pypy/module/_cffi_backend/cerrno.py
--- a/pypy/module/_cffi_backend/cerrno.py
+++ b/pypy/module/_cffi_backend/cerrno.py
@@ -13,18 +13,18 @@
 _errno_after  = rposix._errno_after
 
 def get_errno(space):
-    return space.wrap(rposix.get_saved_errno())
+    return space.wrap(rposix.get_saved_alterrno())
 
 @unwrap_spec(errno=int)
 def set_errno(space, errno):
-    rposix.set_saved_errno(errno)
+    rposix.set_saved_alterrno(errno)
 
 # ____________________________________________________________
 
 @unwrap_spec(code=int)
 def getwinerror(space, code=-1):
-    from rpython.rlib.rwin32 import GetLastError_saved, FormatError
+    from rpython.rlib.rwin32 import GetLastError_alt_saved, FormatError
     if code == -1:
-        code = GetLastError_saved()
+        code = GetLastError_alt_saved()
     message = FormatError(code)
     return space.newtuple([space.wrap(code), space.wrap(message)])
diff --git a/pypy/module/_rawffi/interp_rawffi.py 
b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -608,19 +608,19 @@
     return space.wrap(W_CDLL(space, name, cdll))
 
 def get_errno(space):
-    return space.wrap(rposix.get_saved_errno())
+    return space.wrap(rposix.get_saved_alterrno())
 
 def set_errno(space, w_errno):
-    rposix.set_saved_errno(space.int_w(w_errno))
+    rposix.set_saved_alterrno(space.int_w(w_errno))
 
 if sys.platform == 'win32':
     # see also
     # https://bitbucket.org/pypy/pypy/issue/1944/ctypes-on-windows-getlasterror
     def get_last_error(space):
-        return space.wrap(rwin32.GetLastError_saved())
+        return space.wrap(rwin32.GetLastError_alt_saved())
     @unwrap_spec(error=int)
     def set_last_error(space, error):
-        rwin32.SetLastError_saved(error)
+        rwin32.SetLastError_alt_saved(error)
 else:
     # always have at least a dummy version of these functions
     # (https://bugs.pypy.org/issue1242)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py 
b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -202,7 +202,7 @@
         assert loop.match_by_id('cfficall', """
             p96 = force_token()
             setfield_gc(p0, p96, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token .>)
-            f97 = call_release_gil(27, i59, 1.0, 3, descr=<Callf 8 fi EF=6 
OS=62>)
+            f97 = call_release_gil(91, i59, 1.0, 3, descr=<Callf 8 fi EF=6 
OS=62>)
             guard_not_forced(descr=...)
             guard_no_exception(descr=...)
         """, ignore_ops=['guard_not_invalidated'])
diff --git a/rpython/jit/backend/arm/callbuilder.py 
b/rpython/jit/backend/arm/callbuilder.py
--- a/rpython/jit/backend/arm/callbuilder.py
+++ b/rpython/jit/backend/arm/callbuilder.py
@@ -176,11 +176,14 @@
 
     def write_real_errno(self, save_err):
         if save_err & rffi.RFFI_READSAVED_ERRNO:
-            # Just before a call, read 'rpy_errno' and write it into the
+            # Just before a call, read '*_errno' and write it into the
             # real 'errno'.  The r0-r3 registers contain arguments to the
             # future call; the r5-r7 registers contain various stuff.
             # We still have r8-r12.
-            rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
+            else:
+                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
             p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
             self.mc.LDR_ri(r.r9.value, r.sp.value,
                            self.asm.saved_threadlocal_addr + self.current_sp)
@@ -199,10 +202,13 @@
     def read_real_errno(self, save_err):
         if save_err & rffi.RFFI_SAVE_ERRNO:
             # Just after a call, read the real 'errno' and save a copy of
-            # it inside our thread-local 'rpy_errno'.  Registers r8-r12
+            # it inside our thread-local '*_errno'.  Registers r8-r12
             # are unused here, and registers r2-r3 never contain anything
             # after the call.
-            rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
+            else:
+                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
             p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
             self.mc.LDR_ri(r.r3.value, r.sp.value,
                            self.asm.saved_threadlocal_addr)
diff --git a/rpython/jit/backend/llsupport/llerrno.py 
b/rpython/jit/backend/llsupport/llerrno.py
--- a/rpython/jit/backend/llsupport/llerrno.py
+++ b/rpython/jit/backend/llsupport/llerrno.py
@@ -18,19 +18,41 @@
         return 3 * WORD
 
 
+def get_debug_saved_alterrno(cpu):
+    return cpu._debug_errno_container[4]
+
+def set_debug_saved_alterrno(cpu, nerrno):
+    assert nerrno >= 0
+    cpu._debug_errno_container[4] = nerrno
+
+def get_alt_errno_offset(cpu):
+    if cpu.translate_support_code:
+        from rpython.rlib import rthread
+        return rthread.tlfield_alt_errno.getoffset()
+    else:
+        return 4 * WORD
+
+
 def get_debug_saved_lasterror(cpu):
-    return cpu._debug_errno_container[4]
+    return cpu._debug_errno_container[5]
 
 def set_debug_saved_lasterror(cpu, nerrno):
     assert nerrno >= 0
-    cpu._debug_errno_container[4] = nerrno
+    cpu._debug_errno_container[5] = nerrno
 
 def get_rpy_lasterror_offset(cpu):
     if cpu.translate_support_code:
         from rpython.rlib import rthread
         return rthread.tlfield_rpy_lasterror.getoffset()
     else:
-        return 4 * WORD
+        return 5 * WORD
+
+def get_alt_lasterror_offset(cpu):
+    if cpu.translate_support_code:
+        from rpython.rlib import rthread
+        return rthread.tlfield_alt_lasterror.getoffset()
+    else:
+        return 6 * WORD
 
 
 def _fetch_addr_errno():
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -63,7 +63,7 @@
                                               ad.lendescr, FLAG_FLOAT)
         self.setup()
         self._debug_errno_container = lltype.malloc(
-            rffi.CArray(lltype.Signed), 5, flavor='raw', zero=True,
+            rffi.CArray(lltype.Signed), 7, flavor='raw', zero=True,
             track_allocation=False)
 
     def getarraydescr_for_frame(self, type):
diff --git a/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py 
b/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
@@ -98,6 +98,7 @@
         self.run('close_stack')
         assert 'call_release_gil' in 
udir.join('TestCompileFramework.log').read()
 
+    # XXX this should also test get/set_alterrno ?
     def define_get_set_errno(self):
         eci = ExternalCompilationInfo(
             post_include_bits=[r'''
diff --git a/rpython/jit/backend/test/runner_test.py 
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2948,7 +2948,11 @@
         calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
                                                           types.slong)
         #
-        for saveerr in [rffi.RFFI_ERR_NONE, rffi.RFFI_SAVE_ERRNO]:
+        for saveerr in [rffi.RFFI_ERR_NONE,
+                        rffi.RFFI_SAVE_ERRNO,
+                        rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO,
+                        rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
+                        ]:
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -2965,15 +2969,23 @@
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
             llerrno.set_debug_saved_errno(self.cpu, 24)
+            llerrno.set_debug_saved_alterrno(self.cpu, 25)
             deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
             original_result = self.cpu.get_int_value(deadframe, 0)
             result = llerrno.get_debug_saved_errno(self.cpu)
-            print 'saveerr =', saveerr, ': got result =', result
+            altresult = llerrno.get_debug_saved_alterrno(self.cpu)
+            print 'saveerr =', saveerr, ': got result =', result, \
+                  'altresult =', altresult
             #
-            if saveerr == rffi.RFFI_SAVE_ERRNO:
-                assert result == 42      # from the C code
-            else:
-                assert result == 24      # not touched
+            expected = {
+                rffi.RFFI_ERR_NONE: (24, 25),
+                rffi.RFFI_SAVE_ERRNO: (42, 25),
+                rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO: (24, 25),
+                rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO: (24, 42),
+            }
+            # expected (24, 25) as originally set, with possibly one
+            # of the two changed to 42 by the assembler code
+            assert (result, altresult) == expected[saveerr]
             assert original_result == 3456789
 
     def test_call_release_gil_readsaved_errno(self):
@@ -3007,7 +3019,11 @@
         calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
                                                           types.slong)
         #
-        for saveerr in [rffi.RFFI_READSAVED_ERRNO, 
rffi.RFFI_ZERO_ERRNO_BEFORE]:
+        for saveerr in [rffi.RFFI_READSAVED_ERRNO,
+                        rffi.RFFI_ZERO_ERRNO_BEFORE,
+                        rffi.RFFI_READSAVED_ERRNO   | rffi.RFFI_ALT_ERRNO,
+                        rffi.RFFI_ZERO_ERRNO_BEFORE | rffi.RFFI_ALT_ERRNO,
+                        ]:
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -3024,12 +3040,17 @@
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
             llerrno.set_debug_saved_errno(self.cpu, 24)
+            llerrno.set_debug_saved_alterrno(self.cpu, 25)
             deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
             result = self.cpu.get_int_value(deadframe, 0)
             assert llerrno.get_debug_saved_errno(self.cpu) == 24
+            assert llerrno.get_debug_saved_alterrno(self.cpu) == 25
             #
-            if saveerr == rffi.RFFI_READSAVED_ERRNO:
-                assert result == 24 + 345678900
+            if saveerr & rffi.RFFI_READSAVED_ERRNO:
+                if saveerr & rffi.RFFI_ALT_ERRNO:
+                    assert result == 25 + 345678900
+                else:
+                    assert result == 24 + 345678900
             else:
                 assert result == 0  + 345678900
 
@@ -3064,7 +3085,10 @@
                                                           types.slong)
         #
         for saveerr in [rffi.RFFI_SAVE_ERRNO,  # but not _LASTERROR
-                        rffi.RFFI_SAVE_LASTERROR]:
+                        rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
+                        rffi.RFFI_SAVE_LASTERROR,
+                        rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_ALT_ERRNO,
+                        ]:
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -3125,7 +3149,9 @@
         calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
                                                           types.slong)
         #
-        for saveerr in [rffi.RFFI_READSAVED_LASTERROR]:
+        for saveerr in [rffi.RFFI_READSAVED_LASTERROR,
+                        rffi.RFFI_READSAVED_LASTERROR | rffi.RFFI_ALT_ERRNO,
+                       ]:
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -3198,7 +3224,10 @@
         calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
                                                           types.slong)
         #
-        for saveerr in [rffi.RFFI_ERR_ALL]:
+        for saveerr in [rffi.RFFI_ERR_ALL,
+                        rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO, 
+                       ]:
+            use_alt_errno = saveerr & rffi.RFFI_ALT_ERRNO
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -3214,7 +3243,10 @@
             looptoken = JitCellToken()
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
-            llerrno.set_debug_saved_errno(self.cpu, 8)
+            if use_alt_errno:
+                llerrno.set_debug_saved_alterrno(self.cpu, 8)
+            else:
+                llerrno.set_debug_saved_errno(self.cpu, 8)
             llerrno.set_debug_saved_lasterror(self.cpu, 9)
             deadframe = self.cpu.execute_token(looptoken, 1, 2, 3, 4, 5, 6, 7)
             result = self.cpu.get_int_value(deadframe, 0)
diff --git a/rpython/jit/backend/x86/callbuilder.py 
b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -196,21 +196,27 @@
             SetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
             assert isinstance(self, CallBuilder32)    # Windows 32-bit only
             #
-            rpy_lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
+            else:
+                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
             tlofsreg = self.get_tlofs_reg()    # => esi, callee-saved
             self.save_stack_position()         # => edi, callee-saved
-            mc.PUSH_m((tlofsreg.value, rpy_lasterror))
+            mc.PUSH_m((tlofsreg.value, lasterror))
             mc.CALL(imm(SetLastError_addr))
             # restore the stack position without assuming a particular
             # calling convention of _SetLastError()
             self.mc.MOV(esp, self.saved_stack_position_reg)
 
         if save_err & rffi.RFFI_READSAVED_ERRNO:
-            # Just before a call, read 'rpy_errno' and write it into the
+            # Just before a call, read '*_errno' and write it into the
             # real 'errno'.  Most registers are free here, including the
             # callee-saved ones, except 'ebx' and except the ones used to
             # pass the arguments on x86-64.
-            rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
+            else:
+                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
             p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
             tlofsreg = self.get_tlofs_reg()    # => esi or r12, callee-saved
             if IS_X86_32:
@@ -234,11 +240,14 @@
 
         if save_err & rffi.RFFI_SAVE_ERRNO:
             # Just after a call, read the real 'errno' and save a copy of
-            # it inside our thread-local 'rpy_errno'.  Most registers are
+            # it inside our thread-local '*_errno'.  Most registers are
             # free here, including the callee-saved ones, except 'ebx'.
             # The tlofs register might have been loaded earlier and is
             # callee-saved, so it does not need to be reloaded.
-            rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
+            else:
+                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
             p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
             tlofsreg = self.get_tlofs_reg()   # => esi or r12 (possibly reused)
             mc.MOV_rm(edi.value, (tlofsreg.value, p_errno))
@@ -256,13 +265,16 @@
             GetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
             assert isinstance(self, CallBuilder32)    # Windows 32-bit only
             #
-            rpy_lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
+            else:
+                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
             self.save_result_value(save_edx=True)   # save eax/edx/xmm0
             self.result_value_saved_early = True
             mc.CALL(imm(GetLastError_addr))
             #
             tlofsreg = self.get_tlofs_reg()    # => esi (possibly reused)
-            mc.MOV32_mr((tlofsreg.value, rpy_lasterror), eax.value)
+            mc.MOV32_mr((tlofsreg.value, lasterror), eax.value)
 
     def move_real_result_and_call_reacqgil_addr(self, fastgil):
         from rpython.jit.backend.x86 import rx86
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -2879,7 +2879,8 @@
         box_result = op.result
         # for now, any call via libffi saves and restores everything
         # (that is, errno and SetLastError/GetLastError on Windows)
-        c_saveall = ConstInt(rffi.RFFI_ERR_ALL)
+        # Note these flags match the ones in clibffi.ll_callback
+        c_saveall = ConstInt(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
         self.history.record(rop.CALL_RELEASE_GIL,
                             [c_saveall, op.getarg(2)] + arg_boxes,
                             box_result, calldescr)
diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py
--- a/rpython/rlib/clibffi.py
+++ b/rpython/rlib/clibffi.py
@@ -331,7 +331,8 @@
     c_ffi_call_return_type = lltype.Void
 c_ffi_call = external('ffi_call', [FFI_CIFP, rffi.VOIDP, rffi.VOIDP,
                                    VOIDPP], c_ffi_call_return_type,
-                      save_err=rffi.RFFI_ERR_ALL)
+                      save_err=rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
+# Note: the RFFI_ALT_ERRNO flag matches the one in pyjitpl.direct_libffi_call
 CALLBACK_TP = rffi.CCallback([FFI_CIFP, rffi.VOIDP, rffi.VOIDPP, rffi.VOIDP],
                              lltype.Void)
 c_ffi_prep_closure = external('ffi_prep_closure', [FFI_CLOSUREP, FFI_CIFP,
@@ -424,9 +425,9 @@
     userdata.callback(ll_args, ll_res, userdata)
 
 def ll_callback(ffi_cif, ll_res, ll_args, ll_userdata):
-    rposix._errno_after(rffi.RFFI_ERR_ALL)
+    rposix._errno_after(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
     _ll_callback(ffi_cif, ll_res, ll_args, ll_userdata)
-    rposix._errno_before(rffi.RFFI_ERR_ALL)
+    rposix._errno_before(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
 
 
 class StackCheckError(ValueError):
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -116,17 +116,44 @@
     from rpython.rlib import rthread
     rthread.tlfield_rpy_errno.setraw(rffi.cast(INT, errno))
 
+def get_saved_alterrno():
+    """Return the value of the "saved alterrno".
+    This value is saved after a call to a C function, if it was declared
+    with the flag llexternal(..., save_err=rffi.RFFI_SAVE_ERRNO | 
rffl.RFFI_ALT_ERRNO).
+    Functions without that flag don't change the saved errno.
+    """
+    from rpython.rlib import rthread
+    return intmask(rthread.tlfield_alt_errno.getraw())
 
+def set_saved_alterrno(errno):
+    """Set the value of the saved alterrno.  This value will be used to
+    initialize the real errno just before calling the following C function,
+    provided it was declared llexternal(..., save_err=RFFI_READSAVED_ERRNO | 
rffl.RFFI_ALT_ERRNO).
+    Note also that it is more common to want the real errno to be initially
+    zero; for that case, use llexternal(..., save_err=RFFI_ZERO_ERRNO_BEFORE)
+    and then you don't need set_saved_errno(0).
+    """
+    from rpython.rlib import rthread
+    rthread.tlfield_alt_errno.setraw(rffi.cast(INT, errno))
+
+
+# These are not posix specific, but where should they move to?
 @specialize.call_location()
 def _errno_before(save_err):
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         from rpython.rlib import rthread
-        _set_errno(rthread.tlfield_rpy_errno.getraw())
+        if save_err & rffi.RFFI_ALT_ERRNO:
+            _set_errno(rthread.tlfield_alt_errno.getraw())
+        else:
+            _set_errno(rthread.tlfield_rpy_errno.getraw())
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         _set_errno(rffi.cast(rffi.INT, 0))
     if WIN32 and (save_err & rffi.RFFI_READSAVED_LASTERROR):
         from rpython.rlib import rthread, rwin32
-        err = rthread.tlfield_rpy_lasterror.getraw()
+        if save_err & rffi.RFFI_ALT_ERRNO:
+            err = rthread.tlfield_alt_lasterror.getraw()
+        else:
+            err = rthread.tlfield_rpy_lasterror.getraw()
         # careful, getraw() overwrites GetLastError.
         # We must assign it with _SetLastError() as the last
         # operation, i.e. after the errno handling.
@@ -140,14 +167,23 @@
             err = rwin32._GetLastError()
             # careful, setraw() overwrites GetLastError.
             # We must read it first, before the errno handling.
-            rthread.tlfield_rpy_lasterror.setraw(err)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rthread.tlfield_alt_lasterror.setraw(err)
+            else:
+                rthread.tlfield_rpy_lasterror.setraw(err)
         elif save_err & rffi.RFFI_SAVE_WSALASTERROR:
             from rpython.rlib import rthread, _rsocket_rffi
             err = _rsocket_rffi._WSAGetLastError()
-            rthread.tlfield_rpy_lasterror.setraw(err)
+            if save_err & rffi.RFFI_ALT_ERRNO:
+                rthread.tlfield_alt_lasterror.setraw(err)
+            else:
+                rthread.tlfield_rpy_lasterror.setraw(err)
     if save_err & rffi.RFFI_SAVE_ERRNO:
         from rpython.rlib import rthread
-        rthread.tlfield_rpy_errno.setraw(_get_errno())
+        if save_err & rffi.RFFI_ALT_ERRNO:
+            rthread.tlfield_alt_errno.setraw(_get_errno())
+        else:
+            rthread.tlfield_rpy_errno.setraw(_get_errno())
 
 
 if os.name == 'nt':
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -379,9 +379,11 @@
 tlfield_p_errno = ThreadLocalField(rffi.CArrayPtr(rffi.INT), "p_errno",
                                    loop_invariant=True)
 tlfield_rpy_errno = ThreadLocalField(rffi.INT, "rpy_errno")
+tlfield_alt_errno = ThreadLocalField(rffi.INT, "alt_errno")
 if sys.platform == "win32":
     from rpython.rlib import rwin32
     tlfield_rpy_lasterror = ThreadLocalField(rwin32.DWORD, "rpy_lasterror")
+    tlfield_alt_lasterror = ThreadLocalField(rwin32.DWORD, "alt_lasterror")
 
 def _threadlocalref_seeme(field):
     "NOT_RPYTHON"
diff --git a/rpython/rlib/rwin32.py b/rpython/rlib/rwin32.py
--- a/rpython/rlib/rwin32.py
+++ b/rpython/rlib/rwin32.py
@@ -145,6 +145,29 @@
         from rpython.rlib import rthread
         rthread.tlfield_rpy_lasterror.setraw(rffi.cast(DWORD, err))
 
+    def GetLastError_alt_saved():
+        """Return the value of the "saved alt LastError".
+        The C-level GetLastError() is saved there after a call to a C
+        function, if that C function was declared with the flag
+        llexternal(..., save_err=RFFI_SAVE_LASTERROR | RFFI_ALT_ERRNO).
+        Functions without that flag don't change the saved LastError.
+        Alternatively, if the function was declared 
+        RFFI_SAVE_WSALASTERROR | RFFI_ALT_ERRNO,
+        then the value of the C-level WSAGetLastError() is saved instead
+        (into the same "saved alt LastError" variable).
+        """
+        from rpython.rlib import rthread
+        return rffi.cast(lltype.Signed, rthread.tlfield_alt_lasterror.getraw())
+
+    def SetLastError_alt_saved(err):
+        """Set the value of the saved alt LastError.  This value will be used 
in
+        a call to the C-level SetLastError() just before calling the
+        following C function, provided it was declared
+        llexternal(..., save_err=RFFI_READSAVED_LASTERROR | RFFI_ALT_ERRNO).
+        """
+        from rpython.rlib import rthread
+        rthread.tlfield_alt_lasterror.setraw(rffi.cast(DWORD, err))
+
     # In tests, the first call to _GetLastError() is always wrong,
     # because error is hidden by operations in ll2ctypes.  Call it now.
     _GetLastError()
diff --git a/rpython/rtyper/lltypesystem/rffi.py 
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -70,7 +70,7 @@
 RFFI_FULL_LASTERROR      = RFFI_SAVE_LASTERROR | RFFI_READSAVED_LASTERROR
 RFFI_ERR_NONE            = 0
 RFFI_ERR_ALL             = RFFI_FULL_ERRNO | RFFI_FULL_LASTERROR
-
+RFFI_ALT_ERRNO           = 64    # read, save using alt tl destination
 def llexternal(name, args, result, _callable=None,
                compilation_info=ExternalCompilationInfo(),
                sandboxsafe=False, releasegil='auto',
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to