[pypy-svn] r46760 - in pypy/dist/pypy/rpython/lltypesystem: . test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 20 14:28:07 CEST 2007


Author: arigo
Date: Thu Sep 20 14:28:07 2007
New Revision: 46760

Modified:
   pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py
   pypy/dist/pypy/rpython/lltypesystem/rffi.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
Log:
Implement errno support in ll2ctypes.


Modified: pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py	Thu Sep 20 14:28:07 2007
@@ -11,6 +11,7 @@
 from pypy.rpython.extfunc import ExtRegistryEntry
 from pypy.rlib.objectmodel import Symbolic
 from pypy.tool.uid import fixid
+from pypy.tool.tls import tlsobject
 from pypy.rlib.rarithmetic import r_uint
 from pypy.annotation import model as annmodel
 from pypy.rpython.rbuiltin import gen_cast
@@ -534,7 +535,9 @@
     RESULT = FUNCTYPE.RESULT
     def invoke_via_ctypes(*argvalues):
         cargs = [lltype2ctypes(value) for value in argvalues]
+        _restore_c_errno()
         cres = cfunc(*cargs)
+        _save_c_errno()
         return ctypes2lltype(RESULT, cres)
     return invoke_via_ctypes
 
@@ -578,3 +581,43 @@
         v_arg = hop.inputarg(hop.args_r[1], arg=1)
         TYPE1 = v_arg.concretetype
         return gen_cast(hop.llops, RESTYPE, v_arg)
+
+# ____________________________________________________________
+# errno
+
+# this saves in a thread-local way the "current" value that errno
+# should have in C.  We have to save it away from one external C function
+# call to the next.  Otherwise a non-zero value left behind will confuse
+# CPython itself a bit later, and/or CPython will stamp on it before we
+# try to inspect it via rffi.get_errno().
+TLS = tlsobject()
+
+# helpers to save/restore the C-level errno -- platform-specific because
+# ctypes doesn't just do the right thing and expose it directly :-(
+def _where_is_errno():
+    raise NotImplementedError("don't know how to get the C-level errno!")
+
+def _save_c_errno():
+    errno_p = _where_is_errno()
+    TLS.errno = errno_p.contents.value
+    errno_p.contents.value = 0
+
+def _restore_c_errno():
+    if hasattr(TLS, 'errno'):
+        _where_is_errno().contents.value = TLS.errno
+
+if ctypes:
+    if sys.platform == 'win32':
+        standard_c_lib._errno.restype = ctypes.POINTER(ctypes.c_int)
+        def _where_is_errno():
+            return standard_c_lib._errno()
+
+    elif sys.platform in ('linux2', 'freebsd6'):
+        standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int)
+        def _where_is_errno():
+            return standard_c_lib.__errno_location()
+
+    elif sys.platform == 'darwin':
+        standard_c_lib.__errno.restype = ctypes.POINTER(ctypes.c_int)
+        def _where_is_errno():
+            return standard_c_lib.__errno()

Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rffi.py	Thu Sep 20 14:28:07 2007
@@ -211,7 +211,7 @@
 def COpaquePtr(*args, **kwds):
     return lltype.Ptr(COpaque(*args, **kwds))
 
-def CExternVariable(TYPE, name):
+def CExternVariable(TYPE, name, _CConstantClass=CConstant):
     """Return a pair of functions - a getter and a setter - to access
     the given global C variable.
     """
@@ -221,7 +221,7 @@
     # some #include...
     assert not isinstance(TYPE, lltype.ContainerType)
     CTYPE = lltype.FixedSizeArray(TYPE, 1)
-    c_variable_ref = CConstant('(&%s)' % (name,), lltype.Ptr(CTYPE))
+    c_variable_ref = _CConstantClass('(&%s)' % (name,), lltype.Ptr(CTYPE))
     def getter():
         return c_variable_ref[0]
     def setter(newvalue):
@@ -229,7 +229,22 @@
     return (func_with_new_name(getter, '%s_getter' % (name,)),
             func_with_new_name(setter, '%s_setter' % (name,)))
 
-get_errno, set_errno = CExternVariable(lltype.Signed, 'errno')
+
+class CConstantErrno(CConstant):
+    # these accessors are used when calling get_errno() or set_errno()
+    # on top of CPython
+    def __getitem__(self, index):
+        assert index == 0
+        try:
+            return ll2ctypes.TLS.errno
+        except AttributeError:
+            raise ValueError("no C function call occurred so far, "
+                             "errno is undefined")
+    def __setitem__(self, index, value):
+        assert index == 0
+        ll2ctypes.TLS.errno = value
+
+get_errno, set_errno = CExternVariable(lltype.Signed, 'errno', CConstantErrno)
 
 # char, represented as a Python character
 # (use SIGNEDCHAR or UCHAR for the small integer types)

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py	Thu Sep 20 14:28:07 2007
@@ -516,3 +516,24 @@
         lltype.free(s1, flavor='raw')
         lltype.free(a2, flavor='raw')
         lltype.free(s2, flavor='raw')
+
+    def test_get_errno(self):
+        if sys.platform.startswith('win'):
+            underscore_on_windows = '_'
+        else:
+            underscore_on_windows = ''
+        strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T,
+                                 includes=['string.h'])
+        os_write = rffi.llexternal(underscore_on_windows+'write',
+                                   [rffi.INT, rffi.CCHARP, rffi.SIZE_T],
+                                   rffi.SIZE_T)
+        buffer = lltype.malloc(rffi.CCHARP.TO, 5, flavor='raw')
+        written = os_write(12312312, buffer, 5)
+        lltype.free(buffer, flavor='raw')
+        assert rffi.cast(lltype.Signed, written) < 0
+        # the next line is a random external function call,
+        # to check that it doesn't reset errno
+        strlen("hi!")
+        err = rffi.get_errno()
+        import errno
+        assert err == errno.EBADF



More information about the Pypy-commit mailing list