[Python-checkins] r63945 - in python/trunk: Lib/ctypes/__init__.py Lib/ctypes/test/test_errno.py Misc/NEWS Modules/_ctypes/_ctypes.c Modules/_ctypes/callbacks.c Modules/_ctypes/callproc.c Modules/_ctypes/ctypes.h

thomas.heller python-checkins at python.org
Wed Jun 4 22:22:06 CEST 2008


Author: thomas.heller
Date: Wed Jun  4 22:22:05 2008
New Revision: 63945

Log:
Revert revisions 63943 and 63942 (Issue #1798: Add ctypes calling
convention that allows safe access to errno)

This code does not yet work on OS X (__thread storage specifier not
available), so i needs a configure check plus a more portable
solution.


Removed:
   python/trunk/Lib/ctypes/test/test_errno.py
Modified:
   python/trunk/Lib/ctypes/__init__.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/_ctypes/_ctypes.c
   python/trunk/Modules/_ctypes/callbacks.c
   python/trunk/Modules/_ctypes/callproc.c
   python/trunk/Modules/_ctypes/ctypes.h

Modified: python/trunk/Lib/ctypes/__init__.py
==============================================================================
--- python/trunk/Lib/ctypes/__init__.py	(original)
+++ python/trunk/Lib/ctypes/__init__.py	Wed Jun  4 22:22:05 2008
@@ -33,9 +33,7 @@
         DEFAULT_MODE = RTLD_GLOBAL
 
 from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
-     FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
-     FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
-     FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
+     FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI
 
 """
 WINOLEAPI -> HRESULT
@@ -75,9 +73,8 @@
     return create_string_buffer(init, size)
 
 _c_functype_cache = {}
-def CFUNCTYPE(restype, *argtypes, **kw):
-    """CFUNCTYPE(restype, *argtypes,
-                 use_errno=False, use_last_error=False) -> function prototype.
+def CFUNCTYPE(restype, *argtypes):
+    """CFUNCTYPE(restype, *argtypes) -> function prototype.
 
     restype: the result type
     argtypes: a sequence specifying the argument types
@@ -91,21 +88,14 @@
     prototype((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
     prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
     """
-    flags = _FUNCFLAG_CDECL
-    if kw.pop("use_errno", False):
-        flags |= _FUNCFLAG_USE_ERRNO
-    if kw.pop("use_last_error", False):
-        flags |= _FUNCFLAG_USE_LASTERROR
-    if kw:
-        raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
     try:
-        return _c_functype_cache[(restype, argtypes, flags)]
+        return _c_functype_cache[(restype, argtypes)]
     except KeyError:
         class CFunctionType(_CFuncPtr):
             _argtypes_ = argtypes
             _restype_ = restype
-            _flags_ = flags
-        _c_functype_cache[(restype, argtypes, flags)] = CFunctionType
+            _flags_ = _FUNCFLAG_CDECL
+        _c_functype_cache[(restype, argtypes)] = CFunctionType
         return CFunctionType
 
 if _os.name in ("nt", "ce"):
@@ -116,23 +106,16 @@
         _FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
 
     _win_functype_cache = {}
-    def WINFUNCTYPE(restype, *argtypes, **kw):
+    def WINFUNCTYPE(restype, *argtypes):
         # docstring set later (very similar to CFUNCTYPE.__doc__)
-        flags = _FUNCFLAG_STDCALL
-        if kw.pop("use_errno", False):
-            flags |= _FUNCFLAG_USE_ERRNO
-        if kw.pop("use_last_error", False):
-            flags |= _FUNCFLAG_USE_LASTERROR
-        if kw:
-            raise ValueError("unexpected keyword argument(s) %s" % kw.keys())
         try:
-            return _win_functype_cache[(restype, argtypes, flags)]
+            return _win_functype_cache[(restype, argtypes)]
         except KeyError:
             class WinFunctionType(_CFuncPtr):
                 _argtypes_ = argtypes
                 _restype_ = restype
-                _flags_ = flags
-            _win_functype_cache[(restype, argtypes, flags)] = WinFunctionType
+                _flags_ = _FUNCFLAG_STDCALL
+            _win_functype_cache[(restype, argtypes)] = WinFunctionType
             return WinFunctionType
     if WINFUNCTYPE.__doc__:
         WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
@@ -141,7 +124,6 @@
     from _ctypes import dlopen as _dlopen
 
 from _ctypes import sizeof, byref, addressof, alignment, resize
-from _ctypes import get_errno, set_errno
 from _ctypes import _SimpleCData
 
 def _check_size(typ, typecode=None):
@@ -331,24 +313,12 @@
     Calling the functions releases the Python GIL during the call and
     reacquires it afterwards.
     """
-    _func_flags_ = _FUNCFLAG_CDECL
-    _func_restype_ = c_int
+    class _FuncPtr(_CFuncPtr):
+        _flags_ = _FUNCFLAG_CDECL
+        _restype_ = c_int # default, can be overridden in instances
 
-    def __init__(self, name, mode=DEFAULT_MODE, handle=None,
-                 use_errno=False,
-                 use_last_error=False):
+    def __init__(self, name, mode=DEFAULT_MODE, handle=None):
         self._name = name
-        flags = self._func_flags_
-        if use_errno:
-            flags |= _FUNCFLAG_USE_ERRNO
-        if use_last_error:
-            flags |= _FUNCFLAG_USE_LASTERROR
-
-        class _FuncPtr(_CFuncPtr):
-            _flags_ = flags
-            _restype_ = self._func_restype_
-        self._FuncPtr = _FuncPtr
-
         if handle is None:
             self._handle = _dlopen(self._name, mode)
         else:
@@ -378,7 +348,9 @@
     access Python API functions.  The GIL is not released, and
     Python exceptions are handled correctly.
     """
-    _func_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
+    class _FuncPtr(_CFuncPtr):
+        _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
+        _restype_ = c_int # default, can be overridden in instances
 
 if _os.name in ("nt", "ce"):
 
@@ -386,7 +358,9 @@
         """This class represents a dll exporting functions using the
         Windows stdcall calling convention.
         """
-        _func_flags_ = _FUNCFLAG_STDCALL
+        class _FuncPtr(_CFuncPtr):
+            _flags_ = _FUNCFLAG_STDCALL
+            _restype_ = c_int # default, can be overridden in instances
 
     # XXX Hm, what about HRESULT as normal parameter?
     # Mustn't it derive from c_long then?
