diff options
-rw-r--r-- | Lib/ctypes/__init__.py | 72 | ||||
-rw-r--r-- | Lib/ctypes/test/test_errno.py | 76 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_ctypes/_ctypes.c | 15 | ||||
-rw-r--r-- | Modules/_ctypes/callbacks.c | 21 | ||||
-rw-r--r-- | Modules/_ctypes/callproc.c | 139 | ||||
-rw-r--r-- | Modules/_ctypes/ctypes.h | 13 |
7 files changed, 27 insertions, 312 deletions
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index d3e11dc..41d39dc 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -33,9 +33,7 @@ if _os.name == "posix" and _sys.platform == "darwin": 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 @@ def c_buffer(init, size=None): 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 @@ def CFUNCTYPE(restype, *argtypes, **kw): 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 @@ if _os.name in ("nt", "ce"): _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 @@ elif _os.name == "posix": 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 @@ class CDLL(object): 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 @@ class PyDLL(CDLL): 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 @@ if _os.name in ("nt", "ce"): """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 @@ if _os.name in ("nt", "ce"): 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 @@ if _os.name in ("nt", "ce"): 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: diff --git a/Lib/ctypes/test/test_errno.py b/Lib/ctypes/test/test_errno.py deleted file mode 100644 index b80656b..0000000 --- a/Lib/ctypes/test/test_errno.py +++ /dev/null @@ -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() @@ -72,9 +72,6 @@ Extension Modules Library ------- -- Issue #1798: Add ctypes calling convention that allows safe access - to errno. - - Patch #2125: Add GetInteger and GetString methods for msilib.Record objects. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 7deb3f3..740b7f6 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -3271,7 +3271,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) thunk = AllocFunctionCallback(callable, dict->argtypes, dict->restype, - dict->flags); + dict->flags & FUNCFLAG_CDECL); if (!thunk) return NULL; @@ -5273,17 +5273,6 @@ init_ctypes(void) 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 @@ init_ctypes(void) 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"); diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 78c7419..b78c528 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -189,7 +189,6 @@ static void _CallPythonObject(void *mem, SETFUNC setfunc, PyObject *callable, PyObject *converters, - int flags, void **pArgs) { Py_ssize_t i; @@ -272,22 +271,8 @@ static void _CallPythonObject(void *mem, #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 @@ static void closure_fcn(ffi_cif *cif, p->setfunc, p->callable, p->converters, - p->flags, args); } @@ -367,7 +351,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs) CThunkObject *AllocFunctionCallback(PyObject *callable, PyObject *converters, PyObject *restype, - int flags) + int is_cdecl) { int result; CThunkObject *p; @@ -387,7 +371,6 @@ CThunkObject *AllocFunctionCallback(PyObject *callable, goto error; } - p->flags = flags; for (i = 0; i < nArgs; ++i) { PyObject *cnv = PySequence_GetItem(converters, i); if (cnv == NULL) @@ -415,7 +398,7 @@ CThunkObject *AllocFunctionCallback(PyObject *callable, 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, diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index aa297af..95b2709 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -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 @@ static int _call_function_pointer(int flags, 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 @@ static int _call_function_pointer(int flags, ; } #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 @@ pointer(PyObject *self, PyObject *arg) } 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 @@ PyMethodDef module_methods[] = { {"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}, diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index a7c3562..1a104cf 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -87,7 +87,6 @@ typedef struct { 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 PyMethodDef module_methods[]; 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 @@ PyObject *_CallProc(PPROC pProc, #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 int IsSimpleSubType(PyObject *obj); 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 /* |