Author: Armin Rigo <[email protected]>
Branch:
Changeset: r75444:05783c6d4ff1
Date: 2015-01-19 23:53 +0100
http://bitbucket.org/pypy/pypy/changeset/05783c6d4ff1/
Log: hg merge errno-again
Changes how errno, GetLastError, and WSAGetLastError are handled.
The idea is to tie reading the error status as close as possible to
the external function call. This fixes some bugs, both of the very
rare kind (e.g. errno on Linux might in theory be overwritten by
mmap(), called rarely during major GCs, if such a major GC occurs at
exactly the wrong time), and some of the less rare kind
(particularly on Windows tests).
Now the rffi.llexternal() declaration must specify what kind of
errno support it needs ('save_err' argument), and the
rposix.get_errno() function has been consequently renamed to
get_saved_errno(). We need to adapt all RPython libraries that use
rposix.get_errno(), which is why the function was renamed. Same
with rwin32.GetLastError().
diff too long, truncating to 2000 out of 6200 lines
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -486,10 +486,10 @@
w_exception_class=w_exception_class)
wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
-def exception_from_errno(space, w_type):
- from rpython.rlib.rposix import get_errno
+def exception_from_saved_errno(space, w_type):
+ from rpython.rlib.rposix import get_saved_errno
- errno = get_errno()
+ errno = get_saved_errno()
msg = os.strerror(errno)
w_error = space.call_function(w_type, space.wrap(errno), space.wrap(msg))
return OperationError(w_type, w_error)
diff --git a/pypy/module/__pypy__/interp_time.py
b/pypy/module/__pypy__/interp_time.py
--- a/pypy/module/__pypy__/interp_time.py
+++ b/pypy/module/__pypy__/interp_time.py
@@ -1,7 +1,7 @@
from __future__ import with_statement
import sys
-from pypy.interpreter.error import exception_from_errno
+from pypy.interpreter.error import exception_from_saved_errno
from pypy.interpreter.gateway import unwrap_spec
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rtyper.tool import rffi_platform
@@ -48,11 +48,13 @@
c_clock_gettime = rffi.llexternal("clock_gettime",
[lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
- compilation_info=CConfig._compilation_info_, releasegil=False
+ compilation_info=CConfig._compilation_info_, releasegil=False,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
c_clock_getres = rffi.llexternal("clock_getres",
[lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
- compilation_info=CConfig._compilation_info_, releasegil=False
+ compilation_info=CConfig._compilation_info_, releasegil=False,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
@unwrap_spec(clk_id="c_int")
@@ -60,7 +62,7 @@
with lltype.scoped_alloc(TIMESPEC) as tp:
ret = c_clock_gettime(clk_id, tp)
if ret != 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
return space.wrap(int(tp.c_tv_sec) + 1e-9 * int(tp.c_tv_nsec))
@unwrap_spec(clk_id="c_int")
@@ -68,5 +70,5 @@
with lltype.scoped_alloc(TIMESPEC) as tp:
ret = c_clock_getres(clk_id, tp)
if ret != 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
return space.wrap(int(tp.c_tv_sec) + 1e-9 * int(tp.c_tv_nsec))
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
@@ -160,7 +160,7 @@
@jit.jit_callback("CFFI")
-def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
+def _invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
""" Callback specification.
ffi_cif - something ffi specific, don't care
ll_args - rffi.VOIDPP - pointer to array of pointers to args
@@ -168,7 +168,6 @@
ll_userdata - a special structure which holds necessary information
(what the real callback is for example), casted to VOIDP
"""
- e = cerrno.get_real_errno()
ll_res = rffi.cast(rffi.CCHARP, ll_res)
unique_id = rffi.cast(lltype.Signed, ll_userdata)
callback = global_callback_mapping.get(unique_id)
@@ -185,12 +184,9 @@
return
#
must_leave = False
- ec = None
space = callback.space
try:
must_leave = space.threadlocals.try_enter_thread(space)
- ec = cerrno.get_errno_container(space)
- cerrno.save_errno_into(ec, e)
extra_line = ''
try:
w_res = callback.invoke(ll_args)
@@ -212,5 +208,8 @@
callback.write_error_return_value(ll_res)
if must_leave:
space.threadlocals.leave_thread(space)
- if ec is not None:
- cerrno.restore_errno_from(ec)
+
+def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
+ cerrno._errno_after(rffi.RFFI_ERR_ALL)
+ _invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata)
+ cerrno._errno_before(rffi.RFFI_ERR_ALL)
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
@@ -2,7 +2,6 @@
from rpython.rlib import rposix
-from pypy.interpreter.executioncontext import ExecutionContext
from pypy.interpreter.gateway import unwrap_spec
WIN32 = sys.platform == 'win32'
@@ -10,43 +9,22 @@
from rpython.rlib import rwin32
-ExecutionContext._cffi_saved_errno = 0
-ExecutionContext._cffi_saved_LastError = 0
-
-
-def get_errno_container(space):
- return space.getexecutioncontext()
-
-get_real_errno = rposix.get_errno
-
-
-def restore_errno_from(ec):
- if WIN32:
- rwin32.SetLastError(ec._cffi_saved_LastError)
- rposix.set_errno(ec._cffi_saved_errno)
-
-def save_errno_into(ec, errno):
- ec._cffi_saved_errno = errno
- if WIN32:
- ec._cffi_saved_LastError = rwin32.GetLastError()
-
+_errno_before = rposix._errno_before
+_errno_after = rposix._errno_after
def get_errno(space):
- ec = get_errno_container(space)
- return space.wrap(ec._cffi_saved_errno)
+ return space.wrap(rposix.get_saved_errno())
@unwrap_spec(errno=int)
def set_errno(space, errno):
- ec = get_errno_container(space)
- ec._cffi_saved_errno = errno
+ rposix.set_saved_errno(errno)
# ____________________________________________________________
@unwrap_spec(code=int)
def getwinerror(space, code=-1):
- from rpython.rlib.rwin32 import FormatError
+ from rpython.rlib.rwin32 import GetLastError_saved, FormatError
if code == -1:
- ec = get_errno_container(space)
- code = ec._cffi_saved_LastError
+ code = GetLastError_saved()
message = FormatError(code)
return space.newtuple([space.wrap(code), space.wrap(message)])
diff --git a/pypy/module/_cffi_backend/ctypefunc.py
b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -155,13 +155,9 @@
# argtype is a pointer type, and w_obj a list/tuple/str
mustfree_max_plus_1 = i + 1
- ec = cerrno.get_errno_container(space)
- cerrno.restore_errno_from(ec)
jit_libffi.jit_ffi_call(cif_descr,
rffi.cast(rffi.VOIDP, funcaddr),
buffer)
- e = cerrno.get_real_errno()
- cerrno.save_errno_into(ec, e)
resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
w_res = self.ctitem.copy_and_convert_to_object(resultdata)
diff --git a/pypy/module/_cffi_backend/ctypeptr.py
b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -347,7 +347,8 @@
# ____________________________________________________________
-rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP)
+rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP,
+ save_err=rffi.RFFI_SAVE_ERRNO)
rffi_setbuf = rffi.llexternal("setbuf", [rffi.CCHARP, rffi.CCHARP],
lltype.Void)
rffi_fclose = rffi.llexternal("fclose", [rffi.CCHARP], rffi.INT)
@@ -357,7 +358,7 @@
def __init__(self, fd, mode):
self.llf = rffi_fdopen(fd, mode)
if not self.llf:
- raise OSError(rposix.get_errno(), "fdopen failed")
+ raise OSError(rposix.get_saved_errno(), "fdopen failed")
rffi_setbuf(self.llf, lltype.nullptr(rffi.CCHARP.TO))
def close(self):
diff --git a/pypy/module/_io/interp_bufferedio.py
b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -19,10 +19,16 @@
def make_write_blocking_error(space, written):
+ # XXX CPython reads 'errno' here. I *think* it doesn't make sense,
+ # because we might reach this point after calling a write() method
+ # that may be overridden by the user, if that method returns None.
+ # In that case what we get is a potentially nonsense errno. But
+ # we'll use get_saved_errno() anyway, and hope (like CPython does)
+ # that we're getting a reasonable value at this point.
w_type = space.gettypeobject(W_BlockingIOError.typedef)
w_value = space.call_function(
w_type,
- space.wrap(rposix.get_errno()),
+ space.wrap(rposix.get_saved_errno()),
space.wrap("write could not complete without blocking"),
space.wrap(written))
return OperationError(w_type, w_value)
diff --git a/pypy/module/_locale/interp_locale.py
b/pypy/module/_locale/interp_locale.py
--- a/pypy/module/_locale/interp_locale.py
+++ b/pypy/module/_locale/interp_locale.py
@@ -300,7 +300,8 @@
return space.wrap(result)
_bindtextdomain = rlocale.external('bindtextdomain', [rffi.CCHARP,
rffi.CCHARP],
- rffi.CCHARP)
+ rffi.CCHARP,
+ save_err=rffi.RFFI_SAVE_ERRNO)
@unwrap_spec(domain=str)
def bindtextdomain(space, domain, w_dir):
@@ -325,7 +326,7 @@
rffi.free_charp(dir_c)
if not dirname:
- errno = rposix.get_errno()
+ errno = rposix.get_saved_errno()
raise OperationError(space.w_OSError, space.wrap(errno))
return space.wrap(rffi.charp2str(dirname))
diff --git a/pypy/module/_multiprocessing/interp_connection.py
b/pypy/module/_multiprocessing/interp_connection.py
--- a/pypy/module/_multiprocessing/interp_connection.py
+++ b/pypy/module/_multiprocessing/interp_connection.py
@@ -406,7 +406,7 @@
size, written_ptr, rffi.NULL)
if (result == 0 and
- rwin32.GetLastError() == ERROR_NO_SYSTEM_RESOURCES):
+ rwin32.GetLastError_saved() == ERROR_NO_SYSTEM_RESOURCES):
raise oefmt(space.w_ValueError,
"Cannot send %d bytes over connection", size)
finally:
@@ -430,7 +430,7 @@
if result:
return intmask(read_ptr[0]), lltype.nullptr(rffi.CCHARP.TO)
- err = rwin32.GetLastError()
+ err = rwin32.GetLastError_saved()
if err == ERROR_BROKEN_PIPE:
raise OperationError(space.w_EOFError, space.w_None)
elif err != ERROR_MORE_DATA:
@@ -441,7 +441,7 @@
lltype.nullptr(rwin32.LPDWORD.TO),
lltype.nullptr(rwin32.LPDWORD.TO),
left_ptr):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
length = intmask(read_ptr[0] + left_ptr[0])
if length > maxlength: # bad message, close connection
@@ -460,7 +460,7 @@
read_ptr, rffi.NULL)
if not result:
rffi.free_charp(newbuf)
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
assert read_ptr[0] == left_ptr[0]
return length, newbuf
@@ -480,7 +480,7 @@
lltype.nullptr(rwin32.LPDWORD.TO),
bytes_ptr,
lltype.nullptr(rwin32.LPDWORD.TO)):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
bytes = bytes_ptr[0]
finally:
lltype.free(bytes_ptr, flavor='raw')
@@ -506,7 +506,8 @@
lltype.nullptr(rwin32.LPDWORD.TO),
bytes_ptr,
lltype.nullptr(rwin32.LPDWORD.TO)):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space,
+ rwin32.lastSavedWindowsError())
bytes = bytes_ptr[0]
finally:
lltype.free(bytes_ptr, flavor='raw')
diff --git a/pypy/module/_multiprocessing/interp_semaphore.py
b/pypy/module/_multiprocessing/interp_semaphore.py
--- a/pypy/module/_multiprocessing/interp_semaphore.py
+++ b/pypy/module/_multiprocessing/interp_semaphore.py
@@ -26,12 +26,14 @@
_CreateSemaphore = rwin32.winexternal(
'CreateSemaphoreA', [rffi.VOIDP, rffi.LONG, rffi.LONG, rwin32.LPCSTR],
- rwin32.HANDLE)
- _CloseHandle = rwin32.winexternal('CloseHandle', [rwin32.HANDLE],
+ rwin32.HANDLE,
+ save_err=rffi.RFFI_FULL_LASTERROR)
+ _CloseHandle_no_errno = rwin32.winexternal('CloseHandle', [rwin32.HANDLE],
rwin32.BOOL, releasegil=False)
_ReleaseSemaphore = rwin32.winexternal(
'ReleaseSemaphore', [rwin32.HANDLE, rffi.LONG, rffi.LONGP],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
else:
from rpython.rlib import rposix
@@ -81,51 +83,61 @@
_sem_open = external('sem_open',
[rffi.CCHARP, rffi.INT, rffi.INT, rffi.UINT],
- SEM_T)
+ SEM_T, save_err=rffi.RFFI_SAVE_ERRNO)
# sem_close is releasegil=False to be able to use it in the __del__
- _sem_close = external('sem_close', [SEM_T], rffi.INT, releasegil=False)
- _sem_unlink = external('sem_unlink', [rffi.CCHARP], rffi.INT)
- _sem_wait = external('sem_wait', [SEM_T], rffi.INT)
- _sem_trywait = external('sem_trywait', [SEM_T], rffi.INT)
- _sem_post = external('sem_post', [SEM_T], rffi.INT)
- _sem_getvalue = external('sem_getvalue', [SEM_T, rffi.INTP], rffi.INT)
+ _sem_close_no_errno = external('sem_close', [SEM_T], rffi.INT,
+ releasegil=False)
+ _sem_close = external('sem_close', [SEM_T], rffi.INT, releasegil=False,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ _sem_unlink = external('sem_unlink', [rffi.CCHARP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ _sem_wait = external('sem_wait', [SEM_T], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ _sem_trywait = external('sem_trywait', [SEM_T], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ _sem_post = external('sem_post', [SEM_T], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ _sem_getvalue = external('sem_getvalue', [SEM_T, rffi.INTP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
- _gettimeofday = external('gettimeofday', [TIMEVALP, rffi.VOIDP], rffi.INT)
+ _gettimeofday = external('gettimeofday', [TIMEVALP, rffi.VOIDP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
_select = external('select', [rffi.INT, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP,
- TIMEVALP], rffi.INT)
+ TIMEVALP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
@jit.dont_look_inside
def sem_open(name, oflag, mode, value):
res = _sem_open(name, oflag, mode, value)
if res == rffi.cast(SEM_T, SEM_FAILED):
- raise OSError(rposix.get_errno(), "sem_open failed")
+ raise OSError(rposix.get_saved_errno(), "sem_open failed")
return res
def sem_close(handle):
res = _sem_close(handle)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_close failed")
+ raise OSError(rposix.get_saved_errno(), "sem_close failed")
def sem_unlink(name):
res = _sem_unlink(name)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_unlink failed")
+ raise OSError(rposix.get_saved_errno(), "sem_unlink failed")
def sem_wait(sem):
res = _sem_wait(sem)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_wait failed")
+ raise OSError(rposix.get_saved_errno(), "sem_wait failed")
def sem_trywait(sem):
res = _sem_trywait(sem)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_trywait failed")
+ raise OSError(rposix.get_saved_errno(), "sem_trywait failed")
def sem_timedwait(sem, deadline):
res = _sem_timedwait(sem, deadline)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_timedwait failed")
+ raise OSError(rposix.get_saved_errno(), "sem_timedwait failed")
def _sem_timedwait_save(sem, deadline):
delay = 0
@@ -135,7 +147,7 @@
# poll
if _sem_trywait(sem) == 0:
return 0
- elif rposix.get_errno() != errno.EAGAIN:
+ elif rposix.get_saved_errno() != errno.EAGAIN:
return -1
now = gettimeofday()
@@ -143,7 +155,7 @@
c_tv_nsec = rffi.getintfield(deadline[0], 'c_tv_nsec')
if (c_tv_sec < now[0] or
(c_tv_sec == now[0] and c_tv_nsec <= now[1])):
- rposix.set_errno(errno.ETIMEDOUT)
+ rposix.set_saved_errno(errno.ETIMEDOUT)
return -1
@@ -166,21 +178,21 @@
if SEM_TIMED_WAIT:
_sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP],
- rffi.INT)
+ rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO)
else:
_sem_timedwait = _sem_timedwait_save
def sem_post(sem):
res = _sem_post(sem)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_post failed")
+ raise OSError(rposix.get_saved_errno(), "sem_post failed")
def sem_getvalue(sem):
sval_ptr = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
try:
res = _sem_getvalue(sem, sval_ptr)
if res < 0:
- raise OSError(rposix.get_errno(), "sem_getvalue failed")
+ raise OSError(rposix.get_saved_errno(), "sem_getvalue failed")
return rffi.cast(lltype.Signed, sval_ptr[0])
finally:
lltype.free(sval_ptr, flavor='raw')
@@ -190,7 +202,7 @@
try:
res = _gettimeofday(now, None)
if res < 0:
- raise OSError(rposix.get_errno(), "gettimeofday failed")
+ raise OSError(rposix.get_saved_errno(), "gettimeofday failed")
return (rffi.getintfield(now[0], 'c_tv_sec'),
rffi.getintfield(now[0], 'c_tv_usec'))
finally:
@@ -216,18 +228,16 @@
if sys.platform == 'win32':
def create_semaphore(space, name, val, max):
- rwin32.SetLastError(0)
+ rwin32.SetLastError_saved(0)
handle = _CreateSemaphore(rffi.NULL, val, max, rffi.NULL)
# On Windows we should fail on ERROR_ALREADY_EXISTS
- err = rwin32.GetLastError()
+ err = rwin32.GetLastError_saved()
if err != 0:
raise WindowsError(err, "CreateSemaphore")
return handle
def delete_semaphore(handle):
- if not _CloseHandle(handle):
- err = rwin32.GetLastError()
- raise WindowsError(err, "CloseHandle")
+ _CloseHandle_no_errno(handle)
def semlock_acquire(self, space, block, w_timeout):
if not block:
@@ -286,7 +296,7 @@
def semlock_release(self, space):
if not _ReleaseSemaphore(self.handle, 1,
lltype.nullptr(rffi.LONGP.TO)):
- err = rwin32.GetLastError()
+ err = rwin32.GetLastError_saved()
if err == 0x0000012a: # ERROR_TOO_MANY_POSTS
raise OperationError(
space.w_ValueError,
@@ -300,7 +310,7 @@
previous_ptr = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw')
try:
if not _ReleaseSemaphore(self.handle, 1, previous_ptr):
- raise rwin32.lastWindowsError("ReleaseSemaphore")
+ raise rwin32.lastSavedWindowsError("ReleaseSemaphore")
return previous_ptr[0] + 1
finally:
lltype.free(previous_ptr, flavor='raw')
@@ -320,7 +330,7 @@
return sem
def delete_semaphore(handle):
- sem_close(handle)
+ _sem_close_no_errno(handle)
def semlock_acquire(self, space, block, w_timeout):
if not block:
diff --git a/pypy/module/_multiprocessing/interp_win32.py
b/pypy/module/_multiprocessing/interp_win32.py
--- a/pypy/module/_multiprocessing/interp_win32.py
+++ b/pypy/module/_multiprocessing/interp_win32.py
@@ -41,20 +41,24 @@
rwin32.DWORD, rwin32.DWORD, rwin32.DWORD,
rwin32.DWORD, rwin32.DWORD, rwin32.DWORD,
rffi.VOIDP],
- rwin32.HANDLE)
+ rwin32.HANDLE,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_ConnectNamedPipe = rwin32.winexternal(
- 'ConnectNamedPipe', [rwin32.HANDLE, rffi.VOIDP], rwin32.BOOL)
+ 'ConnectNamedPipe', [rwin32.HANDLE, rffi.VOIDP], rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_SetNamedPipeHandleState = rwin32.winexternal(
'SetNamedPipeHandleState', [
rwin32.HANDLE,
rwin32.LPDWORD, rwin32.LPDWORD, rwin32.LPDWORD],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_WaitNamedPipe = rwin32.winexternal(
'WaitNamedPipeA', [rwin32.LPCSTR, rwin32.DWORD],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_PeekNamedPipe = rwin32.winexternal(
'PeekNamedPipe', [
@@ -62,31 +66,36 @@
rffi.VOIDP,
rwin32.DWORD,
rwin32.LPDWORD, rwin32.LPDWORD, rwin32.LPDWORD],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_CreateFile = rwin32.winexternal(
'CreateFileA', [
rwin32.LPCSTR,
rwin32.DWORD, rwin32.DWORD, rffi.VOIDP,
rwin32.DWORD, rwin32.DWORD, rwin32.HANDLE],
- rwin32.HANDLE)
+ rwin32.HANDLE,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_WriteFile = rwin32.winexternal(
'WriteFile', [
rwin32.HANDLE,
rffi.VOIDP, rwin32.DWORD,
rwin32.LPDWORD, rffi.VOIDP],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_ReadFile = rwin32.winexternal(
'ReadFile', [
rwin32.HANDLE,
rffi.VOIDP, rwin32.DWORD,
rwin32.LPDWORD, rffi.VOIDP],
- rwin32.BOOL)
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_ExitProcess = rwin32.winexternal(
- 'ExitProcess', [rffi.UINT], lltype.Void)
+ 'ExitProcess', [rffi.UINT], lltype.Void,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
_GetTickCount = rwin32.winexternal(
'GetTickCount', [], rwin32.DWORD)
@@ -97,10 +106,10 @@
def CloseHandle(space, w_handle):
handle = handle_w(space, w_handle)
if not rwin32.CloseHandle(handle):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
def GetLastError(space):
- return space.wrap(rwin32.GetLastError())
+ return space.wrap(rwin32.GetLastError_saved())
# __________________________________________________________
# functions for the "win32" namespace
@@ -118,7 +127,7 @@
outputsize, inputsize, timeout, rffi.NULL)
if handle == rwin32.INVALID_HANDLE_VALUE:
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
return w_handle(space, handle)
@@ -129,7 +138,7 @@
raise OperationError(space.w_NotImplementedError,
space.wrap("expected a NULL pointer"))
if not _ConnectNamedPipe(handle, rffi.NULL):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances,
w_timeout):
@@ -149,7 +158,7 @@
statep[2] = rffi.ptradd(state, 2)
if not _SetNamedPipeHandleState(handle, statep[0], statep[1],
statep[2]):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
finally:
lltype.free(state, flavor='raw')
lltype.free(statep, flavor='raw')
@@ -158,7 +167,7 @@
def WaitNamedPipe(space, name, timeout):
# Careful: zero means "default value specified by CreateNamedPipe()"
if not _WaitNamedPipe(name, timeout):
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
@unwrap_spec(filename=str, access=r_uint, share=r_uint,
disposition=r_uint, flags=r_uint)
@@ -174,7 +183,7 @@
disposition, flags, rwin32.NULL_HANDLE)
if handle == rwin32.INVALID_HANDLE_VALUE:
- raise wrap_windowserror(space, rwin32.lastWindowsError())
+ raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
return w_handle(space, handle)
diff --git a/pypy/module/_rawffi/alt/interp_funcptr.py
b/pypy/module/_rawffi/alt/interp_funcptr.py
--- a/pypy/module/_rawffi/alt/interp_funcptr.py
+++ b/pypy/module/_rawffi/alt/interp_funcptr.py
@@ -14,7 +14,6 @@
from rpython.rlib.objectmodel import we_are_translated
from pypy.module._rawffi.alt.type_converter import FromAppLevelConverter,
ToAppLevelConverter
from pypy.module._rawffi.interp_rawffi import got_libffi_error,
wrap_dlopenerror
-from pypy.module._rawffi import lasterror
import os
if os.name == 'nt':
@@ -202,23 +201,11 @@
self.func = func
self.argchain = argchain
- def before(self):
- lasterror.restore_last_error(self.space)
-
- def after(self):
- lasterror.save_last_error(self.space)
-
def get_longlong(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.LONGLONG)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.LONGLONG)
def get_ulonglong(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.ULONGLONG)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.ULONGLONG)
def get_signed(self, w_ffitype):
# if the declared return type of the function is smaller than LONG,
@@ -229,7 +216,6 @@
# to space.wrap in order to get a nice applevel <int>.
#
restype = w_ffitype.get_ffitype()
- self.before()
call = self.func.call
if restype is libffi.types.slong:
x = call(self.argchain, rffi.LONG)
@@ -241,19 +227,14 @@
x = rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
else:
raise self.error(w_ffitype)
- self.after()
return x
def get_unsigned(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.ULONG)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.ULONG)
def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
# the same comment as get_signed apply
restype = w_ffitype.get_ffitype()
- self.before()
call = self.func.call
if restype is libffi.types.uint:
assert not libffi.IS_32_BIT
@@ -266,57 +247,35 @@
x = rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
else:
raise self.error(w_ffitype)
- self.after()
return x
def get_pointer(self, w_ffitype):
- self.before()
ptrres = self.func.call(self.argchain, rffi.VOIDP)
- self.after()
return rffi.cast(rffi.ULONG, ptrres)
def get_char(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.UCHAR)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.UCHAR)
def get_unichar(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.WCHAR_T)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.WCHAR_T)
def get_float(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.DOUBLE)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.DOUBLE)
def get_singlefloat(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, rffi.FLOAT)
- self.after()
- return x
+ return self.func.call(self.argchain, rffi.FLOAT)
def get_struct(self, w_ffitype, w_structdescr):
- self.before()
addr = self.func.call(self.argchain, rffi.LONG, is_struct=True)
- self.after()
return w_structdescr.fromaddress(self.space, addr)
def get_struct_rawffi(self, w_ffitype, w_structdescr):
- self.before()
uintval = self.func.call(self.argchain, rffi.ULONG, is_struct=True)
- self.after()
return w_structdescr.fromaddress(self.space, uintval)
def get_void(self, w_ffitype):
- self.before()
- x = self.func.call(self.argchain, lltype.Void)
- self.after()
- return x
+ return self.func.call(self.argchain, lltype.Void)
def unpack_argtypes(space, w_argtypes, w_restype):
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
@@ -18,7 +18,6 @@
from rpython.rlib.rarithmetic import intmask, r_uint
from pypy.module._rawffi.buffer import RawFFIBuffer
from pypy.module._rawffi.tracker import tracker
-from pypy.module._rawffi import lasterror
TYPEMAP = {
# XXX A mess with unsigned/signed/normal chars :-/
@@ -496,14 +495,10 @@
try:
if self.resshape is not None:
result = self.resshape.allocate(space, 1, autofree=True)
- lasterror.restore_last_error(space)
self.ptr.call(args_ll, result.ll_buffer)
- lasterror.save_last_error(space)
return space.wrap(result)
else:
- lasterror.restore_last_error(space)
self.ptr.call(args_ll, lltype.nullptr(rffi.VOIDP.TO))
- lasterror.save_last_error(space)
return space.w_None
except StackCheckError, e:
raise OperationError(space.w_ValueError, space.wrap(e.message))
@@ -613,17 +608,19 @@
return space.wrap(W_CDLL(space, name, cdll))
def get_errno(space):
- return space.wrap(rposix.get_errno())
+ return space.wrap(rposix.get_saved_errno())
def set_errno(space, w_errno):
- rposix.set_errno(space.int_w(w_errno))
+ rposix.set_saved_errno(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(lasterror.fetch_last_error(space))
+ return space.wrap(rwin32.GetLastError_saved())
@unwrap_spec(error=int)
def set_last_error(space, error):
- lasterror.store_last_error(space, error)
+ rwin32.SetLastError_saved(error)
else:
# always have at least a dummy version of these functions
# (https://bugs.pypy.org/issue1242)
diff --git a/pypy/module/_rawffi/lasterror.py b/pypy/module/_rawffi/lasterror.py
deleted file mode 100644
--- a/pypy/module/_rawffi/lasterror.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# For Windows only.
-# https://bitbucket.org/pypy/pypy/issue/1944/ctypes-on-windows-getlasterror
-
-import os
-
-_MS_WINDOWS = os.name == "nt"
-
-
-if _MS_WINDOWS:
- from rpython.rlib import rwin32
- from pypy.interpreter.executioncontext import ExecutionContext
-
-
- ExecutionContext._rawffi_last_error = 0
-
- def fetch_last_error(space):
- ec = space.getexecutioncontext()
- return ec._rawffi_last_error
-
- def store_last_error(space, last_error):
- ec = space.getexecutioncontext()
- ec._rawffi_last_error = last_error
-
- def restore_last_error(space):
- ec = space.getexecutioncontext()
- lasterror = ec._rawffi_last_error
- rwin32.SetLastError(lasterror)
-
- def save_last_error(space):
- lasterror = rwin32.GetLastError()
- ec = space.getexecutioncontext()
- ec._rawffi_last_error = lasterror
-
-else:
-
- def restore_last_error(space):
- pass
-
- def save_last_error(space):
- pass
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -9,7 +9,7 @@
PyObject, PyObjectP, make_ref, from_ref, Py_DecRef, borrow_from)
from pypy.module.cpyext.state import State
from pypy.module.cpyext.import_ import PyImport_Import
-from rpython.rlib.rposix import get_errno
+from rpython.rlib import rposix, jit
@cpython_api([PyObject, PyObject], lltype.Void)
def PyErr_SetObject(space, w_type, w_value):
@@ -159,6 +159,7 @@
PyErr_SetFromErrnoWithFilenameObject(space, w_type, filename)
@cpython_api([PyObject, PyObject], PyObject)
[email protected]_look_inside # direct use of _get_errno()
def PyErr_SetFromErrnoWithFilenameObject(space, w_type, w_value):
"""Similar to PyErr_SetFromErrno(), with the additional behavior that if
w_value is not NULL, it is passed to the constructor of type as a
@@ -166,7 +167,7 @@
this is used to define the filename attribute of the exception instance.
Return value: always NULL."""
# XXX Doesn't actually do anything with PyErr_CheckSignals.
- errno = get_errno()
+ errno = rffi.cast(lltype.Signed, rposix._get_errno())
msg = os.strerror(errno)
if w_value:
w_error = space.call_function(w_type,
diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py
--- a/pypy/module/cpyext/pystrtod.py
+++ b/pypy/module/cpyext/pystrtod.py
@@ -4,12 +4,13 @@
from pypy.module.cpyext.pyobject import PyObject
from rpython.rlib import rdtoa
from rpython.rlib import rfloat
-from rpython.rlib import rposix
+from rpython.rlib import rposix, jit
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.lltypesystem import rffi
@cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0)
[email protected]_look_inside # direct use of _get_errno()
def PyOS_string_to_double(space, s, endptr, w_overflow_exception):
"""Convert a string s to a double, raising a Python
exception on failure. The set of accepted strings corresponds to
@@ -52,8 +53,9 @@
raise OperationError(
space.w_ValueError,
space.wrap('invalid input at position %s' % endpos))
- if rposix.get_errno() == errno.ERANGE:
- rposix.set_errno(0)
+ err = rffi.cast(lltype.Signed, rposix._get_errno())
+ if err == errno.ERANGE:
+ rposix._set_errno(rffi.cast(rffi.INT, 0))
if w_overflow_exception is None:
if result > 0:
return rfloat.INFINITY
diff --git a/pypy/module/fcntl/interp_fcntl.py
b/pypy/module/fcntl/interp_fcntl.py
--- a/pypy/module/fcntl/interp_fcntl.py
+++ b/pypy/module/fcntl/interp_fcntl.py
@@ -55,22 +55,30 @@
constants[name] = value
locals().update(constants)
-def external(name, args, result):
- return rffi.llexternal(name, args, result,
compilation_info=CConfig._compilation_info_)
+def external(name, args, result, **kwds):
+ return rffi.llexternal(name, args, result,
+ compilation_info=CConfig._compilation_info_,
+ **kwds)
_flock = lltype.Ptr(cConfig.flock)
-fcntl_int = external('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT)
-fcntl_str = external('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT)
-fcntl_flock = external('fcntl', [rffi.INT, rffi.INT, _flock], rffi.INT)
-ioctl_int = external('ioctl', [rffi.INT, rffi.UINT, rffi.INT], rffi.INT)
-ioctl_str = external('ioctl', [rffi.INT, rffi.UINT, rffi.CCHARP], rffi.INT)
+fcntl_int = external('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+fcntl_str = external('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+fcntl_flock = external('fcntl', [rffi.INT, rffi.INT, _flock], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ioctl_int = external('ioctl', [rffi.INT, rffi.UINT, rffi.INT], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ioctl_str = external('ioctl', [rffi.INT, rffi.UINT, rffi.CCHARP], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
has_flock = cConfig.has_flock
if has_flock:
- c_flock = external('flock', [rffi.INT, rffi.INT], rffi.INT)
+ c_flock = external('flock', [rffi.INT, rffi.INT], rffi.INT,
+ save_err=rffi.RFFI_SAVE_ERRNO)
def _get_error(space, funcname):
- errno = rposix.get_errno()
+ errno = rposix.get_saved_errno()
return wrap_oserror(space, OSError(errno, funcname),
exception_name = 'w_IOError')
diff --git a/pypy/module/micronumpy/test/test_zjit.py
b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -123,10 +123,9 @@
assert result == 3 ** 2
self.check_trace_count(1)
self.check_simple_loop({
- 'call': 1,
+ 'call': 2, # ccall_pow / _ll_1_threadlocalref_get(rpy_errno)
'float_eq': 2,
'float_mul': 2,
- 'getarrayitem_raw': 1, # read the errno
'guard_false': 2,
'guard_not_invalidated': 1,
'guard_true': 2,
@@ -136,7 +135,6 @@
'jump': 1,
'raw_load': 1,
'raw_store': 1,
- 'setarrayitem_raw': 1, # write the errno
})
def define_pow_int():
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
@@ -200,14 +200,11 @@
assert res == 8.0 * 300
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id('cfficall', """
- setarrayitem_raw(i69, 0, i95, descr=<ArrayS 4>) # write 'errno'
p96 = force_token()
setfield_gc(p0, p96, descr=<FieldP
pypy.interpreter.pyframe.PyFrame.vable_token .>)
- f97 = call_release_gil(i59, 1.0, 3, descr=<Callf 8 fi EF=6 OS=62>)
+ f97 = call_release_gil(27, i59, 1.0, 3, descr=<Callf 8 fi EF=6
OS=62>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
- i98 = getarrayitem_raw(i69, 0, descr=<ArrayS 4>) # read 'errno'
- setfield_gc(p65, i98, descr=<FieldS
pypy.interpreter.executioncontext.ExecutionContext.inst__cffi_saved_errno .>)
""", ignore_ops=['guard_not_invalidated'])
def test_cffi_call_guard_not_forced_fails(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py
b/pypy/module/pypyjit/test_pypy_c/test_thread.py
--- a/pypy/module/pypyjit/test_pypy_c/test_thread.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -64,7 +64,7 @@
guard_true(i56, descr=...)
p57 = force_token()
setfield_gc(p0, p57, descr=<FieldP
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
- i58 = call_release_gil(_, i37, 1, descr=<Calli 4 ii EF=6>)
+ i58 = call_release_gil(0, _, i37, 1, descr=<Calli 4 ii EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
i59 = int_is_true(i58)
@@ -72,14 +72,14 @@
i60 = int_sub(i44, 1)
p62 = force_token()
setfield_gc(p0, p62, descr=<FieldP
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
- i63 = call_release_gil(_, i37, 0, descr=<Calli 4 ii EF=6>)
+ i63 = call_release_gil(0, _, i37, 0, descr=<Calli 4 ii EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
i64 = int_is_true(i63)
guard_false(i64, descr=...)
p65 = force_token()
setfield_gc(p0, p65, descr=<FieldP
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
- call_release_gil(_, i37, descr=<Callv 0 i EF=6>)
+ call_release_gil(0, _, i37, descr=<Callv 0 i EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
guard_not_invalidated(descr=...)
diff --git a/pypy/module/select/interp_epoll.py
b/pypy/module/select/interp_epoll.py
--- a/pypy/module/select/interp_epoll.py
+++ b/pypy/module/select/interp_epoll.py
@@ -4,12 +4,13 @@
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.error import OperationError, exception_from_errno, oefmt
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.error import exception_from_saved_errno
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.tool import rffi_platform
from rpython.rlib._rsocket_rffi import socketclose, FD_SETSIZE
-from rpython.rlib.rposix import get_errno
+from rpython.rlib.rposix import get_saved_errno
from rpython.rlib.rarithmetic import intmask
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -53,19 +54,22 @@
EPOLL_CTL_DEL = cconfig["EPOLL_CTL_DEL"]
epoll_create = rffi.llexternal(
- "epoll_create", [rffi.INT], rffi.INT, compilation_info=eci
+ "epoll_create", [rffi.INT], rffi.INT, compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
epoll_ctl = rffi.llexternal(
"epoll_ctl",
[rffi.INT, rffi.INT, rffi.INT, lltype.Ptr(epoll_event)],
rffi.INT,
- compilation_info=eci
+ compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
epoll_wait = rffi.llexternal(
"epoll_wait",
[rffi.INT, rffi.CArrayPtr(epoll_event), rffi.INT, rffi.INT],
rffi.INT,
compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
@@ -82,7 +86,7 @@
"sizehint must be greater than zero, got %d", sizehint)
epfd = epoll_create(sizehint)
if epfd < 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
return space.wrap(W_Epoll(space, epfd))
@@ -114,10 +118,10 @@
rffi.setintfield(ev.c_data, 'c_fd', fd)
result = epoll_ctl(self.epfd, ctl, fd, ev)
- if ignore_ebadf and get_errno() == errno.EBADF:
+ if ignore_ebadf and get_saved_errno() == errno.EBADF:
result = 0
if result < 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
def descr_get_closed(self, space):
return space.wrap(self.get_closed())
@@ -160,7 +164,7 @@
with lltype.scoped_alloc(rffi.CArray(epoll_event), maxevents) as evs:
nfds = epoll_wait(self.epfd, evs, maxevents, int(timeout))
if nfds < 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
elist_w = [None] * nfds
for i in xrange(nfds):
diff --git a/pypy/module/select/interp_kqueue.py
b/pypy/module/select/interp_kqueue.py
--- a/pypy/module/select/interp_kqueue.py
+++ b/pypy/module/select/interp_kqueue.py
@@ -1,8 +1,9 @@
from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError, exception_from_errno, oefmt
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.error import exception_from_saved_errno
from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
from pypy.interpreter.typedef import TypeDef, generic_new_descr, GetSetProperty
-from rpython.rlib._rsocket_rffi import socketclose
+from rpython.rlib._rsocket_rffi import socketclose_no_errno
from rpython.rlib.rarithmetic import r_uint
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rtyper.tool import rffi_platform
@@ -86,7 +87,8 @@
"kqueue",
[],
rffi.INT,
- compilation_info=eci
+ compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
syscall_kevent = rffi.llexternal(
@@ -99,7 +101,8 @@
lltype.Ptr(timespec)
],
rffi.INT,
- compilation_info=eci
+ compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_ERRNO
)
@@ -110,7 +113,7 @@
def descr__new__(space, w_subtype):
kqfd = syscall_kqueue()
if kqfd < 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space, space.w_IOError)
return space.wrap(W_Kqueue(space, kqfd))
@unwrap_spec(fd=int)
@@ -127,7 +130,7 @@
if not self.get_closed():
kqfd = self.kqfd
self.kqfd = -1
- socketclose(kqfd)
+ socketclose_no_errno(kqfd)
def check_closed(self, space):
if self.get_closed():
@@ -198,7 +201,7 @@
max_events,
ptimeout)
if nfds < 0:
- raise exception_from_errno(space, space.w_IOError)
+ raise exception_from_saved_errno(space,
space.w_IOError)
else:
elist_w = [None] * nfds
for i in xrange(nfds):
diff --git a/pypy/module/signal/interp_signal.py
b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -5,7 +5,7 @@
import os
import errno
-from pypy.interpreter.error import OperationError, exception_from_errno
+from pypy.interpreter.error import OperationError, exception_from_saved_errno
from pypy.interpreter.executioncontext import (AsyncAction, AbstractActionFlag,
PeriodicAsyncAction)
from pypy.interpreter.gateway import unwrap_spec
@@ -258,7 +258,7 @@
def siginterrupt(space, signum, flag):
check_signum_in_range(space, signum)
if rffi.cast(lltype.Signed, c_siginterrupt(signum, flag)) < 0:
- errno = rposix.get_errno()
+ errno = rposix.get_saved_errno()
raise OperationError(space.w_RuntimeError, space.wrap(errno))
@@ -311,7 +311,7 @@
ret = c_setitimer(which, new, old)
if ret != 0:
- raise exception_from_errno(space, get_itimer_error(space))
+ raise exception_from_saved_errno(space,
get_itimer_error(space))
return itimer_retval(space, old[0])
diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -7,12 +7,11 @@
# all but one will be blocked. The other threads get a chance to run
# from time to time, using the periodic action GILReleaseAction.
-from rpython.rlib import rthread, rgil, rwin32
+from rpython.rlib import rthread, rgil
from pypy.module.thread.error import wrap_thread_error
from pypy.interpreter.executioncontext import PeriodicAsyncAction
from pypy.module.thread.threadlocals import OSThreadLocals
from rpython.rlib.objectmodel import invoke_around_extcall
-from rpython.rlib.rposix import get_errno, set_errno
class GILThreadLocals(OSThreadLocals):
"""A version of OSThreadLocals that enforces a GIL."""
@@ -75,16 +74,9 @@
before_external_call._dont_reach_me_in_del_ = True
def after_external_call():
- e = get_errno()
- e2 = 0
- if rwin32.WIN32:
- e2 = rwin32.GetLastError()
rgil.gil_acquire()
rthread.gc_thread_run()
after_thread_switch()
- if rwin32.WIN32:
- rwin32.SetLastError(e2)
- set_errno(e)
after_external_call._gctransformer_hint_cannot_collect_ = True
after_external_call._dont_reach_me_in_del_ = True
diff --git a/pypy/module/thread/threadlocals.py
b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -17,7 +17,8 @@
"NOT_RPYTHON"
self._valuedict = {} # {thread_ident: ExecutionContext()}
self._cleanup_()
- self.raw_thread_local = rthread.ThreadLocalReference(ExecutionContext)
+ self.raw_thread_local = rthread.ThreadLocalReference(ExecutionContext,
+
loop_invariant=True)
def _cleanup_(self):
self._valuedict.clear()
diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -62,7 +62,8 @@
_setCtrlHandlerRoutine = rffi.llexternal(
'pypy_timemodule_setCtrlHandler',
[rwin32.HANDLE], rwin32.BOOL,
- compilation_info=eci)
+ compilation_info=eci,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
class GlobalState:
def __init__(self):
@@ -79,8 +80,8 @@
except WindowsError, e:
raise wrap_windowserror(space, e)
if not _setCtrlHandlerRoutine(globalState.interrupt_event):
- raise wrap_windowserror(
- space, rwin32.lastWindowsError("SetConsoleCtrlHandler"))
+ raise wrap_windowserror(space,
+ rwin32.lastSavedWindowsError("SetConsoleCtrlHandler"))
globalState = GlobalState()
@@ -142,7 +143,7 @@
setattr(cConfig, k, v)
cConfig.tm.__name__ = "_tm"
-def external(name, args, result, eci=CConfig._compilation_info_):
+def external(name, args, result, eci=CConfig._compilation_info_, **kwds):
if _WIN and rffi.sizeof(rffi.TIME_T) == 8:
# Recent Microsoft compilers use 64bit time_t and
# the corresponding functions are named differently
@@ -152,7 +153,8 @@
return rffi.llexternal(name, args, result,
compilation_info=eci,
calling_conv=calling_conv,
- releasegil=False)
+ releasegil=False,
+ **kwds)
if _POSIX:
cConfig.timeval.__name__ = "_timeval"
@@ -169,10 +171,12 @@
c_clock = external('clock', [rffi.TIME_TP], clock_t)
c_time = external('time', [rffi.TIME_TP], rffi.TIME_T)
c_ctime = external('ctime', [rffi.TIME_TP], rffi.CCHARP)
-c_gmtime = external('gmtime', [rffi.TIME_TP], TM_P)
+c_gmtime = external('gmtime', [rffi.TIME_TP], TM_P,
+ save_err=rffi.RFFI_SAVE_ERRNO)
c_mktime = external('mktime', [TM_P], rffi.TIME_T)
c_asctime = external('asctime', [TM_P], rffi.CCHARP)
-c_localtime = external('localtime', [rffi.TIME_TP], TM_P)
+c_localtime = external('localtime', [rffi.TIME_TP], TM_P,
+ save_err=rffi.RFFI_SAVE_ERRNO)
if _POSIX:
c_tzset = external('tzset', [], lltype.Void)
if _WIN:
@@ -304,7 +308,7 @@
_set_module_object(space, 'altzone', space.wrap(altzone))
def _get_error_msg():
- errno = rposix.get_errno()
+ errno = rposix.get_saved_errno()
return os.strerror(errno)
if sys.platform != 'win32':
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
@@ -11,6 +11,8 @@
from rpython.jit.backend.arm.helper.assembler import saved_registers
from rpython.jit.backend.arm.helper.regalloc import check_imm_arg
from rpython.jit.backend.arm.codebuilder import OverwritingBuilder
+from rpython.jit.backend.llsupport import llerrno
+from rpython.rtyper.lltypesystem import rffi
class ARMCallbuilder(AbstractCallBuilder):
@@ -172,6 +174,41 @@
self.mc.LSL_ri(resloc.value, resloc.value, 16)
self.mc.ASR_ri(resloc.value, resloc.value, 16)
+ 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
+ # 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)
+ 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)
+ self.mc.LDR_ri(r.ip.value, r.r9.value, p_errno)
+ self.mc.LDR_ri(r.r9.value, r.r9.value, rpy_errno)
+ self.mc.STR_ri(r.r9.value, r.ip.value)
+ elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
+ # Same, but write zero.
+ 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)
+ self.mc.LDR_ri(r.ip.value, r.r9.value, p_errno)
+ self.mc.MOV_ri(r.r9.value, 0)
+ self.mc.STR_ri(r.r9.value, r.ip.value)
+
+ 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
+ # are unused here, and registers r2-r3 never contain anything
+ # after the call.
+ 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)
+ self.mc.LDR_ri(r.ip.value, r.r3.value, p_errno)
+ self.mc.LDR_ri(r.ip.value, r.ip.value, 0)
+ self.mc.STR_ri(r.ip.value, r.r3.value, rpy_errno)
class SoftFloatCallBuilder(ARMCallbuilder):
diff --git a/rpython/jit/backend/arm/opassembler.py
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -403,7 +403,9 @@
# args = [resloc, size, sign, args...]
from rpython.jit.backend.llsupport.descr import CallDescr
- cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3],
arglocs[4:], arglocs[0])
+ func_index = 3 + is_call_release_gil
+ cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[func_index],
+ arglocs[func_index+1:], arglocs[0])
descr = op.getdescr()
assert isinstance(descr, CallDescr)
@@ -418,7 +420,9 @@
cb.ressign = signloc.value
if is_call_release_gil:
- cb.emit_call_release_gil()
+ saveerrloc = arglocs[3]
+ assert saveerrloc.is_imm()
+ cb.emit_call_release_gil(saveerrloc.value)
else:
cb.emit()
return fcond
@@ -1286,9 +1290,13 @@
return fcond
def emit_opx_threadlocalref_get(self, op, arglocs, regalloc, fcond):
- ofs0, res = arglocs
- assert ofs0.is_imm()
+ ofs_loc, size_loc, sign_loc, res_loc = arglocs
+ assert ofs_loc.is_imm()
+ assert size_loc.is_imm()
+ assert sign_loc.is_imm()
ofs = self.saved_threadlocal_addr
- self.load_reg(self.mc, res, r.sp, ofs)
- self.load_reg(self.mc, res, res, ofs0.value)
+ self.load_reg(self.mc, res_loc, r.sp, ofs)
+ scale = get_scale(size_loc.value)
+ signed = (sign_loc.value != 0)
+ self._load_from_mem(res_loc, res_loc, ofs_loc, scale, signed, fcond)
return fcond
diff --git a/rpython/jit/backend/arm/regalloc.py
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -573,11 +573,12 @@
# ...
return self._prepare_call(op)
- def _prepare_call(self, op, force_store=[], save_all_regs=False):
+ def _prepare_call(self, op, force_store=[], save_all_regs=False,
+ first_arg_index=1):
args = [None] * (op.numargs() + 3)
calldescr = op.getdescr()
assert isinstance(calldescr, CallDescr)
- assert len(calldescr.arg_classes) == op.numargs() - 1
+ assert len(calldescr.arg_classes) == op.numargs() - first_arg_index
for i in range(op.numargs()):
args[i + 3] = self.loc(op.getarg(i))
@@ -626,9 +627,12 @@
return [loc0, res]
def _prepare_threadlocalref_get(self, op, fcond):
- ofs0 = imm(op.getarg(1).getint())
- res = self.force_allocate_reg(op.result)
- return [ofs0, res]
+ ofs_loc = imm(op.getarg(1).getint())
+ calldescr = op.getdescr()
+ size_loc = imm(calldescr.get_result_size())
+ sign_loc = imm(calldescr.is_result_signed())
+ res_loc = self.force_allocate_reg(op.result)
+ return [ofs_loc, size_loc, sign_loc, res_loc]
def _prepare_guard(self, op, args=None):
if args is None:
@@ -1235,7 +1239,10 @@
def prepare_guard_call_may_force(self, op, guard_op, fcond):
args = self._prepare_call(op, save_all_regs=True)
return self._prepare_guard(guard_op, args)
- prepare_guard_call_release_gil = prepare_guard_call_may_force
+
+ def prepare_guard_call_release_gil(self, op, guard_op, fcond):
+ args = self._prepare_call(op, save_all_regs=True, first_arg_index=2)
+ return self._prepare_guard(guard_op, args)
def prepare_guard_call_assembler(self, op, guard_op, fcond):
locs = self.locs_for_call_assembler(op, guard_op)
diff --git a/rpython/jit/backend/llgraph/runner.py
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -935,7 +935,7 @@
del self.force_guard_op
return res
- def execute_call_release_gil(self, descr, func, *args):
+ def execute_call_release_gil(self, descr, saveerr, func, *args):
if hasattr(descr, '_original_func_'):
func = descr._original_func_ # see pyjitpl.py
# we want to call the function that does the aroundstate
diff --git a/rpython/jit/backend/llsupport/callbuilder.py
b/rpython/jit/backend/llsupport/callbuilder.py
--- a/rpython/jit/backend/llsupport/callbuilder.py
+++ b/rpython/jit/backend/llsupport/callbuilder.py
@@ -42,16 +42,18 @@
self.pop_gcmap()
self.load_result()
- def emit_call_release_gil(self):
+ def emit_call_release_gil(self, save_err):
"""Emit a CALL_RELEASE_GIL, including calls to releasegil_addr
- and reacqgil_addr."""
+ and reacqgil_addr. 'save_err' is a combination of rffi.RFFI_*ERR*."""
fastgil = rffi.cast(lltype.Signed, rgil.gil_fetch_fastgil())
self.select_call_release_gil_mode()
self.prepare_arguments()
self.push_gcmap_for_call_release_gil()
self.call_releasegil_addr_and_move_real_arguments(fastgil)
+ self.write_real_errno(save_err)
self.emit_raw_call()
self.restore_stack_pointer()
+ self.read_real_errno(save_err)
self.move_real_result_and_call_reacqgil_addr(fastgil)
self.pop_gcmap()
self.load_result()
@@ -62,6 +64,12 @@
def move_real_result_and_call_reacqgil_addr(self, fastgil):
raise NotImplementedError
+ def write_real_errno(self, save_err):
+ raise NotImplementedError
+
+ def read_real_errno(self, save_err):
+ raise NotImplementedError
+
def select_call_release_gil_mode(self):
"""Overridden in CallBuilder64"""
self.is_call_release_gil = True
diff --git a/rpython/jit/backend/llsupport/llerrno.py
b/rpython/jit/backend/llsupport/llerrno.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/llerrno.py
@@ -0,0 +1,59 @@
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.jit.backend.llsupport.symbolic import WORD
+
+
+def get_debug_saved_errno(cpu):
+ return cpu._debug_errno_container[3]
+
+def set_debug_saved_errno(cpu, nerrno):
+ assert nerrno >= 0
+ cpu._debug_errno_container[3] = nerrno
+
+def get_rpy_errno_offset(cpu):
+ if cpu.translate_support_code:
+ from rpython.rlib import rthread
+ return rthread.tlfield_rpy_errno.getoffset()
+ 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=['''
+ #include <errno.h>
+ RPY_EXPORTED long fetch_addr_errno(void) {
+ return (long)(&errno);
+ }
+ '''])
+ func1_ptr = rffi.llexternal('fetch_addr_errno', [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ return func1_ptr()
+
+def get_p_errno_offset(cpu):
+ if cpu.translate_support_code:
+ from rpython.rlib import rthread
+ return rthread.tlfield_p_errno.getoffset()
+ else:
+ # fetch the real address of errno (in this thread), and store it
+ # at offset 2 in the _debug_errno_container
+ if cpu._debug_errno_container[2] == 0:
+ addr_errno = _fetch_addr_errno()
+ assert addr_errno != 0
+ cpu._debug_errno_container[2] = addr_errno
+ return 2 * WORD
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
@@ -62,6 +62,9 @@
self.floatarraydescr = ArrayDescr(ad.basesize, ad.itemsize,
ad.lendescr, FLAG_FLOAT)
self.setup()
+ self._debug_errno_container = lltype.malloc(
+ rffi.CArray(lltype.Signed), 5, flavor='raw', zero=True,
+ track_allocation=False)
def getarraydescr_for_frame(self, type):
if type == history.FLOAT:
@@ -222,7 +225,8 @@
# as arguments, and it returns the (possibly reallocated) jitframe.
# The backend can optimize OS_THREADLOCALREF_GET calls to return a
# field of this threadlocal_addr, but only if 'translate_support_code':
- # in untranslated tests, threadlocal_addr is a dummy NULL.
+ # in untranslated tests, threadlocal_addr is a dummy container
+ # for errno tests only.
FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
llmemory.Address],
llmemory.GCREF))
@@ -259,7 +263,8 @@
ll_threadlocal_addr = llop.threadlocalref_addr(
llmemory.Address)
else:
- ll_threadlocal_addr = llmemory.NULL
+ ll_threadlocal_addr = rffi.cast(llmemory.Address,
+ self._debug_errno_container)
llop.gc_writebarrier(lltype.Void, ll_frame)
ll_frame = func(ll_frame, ll_threadlocal_addr)
finally:
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
@@ -2,6 +2,8 @@
from rpython.rlib.jit import dont_look_inside
from rpython.rlib.objectmodel import invoke_around_extcall
from rpython.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rlib import rposix
from rpython.rtyper.annlowlevel import llhelper
@@ -95,3 +97,37 @@
def test_close_stack(self):
self.run('close_stack')
assert 'call_release_gil' in
udir.join('TestCompileFramework.log').read()
+
+ def define_get_set_errno(self):
+ eci = ExternalCompilationInfo(
+ post_include_bits=[r'''
+ #include <errno.h>
+ static int test_get_set_errno(void) {
+ int r = errno;
+ //fprintf(stderr, "read saved errno: %d\n", r);
+ errno = 42;
+ return r;
+ }
+ '''])
+
+ c_test = rffi.llexternal('test_get_set_errno', [], rffi.INT,
+ compilation_info=eci,
+ save_err=rffi.RFFI_FULL_ERRNO)
+
+ def before(n, x):
+ return (n, None, None, None, None, None,
+ None, None, None, None, None, None)
+ #
+ def f(n, x, *args):
+ rposix.set_saved_errno(24)
+ result1 = c_test()
+ result2 = rposix.get_saved_errno()
+ assert result1 == 24
+ assert result2 == 42
+ n -= 1
+ return (n, x) + args
+ return before, f, None
+
+ def test_get_set_errno(self):
+ self.run('get_set_errno')
+ assert 'call_release_gil' in
udir.join('TestCompileFramework.log').read()
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py
b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -5,7 +5,7 @@
from rpython.rlib.jit import promote
from rpython.rlib import jit_hooks, rposix
from rpython.rlib.objectmodel import keepalive_until_here
-from rpython.rlib.rthread import ThreadLocalReference
+from rpython.rlib.rthread import ThreadLocalReference, ThreadLocalField
from rpython.jit.backend.detect_cpu import getcpuclass
from rpython.jit.backend.test.support import CCompiledMixin
from rpython.jit.codewriter.policy import StopAtXPolicy
@@ -128,7 +128,8 @@
class Foo(object):
pass
- t = ThreadLocalReference(Foo)
+ t = ThreadLocalReference(Foo, loop_invariant=True)
+ tf = ThreadLocalField(lltype.Char, "test_call_assembler_")
def change(newthing):
somewhere_else.frame.thing = newthing
@@ -156,6 +157,7 @@
frame.thing = Thing(nextval + 1)
i += 1
if t.get().nine != 9: raise ValueError
+ if ord(tf.getraw()) != 0x92: raise ValueError
return frame.thing.val
driver2 = JitDriver(greens = [], reds = ['n'])
@@ -181,6 +183,7 @@
foo = Foo()
foo.nine = value
t.set(foo)
+ tf.setraw("\x92")
return foo
def mainall(codeno, bound):
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
@@ -20,6 +20,7 @@
from rpython.rlib.rarithmetic import intmask, is_valid_int
from rpython.jit.backend.detect_cpu import autodetect
from rpython.jit.backend.llsupport import jitframe
+from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
IS_32_BIT = sys.maxint < 2**32
@@ -2512,7 +2513,7 @@
tok = BoxInt()
faildescr = BasicFailDescr(1)
ops = [
- ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i1], i2,
+ ResOperation(rop.CALL_RELEASE_GIL, [ConstInt(0), funcbox, i1], i2,
descr=calldescr),
ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
ResOperation(rop.FINISH, [i2], None, descr=BasicFinalDescr(0))
@@ -2570,7 +2571,8 @@
tok = BoxInt()
faildescr = BasicFailDescr(1)
ops = [
- ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i0, i1, i2, i3], None,
+ ResOperation(rop.CALL_RELEASE_GIL,
+ [ConstInt(0), funcbox, i0, i1, i2, i3], None,
descr=calldescr),
ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0))
@@ -2625,7 +2627,8 @@
for i in range(50):
i3 = BoxInt()
ops += [
- ResOperation(rop.CALL_RELEASE_GIL, [funcbox, i1, i2], i3,
+ ResOperation(rop.CALL_RELEASE_GIL,
+ [ConstInt(0), funcbox, i1, i2], i3,
descr=calldescr),
ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
]
@@ -2697,7 +2700,7 @@
assert 0, kind
#
ops = [
- ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3,
+ ResOperation(rop.CALL_RELEASE_GIL, [ConstInt(0), funcbox], b3,
descr=calldescr),
ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0))
@@ -2881,7 +2884,8 @@
loadcodes = ''.join(loadcodes)
print loadcodes
ops += [
- ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None,
+ ResOperation(rop.CALL_RELEASE_GIL,
+ [ConstInt(0)] + insideboxes, None,
descr=calldescr),
ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr),
ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0))
@@ -2916,6 +2920,310 @@
assert got == expected, '\n'.join(
['bad args, signature %r' % codes[1:]] + different_values)
+ def test_call_release_gil_save_errno(self):
+ 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")
+ eci = ExternalCompilationInfo(
+ separate_module_sources=['''
+ #include <errno.h>
+ static long f1(long a, long b, long c, long d,
+ long e, long f, long g) {
+ errno = 42;
+ return (a + 10*b + 100*c + 1000*d +
+ 10000*e + 100000*f + 1000000*g);
+ }
+ RPY_EXPORTED
+ long test_call_release_gil_save_errno(void) {
+ return (long)&f1;
+ }
+ '''])
+ fn_name = 'test_call_release_gil_save_errno'
+ getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ func1_adr = getter_ptr()
+ calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
+ types.slong)
+ #
+ for saveerr in [rffi.RFFI_ERR_NONE, rffi.RFFI_SAVE_ERRNO]:
+ 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_errno(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_errno(self.cpu)
+ print 'saveerr =', saveerr, ': got result =', result
+ #
+ if saveerr == rffi.RFFI_SAVE_ERRNO:
+ assert result == 42 # from the C code
+ else:
+ assert result == 24 # not touched
+ assert original_result == 3456789
+
+ def test_call_release_gil_readsaved_errno(self):
+ 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")
+ eci = ExternalCompilationInfo(
+ separate_module_sources=[r'''
+ #include <stdio.h>
+ #include <errno.h>
+ static long f1(long a, long b, long c, long d,
+ long e, long f, long g) {
+ long r = errno;
+ printf("read saved errno: %ld\n", r);
+ r += 100 * (a + 10*b + 100*c + 1000*d +
+ 10000*e + 100000*f + 1000000*g);
+ return r;
+ }
+ RPY_EXPORTED
+ long test_call_release_gil_readsaved_errno(void) {
+ return (long)&f1;
+ }
+ '''])
+ fn_name = 'test_call_release_gil_readsaved_errno'
+ getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ func1_adr = getter_ptr()
+ calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
+ types.slong)
+ #
+ for saveerr in [rffi.RFFI_READSAVED_ERRNO,
rffi.RFFI_ZERO_ERRNO_BEFORE]:
+ 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_errno(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_errno(self.cpu) == 24
+ #
+ if saveerr == rffi.RFFI_READSAVED_ERRNO:
+ assert result == 24 + 345678900
+ else:
+ assert result == 0 + 345678900
+
+ def test_call_release_gil_save_lasterror(self):
+ 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>
+ static long f1(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);
+ }
+ RPY_EXPORTED
+ long test_call_release_gil_save_lasterror(void) {
+ return (long)&f1;
+ }
+ '''])
+ fn_name = 'test_call_release_gil_save_lasterror'
+ getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ func1_adr = getter_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):
+ 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 <windows.h>
+ static long f1(long a, long b, long c, long d,
+ long e, long f, long g) {
+ long r = GetLastError();
+ printf("GetLastError() result: %ld\n", r);
+ printf("%ld %ld %ld %ld %ld %ld %ld\n", a,b,c,d,e,f,g);
+ r += 100 * (a + 10*b + 100*c + 1000*d +
+ 10000*e + 100000*f + 1000000*g);
+ return r;
+ }
+ RPY_EXPORTED
+ long test_call_release_gil_readsaved_lasterror(void) {
+ return (long)&f1;
+ }
+ '''])
+ fn_name = 'test_call_release_gil_readsaved_lasterror'
+ getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ func1_adr = getter_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_call_release_gil_err_all(self):
+ 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':
+ eci = ExternalCompilationInfo(
+ separate_module_sources=[r'''
+ #include <errno.h>
+ static long f1(long a, long b, long c, long d,
+ long e, long f, long g) {
+ long r = errno;
+ errno = 42;
+ r += 100 * (a + 10*b + 100*c + 1000*d +
+ 10000*e + 100000*f + 1000000*g);
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit