[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