[pypy-commit] pypy errno-again: start work on supporting GetLastError/SetLastError

arigo noreply at buildbot.pypy.org
Fri Jan 16 12:58:41 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: errno-again
Changeset: r75382:80dbb6ecf211
Date: 2015-01-16 12:58 +0100
http://bitbucket.org/pypy/pypy/changeset/80dbb6ecf211/

Log:	start work on supporting GetLastError/SetLastError

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
@@ -17,6 +17,22 @@
     else:
         return 3 * WORD
 
+
+def get_debug_saved_lasterror(cpu):
+    return cpu._debug_errno_container[4]
+
+def set_debug_saved_lasterror(cpu, nerrno):
+    assert nerrno >= 0
+    cpu._debug_errno_container[4] = 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
+
+
 def _fetch_addr_errno():
     eci = ExternalCompilationInfo(
         separate_module_sources=['''
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
@@ -3026,10 +3026,113 @@
                 assert result == 0  + 345678900
 
     def test_call_release_gil_save_lasterror(self):
-        XXX
+        from rpython.translator.tool.cbuild import ExternalCompilationInfo
+        from rpython.rlib.libffi import types
+        from rpython.jit.backend.llsupport import llerrno
+        #
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("not on LLGraph")
+        if sys.platform != 'win32':
+            py.test.skip("Windows test only")
+        eci = ExternalCompilationInfo(
+            separate_module_sources=['''
+                #include <windows.h>
+                RPY_EXPORTED
+                long __stdcall test_call_release_gil_save_lasterror(
+                       long a, long b, long c, long d, long e, long f, long g) {
+                    SetLastError(42);
+                    return (a + 10*b + 100*c + 1000*d +
+                            10000*e + 100000*f + 1000000*g);
+                }
+            '''])
+        fn_name = 'test_call_release_gil_save_lasterror'
+        func1_ptr = rffi.llexternal(fn_name, [lltype.Signed]*7, lltype.Signed,
+                                    compilation_info=eci, _nowrapper=True)
+        func1_adr = rffi.cast(lltype.Signed, func1_ptr)
+        calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
+                                                          types.slong)
+        #
+        for saveerr in [rffi.RFFI_SAVE_ERRNO,  # but not _LASTERROR
+                        rffi.RFFI_SAVE_LASTERROR]:
+            faildescr = BasicFailDescr(1)
+            inputargs = [BoxInt() for i in range(7)]
+            i1 = BoxInt()
+            ops = [
+                ResOperation(rop.CALL_RELEASE_GIL,
+                             [ConstInt(saveerr), ConstInt(func1_adr)]
+                                 + inputargs, i1,
+                             descr=calldescr),
+                ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
+                ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0))
+            ]
+            ops[-2].setfailargs([])
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(inputargs, ops, looptoken)
+            #
+            llerrno.set_debug_saved_lasterror(self.cpu, 24)
+            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_lasterror(self.cpu)
+            print 'saveerr =', saveerr, ': got result =', result
+            #
+            if saveerr == rffi.RFFI_SAVE_LASTERROR:
+                assert result == 42      # from the C code
+            else:
+                assert result == 24      # not touched
+            assert original_result == 3456789
 
     def test_call_release_gil_readsaved_lasterror(self):
-        XXX
+        from rpython.translator.tool.cbuild import ExternalCompilationInfo
+        from rpython.rlib.libffi import types
+        from rpython.jit.backend.llsupport import llerrno
+        #
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("not on LLGraph")
+        if sys.platform != 'win32':
+            py.test.skip("Windows test only")
+        eci = ExternalCompilationInfo(
+            separate_module_sources=[r'''
+                #include <stdio.h>
+                #include <errno.h>
+                RPY_EXPORTED
+                long __stdcall test_call_release_gil_readsaved_lasterror(
+                       long a, long b, long c, long d, long e, long f, long g) {
+                    long r = GetLastError();
+                    printf("GetLastError() result: %ld\n", r);
+                    r += 100 * (a + 10*b + 100*c + 1000*d +
+                                10000*e + 100000*f + 1000000*g);
+                    return r;
+                }
+            '''])
+        fn_name = 'test_call_release_gil_readsaved_lasterror'
+        func1_ptr = rffi.llexternal(fn_name, [lltype.Signed]*7, lltype.Signed,
+                                    compilation_info=eci, _nowrapper=True)
+        func1_adr = rffi.cast(lltype.Signed, func1_ptr)
+        calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
+                                                          types.slong)
+        #
+        for saveerr in [rffi.RFFI_READSAVED_LASTERROR]:
+            faildescr = BasicFailDescr(1)
+            inputargs = [BoxInt() for i in range(7)]
+            i1 = BoxInt()
+            ops = [
+                ResOperation(rop.CALL_RELEASE_GIL,
+                             [ConstInt(saveerr), ConstInt(func1_adr)]
+                                 + inputargs, i1,
+                             descr=calldescr),
+                ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
+                ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0))
+            ]
+            ops[-2].setfailargs([])
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(inputargs, ops, looptoken)
+            #
+            llerrno.set_debug_saved_lasterror(self.cpu, 24)
+            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_lasterror(self.cpu) == 24
+            #
+            assert result == 24 + 345678900
 
     def test_guard_not_invalidated(self):
         cpu = self.cpu
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -7,6 +7,8 @@
 from rpython.rlib import jit
 from rpython.translator.platform import platform
 
+WIN32 = os.name == "nt"
+
 
 class CConstantErrno(CConstant):
     # these accessors are used when calling get_errno() or set_errno()
@@ -109,6 +111,9 @@
 
 @specialize.call_location()
 def _errno_before(save_err):
+    if WIN32 and (save_err & rffi.RFFI_READSAVED_LASTERROR):
+        from rpython.rlib import rthread, rwin32
+        rwin32._SetLastError(rthread.tlfield_rpy_lasterror.getraw())
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         from rpython.rlib import rthread
         _set_errno(rthread.tlfield_rpy_errno.getraw())
@@ -120,6 +125,9 @@
     if save_err & rffi.RFFI_SAVE_ERRNO:
         from rpython.rlib import rthread
         rthread.tlfield_rpy_errno.setraw(_get_errno())
+    if WIN32 and (save_err & rffi.RFFI_SAVE_LASTERROR):
+        from rpython.rlib import rthread, rwin32
+        rthread.tlfield_rpy_lasterror.setraw(rwin32._GetLastError())
 
 
 if os.name == 'nt':
diff --git a/rpython/rlib/rwin32.py b/rpython/rlib/rwin32.py
--- a/rpython/rlib/rwin32.py
+++ b/rpython/rlib/rwin32.py
@@ -123,12 +123,6 @@
     _SetLastError = winexternal('SetLastError', [DWORD], lltype.Void,
                                 _nowrapper=True, sandboxsafe=True)
 
-    def GetLastError_real():
-        return rffi.cast(lltype.Signed, _GetLastError())
-
-    def SetLastError_real(err):
-        _SetLastError(rffi.cast(DWORD, err))
-
     def GetLastError_saved():
         from rpython.rlib import rthread
         return rffi.cast(lltype.Signed, rthread.tlfield_rpy_lasterror.getraw())
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
@@ -64,8 +64,8 @@
 RFFI_ZERO_ERRNO_BEFORE   = 4     # copy the value 0 into real errno before call
 RFFI_FULL_ERRNO          = RFFI_SAVE_ERRNO | RFFI_READSAVED_ERRNO
 RFFI_FULL_ERRNO_ZERO     = RFFI_SAVE_ERRNO | RFFI_ZERO_ERRNO_BEFORE
-RFFI_SAVE_LASTERROR      = 8     # XXX implement me!
-RFFI_READSAVED_LASTERROR = 16    # XXX implement me!
+RFFI_SAVE_LASTERROR      = 8     # win32: save GetLastError() after the call
+RFFI_READSAVED_LASTERROR = 16    # win32: call SetLastError() before the call
 RFFI_FULL_LASTERROR      = RFFI_SAVE_LASTERROR | RFFI_READSAVED_LASTERROR
 RFFI_ERR_NONE            = 0
 RFFI_ERR_ALL             = RFFI_FULL_ERRNO | RFFI_FULL_LASTERROR


More information about the pypy-commit mailing list