[pypy-commit] pypy errno-again: in-progress: move the errno reading code inside the llexternal functions,

arigo noreply at buildbot.pypy.org
Wed Jan 14 17:15:18 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: errno-again
Changeset: r75325:60d2fecaae5c
Date: 2015-01-14 17:14 +0100
http://bitbucket.org/pypy/pypy/changeset/60d2fecaae5c/

Log:	in-progress: move the errno reading code inside the llexternal
	functions, before we reacquire the GIL.

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/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1999,9 +1999,15 @@
                 or isinstance(RESTYPE, lltype.Ptr))
         c_offset, = op.args
         op1 = self.prepare_builtin_call(op, 'threadlocalref_get', [c_offset])
+        if c_offset.value.startswith('RPY_TLOFSLOOPINVARIANT_'):
+            effect = EffectInfo.EF_LOOPINVARIANT
+        elif c_offset.value.startswith('RPY_TLOFS_'):
+            effect = EffectInfo.EF_CANNOT_RAISE
+        else:
+            assert 0
         return self.handle_residual_call(op1,
             oopspecindex=EffectInfo.OS_THREADLOCALREF_GET,
-            extraeffect=EffectInfo.EF_LOOPINVARIANT)
+            extraeffect=effect)
 
 # ____________________________________________________________
 
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -89,26 +89,23 @@
     separate_module_sources=separate_module_sources,
 )
 
+# Direct getters/setters, don't use directly!
 _get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
                                          CConstantErrno, sandboxsafe=True,
                                          _nowrapper=True, c_type='int')
-# the default wrapper for set_errno is not suitable for use in critical places
-# like around GIL handling logic, so we provide our own wrappers.
 
-def get_errno():
-    if jit.we_are_jitted():
-        from rpython.rlib import rthread
-        perrno = rthread.tlfield_p_errno.getraw()
-        return intmask(perrno[0])
-    return intmask(_get_errno())
+def get_saved_errno():
+    """Return the saved value of the errno.  This value is saved after a call
+    to an llexternal function with 'save_err & RFFI_ERRNO_AFTER != 0'."""
+    from rpython.rlib import rthread
+    return intmask(rthread.tlfield_rpy_errno.getraw())
 
-def set_errno(errno):
-    if jit.we_are_jitted():
-        from rpython.rlib import rthread
-        perrno = rthread.tlfield_p_errno.getraw()
-        perrno[0] = rffi.cast(INT, errno)
-        return
-    _set_errno(rffi.cast(INT, errno))
+def set_saved_errno(errno):
+    """Set the saved value of the errno.  This value will be used by a
+    following llexternal function with 'save_err & RFFI_ERRNO_BEFORE != 0'."""
+    from rpython.rlib import rthread
+    rthread.tlfield_rpy_errno.setraw(rffi.cast(INT, errno))
+
 
 if os.name == 'nt':
     is_valid_fd = jit.dont_look_inside(rffi.llexternal(
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 from rpython.translator import cdir
-import py
+import py, sys
 from rpython.rlib import jit, rgc
 from rpython.rlib.debug import ll_assert
 from rpython.rlib.objectmodel import we_are_translated, specialize
@@ -266,19 +266,23 @@
 
 # ____________________________________________________________
 #
-# Thread-locals.  Only for references that change "not too often" --
-# for now, the JIT compiles get() as a loop-invariant, so basically
-# don't change them.
+# Thread-locals.
 # KEEP THE REFERENCE ALIVE, THE GC DOES NOT FOLLOW THEM SO FAR!
 # We use _make_sure_does_not_move() to make sure the pointer will not move.
 
 
 class ThreadLocalField(object):
-    def __init__(self, FIELDTYPE, fieldname):
+    def __init__(self, FIELDTYPE, fieldname, loop_invariant=False):
         "NOT_RPYTHON: must be prebuilt"
         self.FIELDTYPE = FIELDTYPE
         self.fieldname = fieldname
-        offset = CDefinedIntSymbolic('RPY_TLOFS_%s' % self.fieldname,
+        self.loop_invariant = loop_invariant
+        if loop_invariant:
+            invariant = 'LOOPINVARIANT'
+        else:
+            invariant = ''
+        offset = CDefinedIntSymbolic('RPY_TLOFS%s_%s' % (invariant,
+                                                         self.fieldname),
                                      default='?')
         self.offset = offset
 
@@ -309,14 +313,15 @@
 class ThreadLocalReference(ThreadLocalField):
     _COUNT = 1
 
-    def __init__(self, Cls):
+    def __init__(self, Cls, loop_invariant=False):
         "NOT_RPYTHON: must be prebuilt"
         import thread
         self.Cls = Cls
         self.local = thread._local()      # <- NOT_RPYTHON
         unique_id = ThreadLocalReference._COUNT
         ThreadLocalReference._COUNT += 1
-        ThreadLocalField.__init__(self, lltype.Signed, 'tlref%d' % unique_id)
+        ThreadLocalField.__init__(self, lltype.Signed, 'tlref%d' % unique_id,
+                                  loop_invariant=loop_invariant)
         setraw = self.setraw
         offset = self.offset
 
@@ -350,8 +355,13 @@
         self.set = set
 
 
-tlfield_thread_ident = ThreadLocalField(lltype.Signed, "thread_ident")
-tlfield_p_errno = ThreadLocalField(rffi.CArrayPtr(rffi.INT), "p_errno")
+tlfield_thread_ident = ThreadLocalField(lltype.Signed, "thread_ident",
+                                        loop_invariant=True)
+tlfield_p_errno = ThreadLocalField(rffi.CArrayPtr(rffi.INT), "p_errno",
+                                   loop_invariant=True)
+tlfield_rpy_errno = ThreadLocalField(rffi.INT, "rpy_errno")
+if sys.platform == "win32":
+    tlfield_rpy_lasterror = ThreadLocalField(rwin32.DWORD, "rpy_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
@@ -123,16 +123,23 @@
     _SetLastError = winexternal('SetLastError', [DWORD], lltype.Void,
                                 _nowrapper=True, sandboxsafe=True)
 
-    @jit.dont_look_inside
-    def GetLastError():
+    def GetLastError_real():
         return rffi.cast(lltype.Signed, _GetLastError())
-    @jit.dont_look_inside
-    def SetLastError(err):
+
+    def SetLastError_real(err):
         _SetLastError(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()
+    def GetLastError_saved():
+        from rpython.rlib import rthread
+        return rffi.cast(lltype.Signed, rthread.tlfield_rpy_lasterror.getraw())
+
+    def SetLastError_saved(err):
+        from rpython.rlib import rthread
+        rthread.tlfield_rpy_lasterror.setraw(rffi.cast(DWORD, err))
+
+    # In tests, the first call to GetLastError_real() is always wrong,
+    # because error is hidden by operations in ll2ctypes.  Call it now.
+    GetLastError_real()
 
     GetModuleHandle = winexternal('GetModuleHandleA', [rffi.CCHARP], HMODULE)
     LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], HMODULE)
@@ -260,7 +267,7 @@
         return 'Windows Error %d' % (code,)
 
     def lastWindowsError(context="Windows Error"):
-        code = GetLastError()
+        code = GetLastError_saved()
         return WindowsError(code, context)
 
     def FAILED(hr):
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
@@ -59,12 +59,22 @@
         hop.exception_cannot_occur()
         return hop.inputconst(lltype.Bool, hop.s_result.const)
 
+RFFI_SAVE_ERRNO          = 1
+RFFI_READSAVED_ERRNO     = 2
+RFFI_FULL_ERRNO          = RFFI_SAVE_ERRNO | RFFI_READSAVED_ERRNO
+RFFI_SAVE_LASTERROR      = 4
+RFFI_READSAVED_LASTERROR = 8
+RFFI_FULL_LASTERROR      = RFFI_SAVE_LASTERROR | RFFI_READSAVED_LASTERROR
+RFFI_ERR_NONE            = 0
+RFFI_ERR_ALL             = RFFI_FULL_ERRNO | RFFI_FULL_LASTERROR
+
 def llexternal(name, args, result, _callable=None,
                compilation_info=ExternalCompilationInfo(),
                sandboxsafe=False, releasegil='auto',
                _nowrapper=False, calling_conv='c',
                elidable_function=False, macro=None,
-               random_effects_on_gcobjs='auto'):
+               random_effects_on_gcobjs='auto',
+               save_err=RFFI_ERR_NONE):
     """Build an external function that will invoke the C function 'name'
     with the given 'args' types and 'result' type.
 
@@ -141,9 +151,14 @@
         _callable.funcptr = funcptr
 
     if _nowrapper:
+        assert save_err == RFFI_ERR_NONE
         return funcptr
 
 
+    argnames = ', '.join(['a%d' % i for i in range(len(args))])
+    errno_before = (save_err & RFFI_READSAVED_ERRNO) != 0
+    errno_after = (save_err & RFFI_SAVE_ERRNO) != 0
+
     if invoke_around_handlers:
         # The around-handlers are releasing the GIL in a threaded pypy.
         # We need tons of care to ensure that no GC operation and no
@@ -154,13 +169,25 @@
         # neither '*args' nor the GC objects originally passed in as
         # argument to wrapper(), if any (e.g. RPython strings).
 
-        argnames = ', '.join(['a%d' % i for i in range(len(args))])
         source = py.code.Source("""
+            if %(errno_before)s or %(errno_after)s:
+                from rpython.rlib import rposix, rthread
+
             def call_external_function(%(argnames)s):
                 before = aroundstate.before
                 if before: before()
                 # NB. it is essential that no exception checking occurs here!
+                #
+                # restore errno from its saved value
+                if %(errno_before)s:
+                    rposix._set_errno(rthread.tlfield_rpy_errno.getraw())
+                #
                 res = funcptr(%(argnames)s)
+                #
+                # save errno away
+                if %(errno_after)s:
+                    rthread.tlfield_rpy_errno.setraw(rposix._get_errno())
+                #
                 after = aroundstate.after
                 if after: after()
                 return res
@@ -188,15 +215,27 @@
     else:
         # if we don't have to invoke the aroundstate, we can just call
         # the low-level function pointer carelessly
-        if macro is None:
+        if macro is None and save_err == RFFI_ERR_NONE:
             call_external_function = funcptr
         else:
             # ...well, unless it's a macro, in which case we still have
             # to hide it from the JIT...
-            argnames = ', '.join(['a%d' % i for i in range(len(args))])
             source = py.code.Source("""
+                if %(errno_before)s or %(errno_after)s:
+                    from rpython.rlib import rposix, rthread
+
                 def call_external_function(%(argnames)s):
-                    return funcptr(%(argnames)s)
+                    # restore errno from its saved value
+                    if %(errno_before)s:
+                        rposix._set_errno(rthread.tlfield_rpy_errno.getraw())
+                    #
+                    res = funcptr(%(argnames)s)
+                    #
+                    # save errno away
+                    if %(errno_after)s:
+                        rthread.tlfield_rpy_errno.setraw(rposix._get_errno())
+                    #
+                    return res
             """ % locals())
             miniglobals = {'funcptr':     funcptr,
                            '__name__':    __name__,
diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py
--- a/rpython/rtyper/module/ll_os.py
+++ b/rpython/rtyper/module/ll_os.py
@@ -187,11 +187,12 @@
 
     # a simple, yet useful factory
     def extdef_for_os_function_returning_int(self, name, **kwds):
-        c_func = self.llexternal(name, [], rffi.INT, **kwds)
+        c_func = self.llexternal(name, [], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO, **kwds)
         def c_func_llimpl():
             res = rffi.cast(rffi.SIGNED, c_func())
             if res == -1:
-                raise OSError(rposix.get_errno(), "%s failed" % name)
+                raise OSError(rposix.get_saved_errno(), "%s failed" % name)
             return res
         c_func_llimpl.func_name = name + '_llimpl'
 
@@ -199,11 +200,12 @@
                       export_name='ll_os.ll_os_' + name)
 
     def extdef_for_os_function_accepting_int(self, name, **kwds):
-        c_func = self.llexternal(name, [rffi.INT], rffi.INT, **kwds)
+        c_func = self.llexternal(name, [rffi.INT], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO, **kwds)
         def c_func_llimpl(arg):
             res = rffi.cast(rffi.SIGNED, c_func(arg))
             if res == -1:
-                raise OSError(rposix.get_errno(), "%s failed" % name)
+                raise OSError(rposix.get_saved_errno(), "%s failed" % name)
 
         c_func_llimpl.func_name = name + '_llimpl'
 
@@ -211,11 +213,12 @@
                       export_name='ll_os.ll_os_' + name)
 
     def extdef_for_os_function_accepting_2int(self, name, **kwds):
-        c_func = self.llexternal(name, [rffi.INT, rffi.INT], rffi.INT, **kwds)
+        c_func = self.llexternal(name, [rffi.INT, rffi.INT], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO, **kwds)
         def c_func_llimpl(arg, arg2):
             res = rffi.cast(rffi.SIGNED, c_func(arg, arg2))
             if res == -1:
-                raise OSError(rposix.get_errno(), "%s failed" % name)
+                raise OSError(rposix.get_saved_errno(), "%s failed" % name)
 
         c_func_llimpl.func_name = name + '_llimpl'
 
@@ -223,11 +226,12 @@
                       export_name='ll_os.ll_os_' + name)
 
     def extdef_for_os_function_accepting_0int(self, name, **kwds):
-        c_func = self.llexternal(name, [], rffi.INT, **kwds)
+        c_func = self.llexternal(name, [], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO, **kwds)
         def c_func_llimpl():
             res = rffi.cast(rffi.SIGNED, c_func())
             if res == -1:
-                raise OSError(rposix.get_errno(), "%s failed" % name)
+                raise OSError(rposix.get_saved_errno(), "%s failed" % name)
 
         c_func_llimpl.func_name = name + '_llimpl'
 
@@ -235,11 +239,12 @@
                       export_name='ll_os.ll_os_' + name)
 
     def extdef_for_os_function_int_to_int(self, name, **kwds):
-        c_func = self.llexternal(name, [rffi.INT], rffi.INT, **kwds)
+        c_func = self.llexternal(name, [rffi.INT], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO, **kwds)
         def c_func_llimpl(arg):
             res = rffi.cast(rffi.SIGNED, c_func(arg))
             if res == -1:
-                raise OSError(rposix.get_errno(), "%s failed" % name)
+                raise OSError(rposix.get_saved_errno(), "%s failed" % name)
             return res
 
         c_func_llimpl.func_name = name + '_llimpl'
@@ -251,13 +256,14 @@
     def register_os_execv(self):
         os_execv = self.llexternal(
             'execv',
-            [rffi.CCHARP, rffi.CCHARPP], rffi.INT)
+            [rffi.CCHARP, rffi.CCHARPP], rffi.INT,
+            save_err=rffi.RFFI_SAVE_ERRNO)
 
         def execv_llimpl(path, args):
             l_args = rffi.ll_liststr2charpp(args)
             os_execv(path, l_args)
             rffi.free_charpp(l_args)
-            raise OSError(rposix.get_errno(), "execv failed")
+            raise OSError(rposix.get_saved_errno(), "execv failed")
 
         return extdef([str0, [str0]], s_ImpossibleValue, llimpl=execv_llimpl,
                       export_name="ll_os.ll_os_execv")
@@ -267,7 +273,8 @@
     def register_os_execve(self):
         os_execve = self.llexternal(
             'execve',
-            [rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT)
+            [rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT,
+            save_err=rffi.RFFI_SAVE_ERRNO)
 
         def execve_llimpl(path, args, env):
             # XXX Check path, args, env for \0 and raise TypeErrors as
@@ -285,7 +292,7 @@
             rffi.free_charpp(l_env)
             rffi.free_charpp(l_args)
 
-            raise OSError(rposix.get_errno(), "execve failed")
+            raise OSError(rposix.get_saved_errno(), "execve failed")
 
         return extdef(
             [str0, [str0], {str0: str0}],
@@ -298,7 +305,8 @@
     def register_os_spawnv(self):
         os_spawnv = self.llexternal('spawnv',
                                     [rffi.INT, rffi.CCHARP, rffi.CCHARPP],
-                                    rffi.INT)
+                                    rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def spawnv_llimpl(mode, path, args):
             mode = rffi.cast(rffi.INT, mode)
@@ -306,7 +314,7 @@
             childpid = os_spawnv(mode, path, l_args)
             rffi.free_charpp(l_args)
             if childpid == -1:
-                raise OSError(rposix.get_errno(), "os_spawnv failed")
+                raise OSError(rposix.get_saved_errno(), "os_spawnv failed")
             return rffi.cast(lltype.Signed, childpid)
 
         return extdef([int, str0, [str0]], int, llimpl=spawnv_llimpl,
@@ -317,7 +325,8 @@
         os_spawnve = self.llexternal('spawnve',
                                      [rffi.INT, rffi.CCHARP, rffi.CCHARPP,
                                       rffi.CCHARPP],
-                                     rffi.INT)
+                                     rffi.INT,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
 
         def spawnve_llimpl(mode, path, args, env):
             envstrs = []
@@ -331,7 +340,7 @@
             rffi.free_charpp(l_env)
             rffi.free_charpp(l_args)
             if childpid == -1:
-                raise OSError(rposix.get_errno(), "os_spawnve failed")
+                raise OSError(rposix.get_saved_errno(), "os_spawnve failed")
             return rffi.cast(lltype.Signed, childpid)
 
         return extdef([int, str0, [str0], {str0: str0}], int,
@@ -341,13 +350,14 @@
     @registering(os.dup)
     def register_os_dup(self):
         os_dup = self.llexternal(UNDERSCORE_ON_WIN32 + 'dup',
-                                 [rffi.INT], rffi.INT)
+                                 [rffi.INT], rffi.INT,
+                                 save_err=rffi.RFFI_SAVE_ERRNO)
 
         def dup_llimpl(fd):
             rposix.validate_fd(fd)
             newfd = rffi.cast(lltype.Signed, os_dup(rffi.cast(rffi.INT, fd)))
             if newfd == -1:
-                raise OSError(rposix.get_errno(), "dup failed")
+                raise OSError(rposix.get_saved_errno(), "dup failed")
             return newfd
 
         return extdef([int], int, llimpl=dup_llimpl, export_name="ll_os.ll_os_dup")
@@ -355,26 +365,29 @@
     @registering(os.dup2)
     def register_os_dup2(self):
         os_dup2 = self.llexternal(UNDERSCORE_ON_WIN32 + 'dup2',
-                                  [rffi.INT, rffi.INT], rffi.INT)
+                                  [rffi.INT, rffi.INT], rffi.INT,
+                                  save_err=rffi.RFFI_SAVE_ERRNO)
 
         def dup2_llimpl(fd, newfd):
             rposix.validate_fd(fd)
             error = rffi.cast(lltype.Signed, os_dup2(rffi.cast(rffi.INT, fd),
                                              rffi.cast(rffi.INT, newfd)))
             if error == -1:
-                raise OSError(rposix.get_errno(), "dup2 failed")
+                raise OSError(rposix.get_saved_errno(), "dup2 failed")
 
         return extdef([int, int], s_None, llimpl=dup2_llimpl,
                       export_name="ll_os.ll_os_dup2")
 
     @registering_if(os, "getlogin", condition=not _WIN32)
     def register_os_getlogin(self):
-        os_getlogin = self.llexternal('getlogin', [], rffi.CCHARP, releasegil=False)
+        os_getlogin = self.llexternal('getlogin', [], rffi.CCHARP,
+                                      releasegil=False,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def getlogin_llimpl():
             result = os_getlogin()
             if not result:
-                raise OSError(rposix.get_errno(), "getlogin failed")
+                raise OSError(rposix.get_saved_errno(), "getlogin failed")
 
             return rffi.charp2str(result)
 
@@ -384,7 +397,8 @@
     @registering_str_unicode(os.utime)
     def register_os_utime(self, traits):
         UTIMBUFP = lltype.Ptr(self.UTIMBUF)
-        os_utime = self.llexternal('utime', [rffi.CCHARP, UTIMBUFP], rffi.INT)
+        os_utime = self.llexternal('utime', [rffi.CCHARP, UTIMBUFP], rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         if not _WIN32:
             includes = ['sys/time.h']
@@ -409,7 +423,8 @@
             TIMEVAL = config['TIMEVAL']
             TIMEVAL2P = rffi.CArrayPtr(TIMEVAL)
             os_utimes = self.llexternal('utimes', [rffi.CCHARP, TIMEVAL2P],
-                                        rffi.INT, compilation_info=eci)
+                                        rffi.INT, compilation_info=eci,
+                                        save_err=rffi.RFFI_SAVE_ERRNO)
 
             def os_utime_platform(path, actime, modtime):
                 import math
@@ -448,7 +463,7 @@
                     error = os_utime_platform(path, actime, modtime)
                     error = rffi.cast(lltype.Signed, error)
                 if error == -1:
-                    raise OSError(rposix.get_errno(), "os_utime failed")
+                    raise OSError(rposix.get_saved_errno(), "os_utime failed")
         else:
             from rpython.rtyper.module.ll_win32file import make_utime_impl
             os_utime_llimpl = make_utime_impl(traits)
@@ -518,7 +533,8 @@
             return
 
         TMSP = lltype.Ptr(self.TMS)
-        os_times = self.llexternal('times', [TMSP], self.CLOCK_T)
+        os_times = self.llexternal('times', [TMSP], self.CLOCK_T,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         # Here is a random extra platform parameter which is important.
         # Strictly speaking, this should probably be retrieved at runtime, not
@@ -531,7 +547,7 @@
                 result = os_times(l_tmsbuf)
                 result = rffi.cast(lltype.Signed, result)
                 if result == -1:
-                    raise OSError(rposix.get_errno(), "times failed")
+                    raise OSError(rposix.get_saved_errno(), "times failed")
                 return (
                     rffi.cast(lltype.Signed, l_tmsbuf.c_tms_utime)
                                                    / CLOCK_TICKS_PER_SECOND,
@@ -550,11 +566,12 @@
 
     @registering_if(os, 'setsid')
     def register_os_setsid(self):
-        os_setsid = self.llexternal('setsid', [], rffi.PID_T)
+        os_setsid = self.llexternal('setsid', [], rffi.PID_T,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
         def setsid_llimpl():
             result = rffi.cast(lltype.Signed, os_setsid())
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_setsid failed")
+                raise OSError(rposix.get_saved_errno(), "os_setsid failed")
             return result
 
         return extdef([], int, export_name="ll_os.ll_os_setsid",
@@ -562,11 +579,12 @@
 
     @registering_if(os, 'chroot')
     def register_os_chroot(self):
-        os_chroot = self.llexternal('chroot', [rffi.CCHARP], rffi.INT)
+        os_chroot = self.llexternal('chroot', [rffi.CCHARP], rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
         def chroot_llimpl(arg):
             result = os_chroot(arg)
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_chroot failed")
+                raise OSError(rposix.get_saved_errno(), "os_chroot failed")
 
         return extdef([str0], None, export_name="ll_os.ll_os_chroot",
                       llimpl=chroot_llimpl)
@@ -588,13 +606,14 @@
         UTSNAMEP = lltype.Ptr(config['UTSNAME'])
 
         os_uname = self.llexternal('uname', [UTSNAMEP], rffi.INT,
-                                   compilation_info=CConfig._compilation_info_)
+                                   compilation_info=CConfig._compilation_info_,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def uname_llimpl():
             l_utsbuf = lltype.malloc(UTSNAMEP.TO, flavor='raw')
             result = os_uname(l_utsbuf)
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_uname failed")
+                raise OSError(rposix.get_saved_errno(), "os_uname failed")
             retval = (
                 rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_sysname)),
                 rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_nodename)),
@@ -610,13 +629,14 @@
 
     @registering_if(os, 'sysconf')
     def register_os_sysconf(self):
-        c_sysconf = self.llexternal('sysconf', [rffi.INT], rffi.LONG)
+        c_sysconf = self.llexternal('sysconf', [rffi.INT], rffi.LONG,
+                                    save_err=rffi.RFFI_FULL_ERRNO)
 
         def sysconf_llimpl(i):
-            rposix.set_errno(0)
+            rposix.set_saved_errno(0)
             res = c_sysconf(i)
             if res == -1:
-                errno = rposix.get_errno()
+                errno = rposix.get_saved_errno()
                 if errno != 0:
                     raise OSError(errno, "sysconf failed")
             return res
@@ -625,13 +645,14 @@
     @registering_if(os, 'fpathconf')
     def register_os_fpathconf(self):
         c_fpathconf = self.llexternal('fpathconf',
-                                      [rffi.INT, rffi.INT], rffi.LONG)
+                                      [rffi.INT, rffi.INT], rffi.LONG,
+                                      save_err=rffi.RFFI_FULL_ERRNO)
 
         def fpathconf_llimpl(fd, i):
-            rposix.set_errno(0)
+            rposix.set_saved_errno(0)
             res = c_fpathconf(fd, i)
             if res == -1:
-                errno = rposix.get_errno()
+                errno = rposix.get_saved_errno()
                 if errno != 0:
                     raise OSError(errno, "fpathconf failed")
             return res
@@ -641,13 +662,14 @@
     @registering_if(os, 'pathconf')
     def register_os_pathconf(self):
         c_pathconf = self.llexternal('pathconf',
-                                     [rffi.CCHARP, rffi.INT], rffi.LONG)
+                                     [rffi.CCHARP, rffi.INT], rffi.LONG,
+                                     save_err=rffi.RFFI_FULL_ERRNO)
 
         def pathconf_llimpl(path, i):
-            rposix.set_errno(0)
+            rposix.set_saved_errno(0)
             res = c_pathconf(path, i)
             if res == -1:
-                errno = rposix.get_errno()
+                errno = rposix.get_saved_errno()
                 if errno != 0:
                     raise OSError(errno, "pathconf failed")
             return res
@@ -657,10 +679,11 @@
     @registering_if(os, 'confstr')
     def register_os_confstr(self):
         c_confstr = self.llexternal('confstr', [rffi.INT, rffi.CCHARP,
-                                                rffi.SIZE_T], rffi.SIZE_T)
+                                                rffi.SIZE_T], rffi.SIZE_T,
+                                                save_err=rffi.RFFI_FULL_ERRNO)
 
         def confstr_llimpl(i):
-            rposix.set_errno(0)
+            rposix.set_saved_errno(0)
             n = c_confstr(i, lltype.nullptr(rffi.CCHARP.TO), 0)
             n = rffi.cast(lltype.Signed, n)
             if n > 0:
@@ -671,7 +694,7 @@
                 finally:
                     lltype.free(buf, flavor='raw')
             else:
-                errno = rposix.get_errno()
+                errno = rposix.get_saved_errno()
                 if errno != 0:
                     raise OSError(errno, "confstr failed")
                 return None
@@ -717,7 +740,8 @@
     @registering_if(os, 'getgroups')
     def register_os_getgroups(self):
         GP = rffi.CArrayPtr(rffi.PID_T)
-        c_getgroups = self.llexternal('getgroups', [rffi.INT, GP], rffi.INT)
+        c_getgroups = self.llexternal('getgroups', [rffi.INT, GP], rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def getgroups_llimpl():
             n = c_getgroups(0, lltype.nullptr(GP.TO))
@@ -731,7 +755,7 @@
                     lltype.free(groups, flavor='raw')
                 if n >= 0:
                     return result
-            raise OSError(rposix.get_errno(), "os_getgroups failed")
+            raise OSError(rposix.get_saved_errno(), "os_getgroups failed")
 
         return extdef([], [int], llimpl=getgroups_llimpl,
                       export_name="ll_os.ll_getgroups")
@@ -739,7 +763,8 @@
     @registering_if(os, 'setgroups')
     def register_os_setgroups(self):
         GP = rffi.CArrayPtr(rffi.PID_T)
-        c_setgroups = self.llexternal('setgroups', [rffi.SIZE_T, GP], rffi.INT)
+        c_setgroups = self.llexternal('setgroups', [rffi.SIZE_T, GP], rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def setgroups_llimpl(list):
             n = len(list)
@@ -751,7 +776,7 @@
             finally:
                 lltype.free(groups, flavor='raw')
             if n != 0:
-                raise OSError(rposix.get_errno(), "os_setgroups failed")
+                raise OSError(rposix.get_saved_errno(), "os_setgroups failed")
 
         return extdef([[int]], None, llimpl=setgroups_llimpl,
                       export_name="ll_os.ll_setgroups")
@@ -759,12 +784,13 @@
     @registering_if(os, 'initgroups')
     def register_os_initgroups(self):
         c_initgroups = self.llexternal('initgroups',
-                                       [rffi.CCHARP, rffi.PID_T], rffi.INT)
+                                       [rffi.CCHARP, rffi.PID_T], rffi.INT,
+                                       save_err=rffi.RFFI_SAVE_ERRNO)
 
         def initgroups_llimpl(user, group):
             n = c_initgroups(user, rffi.cast(rffi.PID_T, group))
             if n != 0:
-                raise OSError(rposix.get_errno(), "os_initgroups failed")
+                raise OSError(rposix.get_saved_errno(), "os_initgroups failed")
 
         return extdef([str, int], None, llimpl=initgroups_llimpl,
                       export_name="ll_os.ll_initgroups")
@@ -773,11 +799,12 @@
     def register_os_getpgrp(self):
         name = 'getpgrp'
         if self.GETPGRP_HAVE_ARG:
-            c_func = self.llexternal(name, [rffi.INT], rffi.INT)
+            c_func = self.llexternal(name, [rffi.INT], rffi.INT,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
             def c_func_llimpl():
                 res = rffi.cast(rffi.SIGNED, c_func(0))
                 if res == -1:
-                    raise OSError(rposix.get_errno(), "%s failed" % name)
+                    raise OSError(rposix.get_saved_errno(), "%s failed" % name)
                 return res
 
             c_func_llimpl.func_name = name + '_llimpl'
@@ -791,11 +818,12 @@
     def register_os_setpgrp(self):
         name = 'setpgrp'
         if self.SETPGRP_HAVE_ARG:
-            c_func = self.llexternal(name, [rffi.INT, rffi.INT], rffi.INT)
+            c_func = self.llexternal(name, [rffi.INT, rffi.INT], rffi.INT,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
             def c_func_llimpl():
                 res = rffi.cast(rffi.SIGNED, c_func(0, 0))
                 if res == -1:
-                    raise OSError(rposix.get_errno(), "%s failed" % name)
+                    raise OSError(rposix.get_saved_errno(), "%s failed" % name)
 
             c_func_llimpl.func_name = name + '_llimpl'
 
@@ -806,13 +834,14 @@
 
     @registering_if(os, 'tcgetpgrp')
     def register_os_tcgetpgrp(self):
-        c_tcgetpgrp = self.llexternal('tcgetpgrp', [rffi.INT], rffi.PID_T)
+        c_tcgetpgrp = self.llexternal('tcgetpgrp', [rffi.INT], rffi.PID_T,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_tcgetpgrp_llimpl(fd):
             res = c_tcgetpgrp(rffi.cast(rffi.INT, fd))
             res = rffi.cast(lltype.Signed, res)
             if res == -1:
-                raise OSError(rposix.get_errno(), "tcgetpgrp failed")
+                raise OSError(rposix.get_saved_errno(), "tcgetpgrp failed")
             return res
 
         return extdef([int], int, llimpl=c_tcgetpgrp_llimpl,
@@ -821,14 +850,15 @@
     @registering_if(os, 'tcsetpgrp')
     def register_os_tcsetpgrp(self):
         c_tcsetpgrp = self.llexternal('tcsetpgrp', [rffi.INT, rffi.PID_T],
-                                      rffi.INT)
+                                      rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_tcsetpgrp_llimpl(fd, pgrp):
             res = c_tcsetpgrp(rffi.cast(rffi.INT, fd),
                               rffi.cast(rffi.PID_T, pgrp))
             res = rffi.cast(lltype.Signed, res)
             if res == -1:
-                raise OSError(rposix.get_errno(), "tcsetpgrp failed")
+                raise OSError(rposix.get_saved_errno(), "tcsetpgrp failed")
 
         return extdef([int, int], None, llimpl=c_tcsetpgrp_llimpl,
                       export_name='ll_os.ll_os_tcsetpgrp')
@@ -863,7 +893,8 @@
 
     @registering_if(os, 'getresuid')
     def register_os_getresuid(self):
-        c_getresuid = self.llexternal('getresuid', [rffi.INTP] * 3, rffi.INT)
+        c_getresuid = self.llexternal('getresuid', [rffi.INTP] * 3, rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_getresuid_llimpl():
             out = lltype.malloc(rffi.INTP.TO, 3, flavor='raw')
@@ -873,7 +904,7 @@
                                   rffi.ptradd(out, 2))
                 res = rffi.cast(lltype.Signed, res)
                 if res == -1:
-                    raise OSError(rposix.get_errno(), "getresuid failed")
+                    raise OSError(rposix.get_saved_errno(), "getresuid failed")
                 return (rffi.cast(lltype.Signed, out[0]),
                         rffi.cast(lltype.Signed, out[1]),
                         rffi.cast(lltype.Signed, out[2]))
@@ -885,7 +916,8 @@
 
     @registering_if(os, 'getresgid')
     def register_os_getresgid(self):
-        c_getresgid = self.llexternal('getresgid', [rffi.INTP] * 3, rffi.INT)
+        c_getresgid = self.llexternal('getresgid', [rffi.INTP] * 3, rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_getresgid_llimpl():
             out = lltype.malloc(rffi.INTP.TO, 3, flavor='raw')
@@ -895,7 +927,7 @@
                                   rffi.ptradd(out, 2))
                 res = rffi.cast(lltype.Signed, res)
                 if res == -1:
-                    raise OSError(rposix.get_errno(), "getresgid failed")
+                    raise OSError(rposix.get_saved_errno(), "getresgid failed")
                 return (rffi.cast(lltype.Signed, out[0]),
                         rffi.cast(lltype.Signed, out[1]),
                         rffi.cast(lltype.Signed, out[2]))
@@ -907,26 +939,28 @@
 
     @registering_if(os, 'setresuid')
     def register_os_setresuid(self):
-        c_setresuid = self.llexternal('setresuid', [rffi.INT] * 3, rffi.INT)
+        c_setresuid = self.llexternal('setresuid', [rffi.INT] * 3, rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_setresuid_llimpl(ruid, euid, suid):
             res = c_setresuid(ruid, euid, suid)
             res = rffi.cast(lltype.Signed, res)
             if res == -1:
-                raise OSError(rposix.get_errno(), "setresuid failed")
+                raise OSError(rposix.get_saved_errno(), "setresuid failed")
 
         return extdef([int, int, int], None, llimpl=c_setresuid_llimpl,
                       export_name='ll_os.ll_os_setresuid')
 
     @registering_if(os, 'setresgid')
     def register_os_setresgid(self):
-        c_setresgid = self.llexternal('setresgid', [rffi.INT] * 3, rffi.INT)
+        c_setresgid = self.llexternal('setresgid', [rffi.INT] * 3, rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
         def c_setresgid_llimpl(rgid, egid, sgid):
             res = c_setresgid(rgid, egid, sgid)
             res = rffi.cast(lltype.Signed, res)
             if res == -1:
-                raise OSError(rposix.get_errno(), "setresgid failed")
+                raise OSError(rposix.get_saved_errno(), "setresgid failed")
 
         return extdef([int, int, int], None, llimpl=c_setresgid_llimpl,
                       export_name='ll_os.ll_os_setresgid')
@@ -935,11 +969,12 @@
     def register_os_open(self, traits):
         os_open = self.llexternal(traits.posix_function_name('open'),
                                   [traits.CCHARP, rffi.INT, rffi.MODE_T],
-                                  rffi.INT)
+                                  rffi.INT,
+                                  save_err=rffi.RFFI_SAVE_ERRNO)
         def os_open_llimpl(path, flags, mode):
             result = rffi.cast(lltype.Signed, os_open(path, flags, mode))
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_open failed")
+                raise OSError(rposix.get_saved_errno(), "os_open failed")
             return result
 
         return extdef([traits.str0, int, int], int, traits.ll_os_name('open'),
@@ -991,7 +1026,7 @@
     def register_os_read(self):
         os_read = self.llexternal(UNDERSCORE_ON_WIN32 + 'read',
                                   [rffi.INT, rffi.VOIDP, rffi.SIZE_T],
-                                  rffi.SIZE_T)
+                                  rffi.SIZE_T, save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_read_llimpl(fd, count):
             if count < 0:
@@ -1001,7 +1036,7 @@
                 void_buf = rffi.cast(rffi.VOIDP, buf.raw)
                 got = rffi.cast(lltype.Signed, os_read(fd, void_buf, count))
                 if got < 0:
-                    raise OSError(rposix.get_errno(), "os_read failed")
+                    raise OSError(rposix.get_saved_errno(), "os_read failed")
                 return buf.str(got)
 
         return extdef([int, int], SomeString(can_be_None=True),
@@ -1011,7 +1046,8 @@
     def register_os_write(self):
         os_write = self.llexternal(UNDERSCORE_ON_WIN32 + 'write',
                                    [rffi.INT, rffi.VOIDP, rffi.SIZE_T],
-                                   rffi.SIZE_T)
+                                   rffi.SIZE_T,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_write_llimpl(fd, data):
             count = len(data)
@@ -1021,7 +1057,7 @@
                     rffi.cast(rffi.INT, fd),
                     buf, rffi.cast(rffi.SIZE_T, count)))
                 if written < 0:
-                    raise OSError(rposix.get_errno(), "os_write failed")
+                    raise OSError(rposix.get_saved_errno(), "os_write failed")
             return written
 
         return extdef([int, str], SomeInteger(nonneg=True),
@@ -1030,13 +1066,14 @@
     @registering(os.close)
     def register_os_close(self):
         os_close = self.llexternal(UNDERSCORE_ON_WIN32 + 'close', [rffi.INT],
-                                   rffi.INT, releasegil=False)
+                                   rffi.INT, releasegil=False,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def close_llimpl(fd):
             rposix.validate_fd(fd)
             error = rffi.cast(lltype.Signed, os_close(rffi.cast(rffi.INT, fd)))
             if error == -1:
-                raise OSError(rposix.get_errno(), "close failed")
+                raise OSError(rposix.get_saved_errno(), "close failed")
 
         return extdef([int], s_None, llimpl=close_llimpl,
                       export_name="ll_os.ll_os_close")
@@ -1066,7 +1103,8 @@
 
         os_lseek = self.llexternal(funcname,
                                    [rffi.INT, rffi.LONGLONG, rffi.INT],
-                                   rffi.LONGLONG, macro=True)
+                                   rffi.LONGLONG, macro=True,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def lseek_llimpl(fd, pos, how):
             rposix.validate_fd(fd)
@@ -1076,7 +1114,7 @@
                            rffi.cast(rffi.INT,      how))
             res = rffi.cast(lltype.SignedLongLong, res)
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_lseek failed")
+                raise OSError(rposix.get_saved_errno(), "os_lseek failed")
             return res
 
         return extdef([int, r_longlong, int],
@@ -1087,7 +1125,9 @@
     @registering_if(os, 'ftruncate')
     def register_os_ftruncate(self):
         os_ftruncate = self.llexternal('ftruncate',
-                                       [rffi.INT, rffi.LONGLONG], rffi.INT, macro=True)
+                                       [rffi.INT, rffi.LONGLONG], rffi.INT,
+                                       macro=True,
+                                       save_err=rffi.RFFI_SAVE_ERRNO)
 
         def ftruncate_llimpl(fd, length):
             rposix.validate_fd(fd)
@@ -1095,7 +1135,7 @@
                             os_ftruncate(rffi.cast(rffi.INT, fd),
                                          rffi.cast(rffi.LONGLONG, length)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_ftruncate failed")
+                raise OSError(rposix.get_saved_errno(), "os_ftruncate failed")
 
         return extdef([int, r_longlong], s_None,
                       llimpl = ftruncate_llimpl,
@@ -1104,41 +1144,45 @@
     @registering_if(os, 'fsync')
     def register_os_fsync(self):
         if not _WIN32:
-            os_fsync = self.llexternal('fsync', [rffi.INT], rffi.INT)
+            os_fsync = self.llexternal('fsync', [rffi.INT], rffi.INT,
+                                       save_err=rffi.RFFI_SAVE_ERRNO)
         else:
-            os_fsync = self.llexternal('_commit', [rffi.INT], rffi.INT)
+            os_fsync = self.llexternal('_commit', [rffi.INT], rffi.INT,
+                                       save_err=rffi.RFFI_SAVE_ERRNO)
 
         def fsync_llimpl(fd):
             rposix.validate_fd(fd)
             res = rffi.cast(rffi.SIGNED, os_fsync(rffi.cast(rffi.INT, fd)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "fsync failed")
+                raise OSError(rposix.get_saved_errno(), "fsync failed")
         return extdef([int], s_None,
                       llimpl=fsync_llimpl,
                       export_name="ll_os.ll_os_fsync")
 
     @registering_if(os, 'fdatasync')
     def register_os_fdatasync(self):
-        os_fdatasync = self.llexternal('fdatasync', [rffi.INT], rffi.INT)
+        os_fdatasync = self.llexternal('fdatasync', [rffi.INT], rffi.INT,
+                                       save_err=rffi.RFFI_SAVE_ERRNO)
 
         def fdatasync_llimpl(fd):
             rposix.validate_fd(fd)
             res = rffi.cast(rffi.SIGNED, os_fdatasync(rffi.cast(rffi.INT, fd)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "fdatasync failed")
+                raise OSError(rposix.get_saved_errno(), "fdatasync failed")
         return extdef([int], s_None,
                       llimpl=fdatasync_llimpl,
                       export_name="ll_os.ll_os_fdatasync")
 
     @registering_if(os, 'fchdir')
     def register_os_fchdir(self):
-        os_fchdir = self.llexternal('fchdir', [rffi.INT], rffi.INT)
+        os_fchdir = self.llexternal('fchdir', [rffi.INT], rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def fchdir_llimpl(fd):
             rposix.validate_fd(fd)
             res = rffi.cast(rffi.SIGNED, os_fchdir(rffi.cast(rffi.INT, fd)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "fchdir failed")
+                raise OSError(rposix.get_saved_errno(), "fchdir failed")
         return extdef([int], s_None,
                       llimpl=fchdir_llimpl,
                       export_name="ll_os.ll_os_fchdir")
@@ -1180,7 +1224,8 @@
     def register_os_getcwd(self):
         os_getcwd = self.llexternal(UNDERSCORE_ON_WIN32 + 'getcwd',
                                     [rffi.CCHARP, rffi.SIZE_T],
-                                    rffi.CCHARP)
+                                    rffi.CCHARP,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_getcwd_llimpl():
             bufsize = 256
@@ -1189,7 +1234,7 @@
                 res = os_getcwd(buf, rffi.cast(rffi.SIZE_T, bufsize))
                 if res:
                     break   # ok
-                error = rposix.get_errno()
+                error = rposix.get_saved_errno()
                 lltype.free(buf, flavor='raw')
                 if error != errno.ERANGE:
                     raise OSError(error, "getcwd failed")
@@ -1208,7 +1253,8 @@
     def register_os_getcwdu(self):
         os_wgetcwd = self.llexternal(UNDERSCORE_ON_WIN32 + 'wgetcwd',
                                      [rffi.CWCHARP, rffi.SIZE_T],
-                                     rffi.CWCHARP)
+                                     rffi.CWCHARP,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_getcwd_llimpl():
             bufsize = 256
@@ -1217,7 +1263,7 @@
                 res = os_wgetcwd(buf, rffi.cast(rffi.SIZE_T, bufsize))
                 if res:
                     break   # ok
-                error = rposix.get_errno()
+                error = rposix.get_saved_errno()
                 lltype.free(buf, flavor='raw')
                 if error != errno.ERANGE:
                     raise OSError(error, "getcwd failed")
@@ -1253,11 +1299,13 @@
             DIRENT = config['DIRENT']
             DIRENTP = lltype.Ptr(DIRENT)
             os_opendir = self.llexternal('opendir', [rffi.CCHARP], DIRP,
-                                         compilation_info=compilation_info)
+                                         compilation_info=compilation_info,
+                                         save_err=rffi.RFFI_SAVE_ERRNO)
             # XXX macro=True is hack to make sure we get the correct kind of
             # dirent struct (which depends on defines)
             os_readdir = self.llexternal('readdir', [DIRP], DIRENTP,
                                          compilation_info=compilation_info,
+                                         save_err=rffi.RFFI_FULL_ERRNO,
                                          macro=True)
             os_closedir = self.llexternal('closedir', [DIRP], rffi.INT,
                                           compilation_info=compilation_info)
@@ -1265,13 +1313,13 @@
             def os_listdir_llimpl(path):
                 dirp = os_opendir(path)
                 if not dirp:
-                    raise OSError(rposix.get_errno(), "os_opendir failed")
+                    raise OSError(rposix.get_saved_errno(), "os_opendir failed")
                 result = []
                 while True:
-                    rposix.set_errno(0)
+                    rposix.set_saved_errno(0)
                     direntp = os_readdir(dirp)
                     if not direntp:
-                        error = rposix.get_errno()
+                        error = rposix.get_saved_errno()
                         break
                     namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
                     name = rffi.charp2str(namep)
@@ -1322,7 +1370,8 @@
 
         else:
             INT_ARRAY_P = rffi.CArrayPtr(rffi.INT)
-            os_pipe = self.llexternal('pipe', [INT_ARRAY_P], rffi.INT)
+            os_pipe = self.llexternal('pipe', [INT_ARRAY_P], rffi.INT,
+                                      save_err=rffi.RFFI_SAVE_ERRNO)
 
             def os_pipe_llimpl():
                 filedes = lltype.malloc(INT_ARRAY_P.TO, 2, flavor='raw')
@@ -1331,7 +1380,7 @@
                 write_fd = filedes[1]
                 lltype.free(filedes, flavor='raw')
                 if error != 0:
-                    raise OSError(rposix.get_errno(), "os_pipe failed")
+                    raise OSError(rposix.get_saved_errno(), "os_pipe failed")
                 return (rffi.cast(lltype.Signed, read_fd),
                         rffi.cast(lltype.Signed, write_fd))
 
@@ -1342,12 +1391,13 @@
     @registering_if(os, 'chown')
     def register_os_chown(self):
         os_chown = self.llexternal('chown', [rffi.CCHARP, rffi.INT, rffi.INT],
-                                   rffi.INT)
+                                   rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_chown_llimpl(path, uid, gid):
             res = os_chown(path, uid, gid)
             if res == -1:
-                raise OSError(rposix.get_errno(), "os_chown failed")
+                raise OSError(rposix.get_saved_errno(), "os_chown failed")
 
         return extdef([str0, int, int], None, "ll_os.ll_os_chown",
                       llimpl=os_chown_llimpl)
@@ -1355,12 +1405,13 @@
     @registering_if(os, 'lchown')
     def register_os_lchown(self):
         os_lchown = self.llexternal('lchown',[rffi.CCHARP, rffi.INT, rffi.INT],
-                                    rffi.INT)
+                                    rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_lchown_llimpl(path, uid, gid):
             res = os_lchown(path, uid, gid)
             if res == -1:
-                raise OSError(rposix.get_errno(), "os_lchown failed")
+                raise OSError(rposix.get_saved_errno(), "os_lchown failed")
 
         return extdef([str0, int, int], None, "ll_os.ll_os_lchown",
                       llimpl=os_lchown_llimpl)
@@ -1368,12 +1419,13 @@
     @registering_if(os, 'fchown')
     def register_os_fchown(self):
         os_fchown = self.llexternal('fchown',[rffi.INT, rffi.INT, rffi.INT],
-                                    rffi.INT)
+                                    rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_fchown_llimpl(fd, uid, gid):
             res = os_fchown(fd, uid, gid)
             if res == -1:
-                raise OSError(rposix.get_errno(), "os_fchown failed")
+                raise OSError(rposix.get_saved_errno(), "os_fchown failed")
 
         return extdef([int, int, int], None, "ll_os.ll_os_fchown",
                       llimpl=os_fchown_llimpl)
@@ -1382,7 +1434,9 @@
     def register_os_readlink(self):
         os_readlink = self.llexternal('readlink',
                                    [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T],
-                                   rffi.INT)
+                                   rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
+
         # XXX SSIZE_T in POSIX.1-2001
 
         def os_readlink_llimpl(path):
@@ -1394,7 +1448,7 @@
                 res = rffi.cast(lltype.Signed, os_readlink(l_path, buf, bufsize))
                 lltype.free(l_path, flavor='raw')
                 if res < 0:
-                    error = rposix.get_errno()    # failed
+                    error = rposix.get_saved_errno()    # failed
                     lltype.free(buf, flavor='raw')
                     raise OSError(error, "readlink failed")
                 elif res < bufsize:
@@ -1418,7 +1472,8 @@
             # emulate waitpid() with the _cwait() of Microsoft's compiler
             os__cwait = self.llexternal('_cwait',
                                         [rffi.INTP, rffi.PID_T, rffi.INT],
-                                        rffi.PID_T)
+                                        rffi.PID_T,
+                                        save_err=rffi.RFFI_SAVE_ERRNO)
             def os_waitpid(pid, status_p, options):
                 result = os__cwait(status_p, pid, options)
                 # shift the status left a byte so this is more
@@ -1432,11 +1487,13 @@
             if _CYGWIN:
                 os_waitpid = self.llexternal('cygwin_waitpid',
                                              [rffi.PID_T, rffi.INTP, rffi.INT],
-                                             rffi.PID_T)
+                                             rffi.PID_T,
+                                             save_err=rffi.RFFI_SAVE_ERRNO)
             else:
                 os_waitpid = self.llexternal('waitpid',
                                              [rffi.PID_T, rffi.INTP, rffi.INT],
-                                             rffi.PID_T)
+                                             rffi.PID_T,
+                                             save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_waitpid_llimpl(pid, options):
             status_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
@@ -1448,7 +1505,7 @@
             status = status_p[0]
             lltype.free(status_p, flavor='raw')
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_waitpid failed")
+                raise OSError(rposix.get_saved_errno(), "os_waitpid failed")
             return (rffi.cast(lltype.Signed, result),
                     rffi.cast(lltype.Signed, status))
 
@@ -1497,12 +1554,13 @@
     @registering_str_unicode(os.unlink)
     def register_os_unlink(self, traits):
         os_unlink = self.llexternal(traits.posix_function_name('unlink'),
-                                    [traits.CCHARP], rffi.INT)
+                                    [traits.CCHARP], rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def unlink_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_unlink(pathname))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_unlink failed")
+                raise OSError(rposix.get_saved_errno(), "os_unlink failed")
 
         if sys.platform == 'win32':
             from rpython.rtyper.module.ll_win32file import make_win32_traits
@@ -1519,12 +1577,13 @@
     @registering_str_unicode(os.chdir)
     def register_os_chdir(self, traits):
         os_chdir = self.llexternal(traits.posix_function_name('chdir'),
-                                   [traits.CCHARP], rffi.INT)
+                                   [traits.CCHARP], rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def os_chdir_llimpl(path):
             res = rffi.cast(lltype.Signed, os_chdir(path))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_chdir failed")
+                raise OSError(rposix.get_saved_errno(), "os_chdir failed")
 
         # On Windows, use an implementation that will produce Win32 errors
         if sys.platform == 'win32':
@@ -1537,7 +1596,8 @@
     @registering_str_unicode(os.mkdir)
     def register_os_mkdir(self, traits):
         os_mkdir = self.llexternal(traits.posix_function_name('mkdir'),
-                                   [traits.CCHARP, rffi.MODE_T], rffi.INT)
+                                   [traits.CCHARP, rffi.MODE_T], rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         if sys.platform == 'win32':
             from rpython.rtyper.module.ll_win32file import make_win32_traits
@@ -1552,7 +1612,7 @@
                 res = os_mkdir(pathname, mode)
                 res = rffi.cast(lltype.Signed, res)
                 if res < 0:
-                    raise OSError(rposix.get_errno(), "os_mkdir failed")
+                    raise OSError(rposix.get_saved_errno(), "os_mkdir failed")
 
         return extdef([traits.str0, int], s_None, llimpl=os_mkdir_llimpl,
                       export_name=traits.ll_os_name('mkdir'))
@@ -1560,12 +1620,13 @@
     @registering_str_unicode(os.rmdir)
     def register_os_rmdir(self, traits):
         os_rmdir = self.llexternal(traits.posix_function_name('rmdir'),
-                                   [traits.CCHARP], rffi.INT)
+                                   [traits.CCHARP], rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def rmdir_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_rmdir(pathname))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_rmdir failed")
+                raise OSError(rposix.get_saved_errno(), "os_rmdir failed")
 
         return extdef([traits.str0], s_None, llimpl=rmdir_llimpl,
                       export_name=traits.ll_os_name('rmdir'))
@@ -1573,12 +1634,13 @@
     @registering_str_unicode(os.chmod)
     def register_os_chmod(self, traits):
         os_chmod = self.llexternal(traits.posix_function_name('chmod'),
-                                   [traits.CCHARP, rffi.MODE_T], rffi.INT)
+                                   [traits.CCHARP, rffi.MODE_T], rffi.INT,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def chmod_llimpl(path, mode):
             res = rffi.cast(lltype.Signed, os_chmod(path, rffi.cast(rffi.MODE_T, mode)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_chmod failed")
+                raise OSError(rposix.get_saved_errno(), "os_chmod failed")
 
         if sys.platform == 'win32':
             from rpython.rtyper.module.ll_win32file import make_chmod_impl
@@ -1590,13 +1652,14 @@
     @registering_if(os, 'fchmod')
     def register_os_fchmod(self):
         os_fchmod = self.llexternal('fchmod', [rffi.INT, rffi.MODE_T],
-                                    rffi.INT)
+                                    rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def fchmod_llimpl(fd, mode):
             mode = rffi.cast(rffi.MODE_T, mode)
             res = rffi.cast(lltype.Signed, os_fchmod(fd, mode))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_fchmod failed")
+                raise OSError(rposix.get_saved_errno(), "os_fchmod failed")
 
         return extdef([int, int], s_None, "ll_os.ll_os_fchmod",
                       llimpl=fchmod_llimpl)
@@ -1604,12 +1667,13 @@
     @registering_str_unicode(os.rename)
     def register_os_rename(self, traits):
         os_rename = self.llexternal(traits.posix_function_name('rename'),
-                                    [traits.CCHARP, traits.CCHARP], rffi.INT)
+                                    [traits.CCHARP, traits.CCHARP], rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def rename_llimpl(oldpath, newpath):
             res = rffi.cast(lltype.Signed, os_rename(oldpath, newpath))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_rename failed")
+                raise OSError(rposix.get_saved_errno(), "os_rename failed")
 
         if sys.platform == 'win32':
             from rpython.rtyper.module.ll_win32file import make_win32_traits
@@ -1626,12 +1690,13 @@
     @registering_str_unicode(getattr(os, 'mkfifo', None))
     def register_os_mkfifo(self, traits):
         os_mkfifo = self.llexternal(traits.posix_function_name('mkfifo'),
-                                    [traits.CCHARP, rffi.MODE_T], rffi.INT)
+                                    [traits.CCHARP, rffi.MODE_T], rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def mkfifo_llimpl(path, mode):
             res = rffi.cast(lltype.Signed, os_mkfifo(path, mode))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_mkfifo failed")
+                raise OSError(rposix.get_saved_errno(), "os_mkfifo failed")
 
         return extdef([traits.str0, int], s_None, llimpl=mkfifo_llimpl,
                       export_name=traits.ll_os_name('mkfifo'))
@@ -1640,12 +1705,13 @@
     def register_os_mknod(self, traits):
         os_mknod = self.llexternal(traits.posix_function_name('mknod'),
                                    [traits.CCHARP, rffi.MODE_T, rffi.INT],
-                                   rffi.INT)      # xxx: actually ^^^ dev_t
+                                   rffi.INT,      # xxx: actually ^^^ dev_t
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
         def mknod_llimpl(path, mode, dev):
             res = rffi.cast(lltype.Signed, os_mknod(path, mode, dev))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_mknod failed")
+                raise OSError(rposix.get_sved_errno(), "os_mknod failed")
 
         return extdef([traits.str0, int, int], s_None, llimpl=mknod_llimpl,
                       export_name=traits.ll_os_name('mknod'))
@@ -1665,25 +1731,27 @@
     @registering_if(os, 'kill', sys.platform != 'win32')
     def register_os_kill(self):
         os_kill = self.llexternal('kill', [rffi.PID_T, rffi.INT],
-                                  rffi.INT)
+                                  rffi.INT,
+                                  save_err=rffi.RFFI_SAVE_ERRNO)
         def kill_llimpl(pid, sig):
             res = rffi.cast(lltype.Signed, os_kill(rffi.cast(rffi.PID_T, pid),
                                                    rffi.cast(rffi.INT, sig)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_kill failed")
+                raise OSError(rposix.get_saved_errno(), "os_kill failed")
         return extdef([int, int], s_None, llimpl=kill_llimpl,
                       export_name="ll_os.ll_os_kill")
 
     @registering_if(os, 'killpg')
     def register_os_killpg(self):
         os_killpg = self.llexternal('killpg', [rffi.INT, rffi.INT],
-                                    rffi.INT)
+                                    rffi.INT,
+                                    save_err=rffi.RFFI_SAVE_ERRNO)
 
         def killpg_llimpl(pid, sig):
             res = rffi.cast(lltype.Signed, os_killpg(rffi.cast(rffi.INT, pid),
                                                      rffi.cast(rffi.INT, sig)))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_killpg failed")
+                raise OSError(rposix.get_saved_errno(), "os_killpg failed")
 
         return extdef([int, int], s_None, llimpl=killpg_llimpl,
                       export_name="ll_os.ll_os_killpg")
@@ -1691,12 +1759,13 @@
     @registering_if(os, 'link')
     def register_os_link(self):
         os_link = self.llexternal('link', [rffi.CCHARP, rffi.CCHARP],
-                                  rffi.INT)
+                                  rffi.INT,
+                                  save_err=rffi.RFFI_SAVE_ERRNO)
 
         def link_llimpl(oldpath, newpath):
             res = rffi.cast(lltype.Signed, os_link(oldpath, newpath))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_link failed")
+                raise OSError(rposix.get_saved_errno(), "os_link failed")
 
         return extdef([str0, str0], s_None, llimpl=link_llimpl,
                       export_name="ll_os.ll_os_link")
@@ -1704,12 +1773,13 @@
     @registering_if(os, 'symlink')
     def register_os_symlink(self):
         os_symlink = self.llexternal('symlink', [rffi.CCHARP, rffi.CCHARP],
-                                     rffi.INT)
+                                     rffi.INT,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
 
         def symlink_llimpl(oldpath, newpath):
             res = rffi.cast(lltype.Signed, os_symlink(oldpath, newpath))
             if res < 0:
-                raise OSError(rposix.get_errno(), "os_symlink failed")
+                raise OSError(rposix.get_saved_errno(), "os_symlink failed")
 
         return extdef([str0, str0], s_None, llimpl=symlink_llimpl,
                       export_name="ll_os.ll_os_symlink")
@@ -1725,9 +1795,10 @@
             ofs = debug.debug_offset()
             opaqueaddr = rthread.gc_thread_before_fork()
             childpid = rffi.cast(lltype.Signed, os_fork())
+            errno = rposix._get_errno()
             rthread.gc_thread_after_fork(childpid, opaqueaddr)
             if childpid == -1:
-                raise OSError(rposix.get_errno(), "os_fork failed")
+                raise OSError(errno, "os_fork failed")
             if childpid == 0:
                 debug.debug_forked(ofs)
             return rffi.cast(lltype.Signed, childpid)
@@ -1741,7 +1812,8 @@
             'openpty',
             [rffi.INTP, rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
             rffi.INT,
-            compilation_info=ExternalCompilationInfo(libraries=['util']))
+            compilation_info=ExternalCompilationInfo(libraries=['util']),
+            save_err=rffi.RFFI_SAVE_ERRNO)
         def openpty_llimpl():
             master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
             slave_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
@@ -1751,7 +1823,7 @@
             lltype.free(master_p, flavor='raw')
             lltype.free(slave_p, flavor='raw')
             if result == -1:
-                raise OSError(rposix.get_errno(), "os_openpty failed")
+                raise OSError(rposix.get_saved_errno(), "os_openpty failed")
             return (rffi.cast(lltype.Signed, master_fd),
                     rffi.cast(lltype.Signed, slave_fd))
 
@@ -1765,7 +1837,8 @@
             'forkpty',
             [rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
             rffi.PID_T,
-            compilation_info=ExternalCompilationInfo(libraries=['util']))
+            compilation_info=ExternalCompilationInfo(libraries=['util']),
+            save_err=rffi.RFFI_SAVE_ERRNO)
         def forkpty_llimpl():
             master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
             master_p[0] = rffi.cast(rffi.INT, -1)
@@ -1777,7 +1850,7 @@
             master_fd = master_p[0]
             lltype.free(master_p, flavor='raw')
             if childpid == -1:
-                raise OSError(rposix.get_errno(), "os_forkpty failed")
+                raise OSError(rposix.get_saved_errno(), "os_forkpty failed")
             if childpid == 0:
                 debug.debug_forked(ofs)
             return (rffi.cast(lltype.Signed, childpid),
@@ -1800,16 +1873,17 @@
 
     @registering_if(os, 'nice')
     def register_os_nice(self):
-        os_nice = self.llexternal('nice', [rffi.INT], rffi.INT)
+        os_nice = self.llexternal('nice', [rffi.INT], rffi.INT,
+                                  save_err=rffi.RFFI_FULL_ERRNO)
 
         def nice_llimpl(inc):
             # Assume that the system provides a standard-compliant version
             # of nice() that returns the new priority.  Nowadays, FreeBSD
             # might be the last major non-compliant system (xxx check me).
-            rposix.set_errno(0)
+            rposix.set_saved_errno(0)
             res = rffi.cast(lltype.Signed, os_nice(inc))
             if res == -1:
-                err = rposix.get_errno()
+                err = rposix.get_saved_errno()
                 if err != 0:
                     raise OSError(err, "os_nice failed")
             return res
@@ -1907,12 +1981,14 @@
 
     @registering_if(os, 'ttyname')
     def register_os_ttyname(self):
-        os_ttyname = self.llexternal('ttyname', [lltype.Signed], rffi.CCHARP, releasegil=False)
+        os_ttyname = self.llexternal('ttyname', [lltype.Signed], rffi.CCHARP,
+                                     releasegil=False,
+                                     save_err=rffi.RFFI_SAVE_ERRNO)
 
         def ttyname_llimpl(fd):
             l_name = os_ttyname(fd)
             if not l_name:
-                raise OSError(rposix.get_errno(), "ttyname raised")
+                raise OSError(rposix.get_saved_errno(), "ttyname raised")
             return rffi.charp2str(l_name)
 
         return extdef([int], str, "ll_os.ttyname",
diff --git a/rpython/rtyper/module/ll_os_environ.py b/rpython/rtyper/module/ll_os_environ.py
--- a/rpython/rtyper/module/ll_os_environ.py
+++ b/rpython/rtyper/module/ll_os_environ.py
@@ -118,7 +118,8 @@
 
 os_getenv = rffi.llexternal('getenv', [rffi.CCHARP], rffi.CCHARP,
                             releasegil=False)
-os_putenv = rffi.llexternal(prefix + 'putenv', [rffi.CCHARP], rffi.INT)
+os_putenv = rffi.llexternal(prefix + 'putenv', [rffi.CCHARP], rffi.INT,
+                            save_err=rffi.RFFI_SAVE_ERRNO)
 if _WIN32:
     _wgetenv = rffi.llexternal('_wgetenv', [rffi.CWCHARP], rffi.CWCHARP,
                                compilation_info=eci, releasegil=False)
@@ -138,7 +139,7 @@
         byname, eq = envkeepalive.byname, '='
         def last_error(msg):
             from rpython.rlib import rposix
-            raise OSError(rposix.get_errno(), msg)
+            raise OSError(rposix.get_saved_errno(), msg)
     else:
         traits = UnicodeTraits()
         get_environ, getenv, putenv = get__wenviron, _wgetenv, _wputenv
@@ -197,14 +198,15 @@
     r_putenv(name, '')
 
 if hasattr(__import__(os.name), 'unsetenv'):
-    os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], rffi.INT)
+    os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], rffi.INT,
+                                  save_err=rffi.RFFI_SAVE_ERRNO)
 
     def unsetenv_llimpl(name):
         with rffi.scoped_str2charp(name) as l_name:
             error = rffi.cast(lltype.Signed, os_unsetenv(l_name))
         if error:
             from rpython.rlib import rposix
-            raise OSError(rposix.get_errno(), "os_unsetenv failed")
+            raise OSError(rposix.get_saved_errno(), "os_unsetenv failed")
         try:
             l_oldstring = envkeepalive.byname[name]
         except KeyError:
diff --git a/rpython/rtyper/module/ll_os_stat.py b/rpython/rtyper/module/ll_os_stat.py
--- a/rpython/rtyper/module/ll_os_stat.py
+++ b/rpython/rtyper/module/ll_os_stat.py
@@ -349,7 +349,8 @@
 
     posix_mystat = rffi.llexternal(c_func_name,
                                    [ARG1, STAT_STRUCT], rffi.INT,
-                                   compilation_info=compilation_info)
+                                   compilation_info=compilation_info,
+                                   save_err=rffi.RFFI_SAVE_ERRNO)
 
     @func_renamer('os_%s_llimpl' % (name,))
     def posix_stat_llimpl(arg):
@@ -361,7 +362,7 @@
             if arg_is_path:
                 traits.free_charp(arg)
             if error != 0:
-                raise OSError(rposix.get_errno(), "os_?stat failed")
+                raise OSError(rposix.get_saved_errno(), "os_?stat failed")
             return build_stat_result(stresult)
         finally:
             lltype.free(stresult, flavor='raw')
@@ -401,8 +402,8 @@
 
     posix_mystatvfs = rffi.llexternal(name,
         [ARG1, STATVFS_STRUCT], rffi.INT,
-        compilation_info=compilation_info
-    )
+        compilation_info=compilation_info,
+        save_err=rffi.RFFI_SAVE_ERRNO)
 
     @func_renamer('os_%s_llimpl' % (name,))
     def posix_statvfs_llimpl(arg):
@@ -414,7 +415,7 @@
             if arg_is_path:
                 traits.free_charp(arg)
             if error != 0:
-                raise OSError(rposix.get_errno(), "os_?statvfs failed")
+                raise OSError(rposix.get_saved_errno(), "os_?statvfs failed")
             return build_statvfs_result(stresult)
         finally:
             lltype.free(stresult, flavor='raw')
diff --git a/rpython/rtyper/module/ll_win32file.py b/rpython/rtyper/module/ll_win32file.py
--- a/rpython/rtyper/module/ll_win32file.py
+++ b/rpython/rtyper/module/ll_win32file.py
@@ -168,7 +168,8 @@
         CreateDirectory = external(
             'CreateDirectory' + suffix,
             [traits.CCHARP, rffi.VOIDP],
-            rwin32.BOOL)
+            rwin32.BOOL,
+            XXX)   # save_err=rffi.RFFI_SAVE_LASTERROR
 
         SetEnvironmentVariable = external(
             'SetEnvironmentVariable' + suffix,
diff --git a/rpython/translator/c/src/thread_gil.c b/rpython/translator/c/src/thread_gil.c
--- a/rpython/translator/c/src/thread_gil.c
+++ b/rpython/translator/c/src/thread_gil.c
@@ -52,11 +52,6 @@
 void RPyGilAcquire(void)
 {
     /* Acquires the GIL.
-
-       Note: in the slow path, this function saves and restores 'errno'.
-       This is needed for now because it may be *followed* by reading
-       the 'errno'.  It's a bit strange, because we could read the errno
-       before calling RPyGilAcquire(), but it's simpler this way.
      */
     long old_fastgil = lock_test_and_set(&rpy_fastgil, 1);
 
@@ -67,7 +62,6 @@
     }
     else {
         /* Otherwise, another thread is busy with the GIL. */
-        SAVE_ERRNO();
 
         /* Register me as one of the threads that is actively waiting
            for the GIL.  The number of such threads is found in
@@ -109,8 +103,6 @@
         atomic_decrement(&rpy_waiting_threads);
         mutex2_loop_stop(&mutex_gil);
         mutex1_unlock(&mutex_gil_stealer);
-
-        RESTORE_ERRNO();
     }
     assert(RPY_FASTGIL_LOCKED(rpy_fastgil));
 
diff --git a/rpython/translator/c/src/thread_nt.c b/rpython/translator/c/src/thread_nt.c
--- a/rpython/translator/c/src/thread_nt.c
+++ b/rpython/translator/c/src/thread_nt.c
@@ -8,7 +8,6 @@
 #include <stdio.h>
 #include <limits.h>
 #include <process.h>
-#include <errno.h>
 
 
 /*
@@ -244,9 +243,4 @@
 #define atomic_increment(ptr)          InterlockedIncrement(ptr)
 #define atomic_decrement(ptr)          InterlockedDecrement(ptr)
 
-#define SAVE_ERRNO()      int saved_errno = errno; \
-                          DWORD saved_lasterr = GetLastError()
-#define RESTORE_ERRNO()   errno = saved_errno; \
-                          SetLastError(saved_lasterr)
-
 #include "src/thread_gil.c"
diff --git a/rpython/translator/c/src/thread_pthread.c b/rpython/translator/c/src/thread_pthread.c
--- a/rpython/translator/c/src/thread_pthread.c
+++ b/rpython/translator/c/src/thread_pthread.c
@@ -533,7 +533,4 @@
 #define atomic_increment(ptr)          __sync_fetch_and_add(ptr, 1)
 #define atomic_decrement(ptr)          __sync_fetch_and_sub(ptr, 1)
 
-#define SAVE_ERRNO()      int saved_errno = errno
-#define RESTORE_ERRNO()   errno = saved_errno
-
 #include "src/thread_gil.c"
diff --git a/rpython/translator/c/src/threadlocal.c b/rpython/translator/c/src/threadlocal.c
--- a/rpython/translator/c/src/threadlocal.c
+++ b/rpython/translator/c/src/threadlocal.c
@@ -2,7 +2,6 @@
 #include "structdef.h"       /* for struct pypy_threadlocal_s */
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
 #include <string.h>
 #ifndef _WIN32
 # include <pthread.h>
@@ -13,9 +12,6 @@
 static void _RPy_ThreadLocals_Init(void *p)
 {
     memset(p, 0, sizeof(struct pypy_threadlocal_s));
-#ifdef RPY_TLOFS_p_errno
-    ((struct pypy_threadlocal_s *)p)->p_errno = &errno;
-#endif
 #ifdef RPY_TLOFS_thread_ident
     ((struct pypy_threadlocal_s *)p)->thread_ident =
 #    ifdef _WIN32


More information about the pypy-commit mailing list