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