@@ -410,8 +384,9 @@
         HRESULT error values are automatically raised as WindowsError
         exceptions.
         """
-        _func_flags_ = _FUNCFLAG_STDCALL
-        _func_restype_ = HRESULT
+        class _FuncPtr(_CFuncPtr):
+            _flags_ = _FUNCFLAG_STDCALL
+            _restype_ = HRESULT
 
 class LibraryLoader(object):
     def __init__(self, dlltype):
@@ -449,7 +424,6 @@
         GetLastError = windll.kernel32.GetLastError
     else:
         GetLastError = windll.coredll.GetLastError
-    from _ctypes import get_last_error, set_last_error
 
     def WinError(code=None, descr=None):
         if code is None:

Deleted: python/trunk/Lib/ctypes/test/test_errno.py
==============================================================================
--- python/trunk/Lib/ctypes/test/test_errno.py	Wed Jun  4 22:22:05 2008
+++ (empty file)
@@ -1,76 +0,0 @@
-import unittest, os, errno
-from ctypes import *
-from ctypes.util import find_library
-import threading
-
-class Test(unittest.TestCase):
-    def test_open(self):
-        libc_name = find_library("c")
-        if libc_name is not None:
-            libc = CDLL(libc_name, use_errno=True)
-            if os.name == "nt":
-                libc_open = libc._open
-            else:
-                libc_open = libc.open
-
-            libc_open.argtypes = c_char_p, c_int
-
-            self.failUnlessEqual(libc_open("", 0), -1)
-            self.failUnlessEqual(get_errno(), errno.ENOENT)
-
-            self.failUnlessEqual(set_errno(32), errno.ENOENT)
-            self.failUnlessEqual(get_errno(), 32)
-
-
-            def _worker():
-                set_errno(0)
-
-                libc = CDLL(libc_name, use_errno=False)
-                if os.name == "nt":
-                    libc_open = libc._open
-                else:
-                    libc_open = libc.open
-                libc_open.argtypes = c_char_p, c_int
-                self.failUnlessEqual(libc_open("", 0), -1)
-                self.failUnlessEqual(get_errno(), 0)
-
-            t = threading.Thread(target=_worker)
-            t.start()
-            t.join()
-
-            self.failUnlessEqual(get_errno(), 32)
-            set_errno(0)
-
-    if os.name == "nt":
-
-        def test_GetLastError(self):
-            dll = WinDLL("kernel32", use_last_error=True)
-            GetModuleHandle = dll.GetModuleHandleA
-            GetModuleHandle.argtypes = [c_wchar_p]
-
-            self.failUnlessEqual(0, GetModuleHandle("foo"))
-            self.failUnlessEqual(get_last_error(), 126)
-
-            self.failUnlessEqual(set_last_error(32), 126)
-            self.failUnlessEqual(get_last_error(), 32)
-
-            def _worker():
-                set_last_error(0)
-
-                dll = WinDLL("kernel32", use_last_error=False)
-                GetModuleHandle = dll.GetModuleHandleW
-                GetModuleHandle.argtypes = [c_wchar_p]
-                GetModuleHandle("bar")
-
-                self.failUnlessEqual(get_last_error(), 0)
-
-            t = threading.Thread(target=_worker)
-            t.start()
-            t.join()
-
-            self.failUnlessEqual(get_last_error(), 32)
-
-            set_last_error(0)
-
-if __name__ == "__main__":
-    unittest.main()

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Wed Jun  4 22:22:05 2008
@@ -72,9 +72,6 @@
 Library
 -------
 
-- Issue #1798: Add ctypes calling convention that allows safe access
-  to errno.
-
 - Patch #2125: Add GetInteger and GetString methods for 
   msilib.Record objects.
 

Modified: python/trunk/Modules/_ctypes/_ctypes.c
==============================================================================
--- python/trunk/Modules/_ctypes/_ctypes.c	(original)
+++ python/trunk/Modules/_ctypes/_ctypes.c	Wed Jun  4 22:22:05 2008
@@ -3271,7 +3271,7 @@
 	thunk = AllocFunctionCallback(callable,
 				      dict->argtypes,
 				      dict->restype,
-				      dict->flags);
+				      dict->flags & FUNCFLAG_CDECL);
 	if (!thunk)
 		return NULL;
 
@@ -5273,17 +5273,6 @@
 	if (!m)
 		return;
 
-#ifdef MS_WIN32
-	dwTlsIndex_LastError = TlsAlloc();
-	dwTlsIndex_errno = TlsAlloc();
-	if (dwTlsIndex_LastError == TLS_OUT_OF_INDEXES
-	    || dwTlsIndex_errno == TLS_OUT_OF_INDEXES) {
-		PyErr_SetString(PyExc_MemoryError,
-				"Could not allocate TLSIndex for LastError value");
-		return;
-	}
-#endif
-
 	_pointer_type_cache = PyDict_New();
 	if (_pointer_type_cache == NULL)
 		return;
@@ -5405,8 +5394,6 @@
 	PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL));
 #endif
 	PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL));
-	PyModule_AddObject(m, "FUNCFLAG_USE_ERRNO", PyInt_FromLong(FUNCFLAG_USE_ERRNO));
-	PyModule_AddObject(m, "FUNCFLAG_USE_LASTERROR", PyInt_FromLong(FUNCFLAG_USE_LASTERROR));
 	PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI));
 	PyModule_AddStringConstant(m, "__version__", "1.1.0");
 

Modified: python/trunk/Modules/_ctypes/callbacks.c
==============================================================================
--- python/trunk/Modules/_ctypes/callbacks.c	(original)
+++ python/trunk/Modules/_ctypes/callbacks.c	Wed Jun  4 22:22:05 2008
@@ -189,7 +189,6 @@
 			      SETFUNC setfunc,
 			      PyObject *callable,
 			      PyObject *converters,
-			      int flags,
 			      void **pArgs)
 {
 	Py_ssize_t i;
@@ -272,22 +271,8 @@
 #define CHECK(what, x) \
 if (x == NULL) _AddTraceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
 
-	if (flags & FUNCFLAG_USE_ERRNO)
-		_swap_errno();
-#ifdef MS_WIN32
-	if (flags & FUNCFLAG_USE_LASTERROR)
-		_swap_last_error();
-#endif
-
 	result = PyObject_CallObject(callable, arglist);
 	CHECK("'calling callback function'", result);
-
-#ifdef MS_WIN32
-	if (flags & FUNCFLAG_USE_LASTERROR)
-		_swap_last_error();
-#endif
-	if (flags & FUNCFLAG_USE_ERRNO)
-		_swap_errno();
 	if ((restype != &ffi_type_void) && result) {
 		PyObject *keep;
 		assert(setfunc);
@@ -337,7 +322,6 @@
 			  p->setfunc,
 			  p->callable,
 			  p->converters,
-			  p->flags,
 			  args);
 }
 
@@ -367,7 +351,7 @@
 CThunkObject *AllocFunctionCallback(PyObject *callable,
 				    PyObject *converters,
 				    PyObject *restype,
-				    int flags)
+				    int is_cdecl)
 {
 	int result;
 	CThunkObject *p;
@@ -387,7 +371,6 @@
 		goto error;
 	}
 
-	p->flags = flags;
 	for (i = 0; i < nArgs; ++i) {
 		PyObject *cnv = PySequence_GetItem(converters, i);
 		if (cnv == NULL)
@@ -415,7 +398,7 @@
 
 	cc = FFI_DEFAULT_ABI;
 #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
-	if ((flags & FUNCFLAG_CDECL) == 0)
+	if (is_cdecl == 0)
 		cc = FFI_STDCALL;
 #endif
 	result = ffi_prep_cif(&p->cif, cc,

Modified: python/trunk/Modules/_ctypes/callproc.c
==============================================================================
--- python/trunk/Modules/_ctypes/callproc.c	(original)
+++ python/trunk/Modules/_ctypes/callproc.c	Wed Jun  4 22:22:05 2008
@@ -83,133 +83,6 @@
 #define DONT_USE_SEH
 #endif
 
-/*
-  ctypes maintains a module-global, but thread-local, variable that contains
-  an error number; called 'ctypes_errno' for this discussion.  This variable
-  is a private copy of the systems 'errno' value; the copy is swapped with the
-  'errno' variable on several occasions.
-
-  Foreign functions created with CDLL(..., use_errno=True), when called, swap
-  the values just before the actual function call, and swapped again
-  immediately afterwards.  The 'use_errno' parameter defaults to False, in
-  this case 'ctypes_errno' is not touched.
-
-  The values are also swapped immeditately before and after ctypes callback
-  functions are called, if the callbacks are constructed using the new
-  optional use_errno parameter set to True: CFUNCTYPE(..., use_errno=TRUE) or
-  WINFUNCTYPE(..., use_errno=True).
-
-  Two new ctypes functions are provided to access the 'ctypes_errno' value
-  from Python:
-
-  - ctypes.set_errno(value) sets ctypes_errno to 'value', the previous
-    ctypes_errno value is returned.
-
-  - ctypes.get_errno() returns the current ctypes_errno value.
-
-  ---
-
-  On Windows, the same scheme is implemented for the error value which is
-  managed by the GetLastError() and SetLastError() windows api calls.
-
-  The ctypes functions are 'ctypes.set_last_error(value)' and
-  'ctypes.get_last_error()', the CDLL and WinDLL optional parameter is named
-  'use_last_error', defaults to False.
-
-  ---
-
-  On Windows, TlsSetValue and TlsGetValue calls are used to provide thread
-  local storage for the variables; ctypes compiled with __GNUC__ uses __thread
-  variables.
-*/
-
-#if defined(MS_WIN32)
-DWORD dwTlsIndex_LastError;
-DWORD dwTlsIndex_errno;
-
-void
-_swap_last_error(void)
-{
-	DWORD temp = GetLastError();
-	SetLastError((DWORD)TlsGetValue(dwTlsIndex_LastError));
-	TlsSetValue(dwTlsIndex_LastError, (void *)temp);
-}
-
-static PyObject *
-get_last_error(PyObject *self, PyObject *args)
-{
-	return PyInt_FromLong((DWORD)TlsGetValue(dwTlsIndex_LastError));
-}
-
-static PyObject *
-set_last_error(PyObject *self, PyObject *args)
-{
-	DWORD new_value, prev_value;
-	if (!PyArg_ParseTuple(args, "i", &new_value))
-		return NULL;
-	prev_value = (DWORD)TlsGetValue(dwTlsIndex_LastError);
-	TlsSetValue(dwTlsIndex_LastError, (void *)new_value);
-	return PyInt_FromLong(prev_value);
-}
-
-void
-_swap_errno(void)
-{
-	int temp = errno;
-	errno = (int)TlsGetValue(dwTlsIndex_errno);
-	TlsSetValue(dwTlsIndex_errno, (void *)temp);
-}
-
-static PyObject *
-get_errno(PyObject *self, PyObject *args)
-{
-	return PyInt_FromLong((int)TlsGetValue(dwTlsIndex_errno));
-}
-
-static PyObject *
-set_errno(PyObject *self, PyObject *args)
-{
-	int new_value, prev_value;
-	if (!PyArg_ParseTuple(args, "i", &new_value))
-		return NULL;
-	prev_value = (int)TlsGetValue(dwTlsIndex_errno);
-	TlsSetValue(dwTlsIndex_errno, (void *)new_value);
-	return PyInt_FromLong(prev_value);
-}
-
-#elif defined(__GNUC__)
-static __thread int ctypes_errno;
-
-void
-_swap_errno(void)
-{
-	int temp = errno;
-	errno = ctypes_errno;
-	ctypes_errno = temp;
-}
-
-static PyObject *
-get_errno(PyObject *self, PyObject *args)
-{
-	return PyInt_FromLong(ctypes_errno);
-}
-
-static PyObject *
-set_errno(PyObject *self, PyObject *args)
-{
-	int new_errno, prev_errno;
-	if (!PyArg_ParseTuple(args, "i", &new_errno))
-		return NULL;
-	prev_errno = ctypes_errno;
-	ctypes_errno = new_errno;
-	return PyInt_FromLong(prev_errno);
-}
-#else
-
-#error "TLS not implemented in this configuration"
-
-#endif
-
 #ifdef MS_WIN32
 PyObject *ComError;
 
@@ -787,11 +660,7 @@
 	if ((flags & FUNCFLAG_PYTHONAPI) == 0)
 		Py_UNBLOCK_THREADS
 #endif
-	if (flags & FUNCFLAG_USE_ERRNO)
-		_swap_errno();
 #ifdef MS_WIN32
-	if (flags & FUNCFLAG_USE_LASTERROR)
-		_swap_last_error();
 #ifndef DONT_USE_SEH
 	__try {
 #endif
@@ -806,11 +675,7 @@
 		;
 	}
 #endif
-	if (flags & FUNCFLAG_USE_LASTERROR)
-		_swap_last_error();
 #endif
-	if (flags & FUNCFLAG_USE_ERRNO)
-		_swap_errno();
 #ifdef WITH_THREAD
 	if ((flags & FUNCFLAG_PYTHONAPI) == 0)
 		Py_BLOCK_THREADS
@@ -1802,8 +1667,6 @@
 }
 
 PyMethodDef module_methods[] = {
-	{"get_errno", get_errno, METH_NOARGS},
-	{"set_errno", set_errno, METH_VARARGS},
 	{"POINTER", POINTER, METH_O },
 	{"pointer", pointer, METH_O },
 	{"_unpickle", unpickle, METH_VARARGS },
@@ -1812,8 +1675,6 @@
 	{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
 #endif
 #ifdef MS_WIN32
-	{"get_last_error", get_last_error, METH_NOARGS},
-	{"set_last_error", set_last_error, METH_VARARGS},
 	{"CopyComPointer", copy_com_pointer, METH_VARARGS, copy_com_pointer_doc},
 	{"FormatError", format_error, METH_VARARGS, format_error_doc},
 	{"LoadLibrary", load_library, METH_VARARGS, load_library_doc},

Modified: python/trunk/Modules/_ctypes/ctypes.h
==============================================================================
--- python/trunk/Modules/_ctypes/ctypes.h	(original)
+++ python/trunk/Modules/_ctypes/ctypes.h	Wed Jun  4 22:22:05 2008
@@ -87,7 +87,6 @@
 	PyObject_VAR_HEAD
 	ffi_closure *pcl; /* the C callable */
 	ffi_cif cif;
-	int flags;
 	PyObject *converters;
 	PyObject *callable;
 	PyObject *restype;
@@ -186,7 +185,7 @@
 extern CThunkObject *AllocFunctionCallback(PyObject *callable,
 					   PyObject *converters,
 					   PyObject *restype,
-					   int flags);
+					   int stdcall);
 /* a table entry describing a predefined ctypes type */
 struct fielddesc {
 	char code;
@@ -304,8 +303,6 @@
 #define FUNCFLAG_CDECL   0x1
 #define FUNCFLAG_HRESULT 0x2
 #define FUNCFLAG_PYTHONAPI 0x4
-#define FUNCFLAG_USE_ERRNO 0x8
-#define FUNCFLAG_USE_LASTERROR 0x10
 
 #define TYPEFLAG_ISPOINTER 0x100
 #define TYPEFLAG_HASPOINTER 0x200
@@ -424,16 +421,8 @@
 
 extern PyObject *_pointer_type_cache;
 
-extern void _swap_errno(void);
-
 #ifdef MS_WIN32
-
-extern void _swap_last_error(void);
-
 extern PyObject *ComError;
-
-extern DWORD dwTlsIndex_LastError;
-extern DWORD dwTlsIndex_errno;
 #endif
 
 /*


More information about the Python-checkins mailing list