mirror of https://github.com/python/cpython.git
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.
This commit is contained in:
parent
8f22b88e28
commit
d5bb9215c9
|
@ -33,9 +33,7 @@
|
||||||
DEFAULT_MODE = RTLD_GLOBAL
|
DEFAULT_MODE = RTLD_GLOBAL
|
||||||
|
|
||||||
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \
|
||||||
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI, \
|
FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI
|
||||||
FUNCFLAG_USE_ERRNO as _FUNCFLAG_USE_ERRNO, \
|
|
||||||
FUNCFLAG_USE_LASTERROR as _FUNCFLAG_USE_LASTERROR
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
WINOLEAPI -> HRESULT
|
WINOLEAPI -> HRESULT
|
||||||
|
@ -75,9 +73,8 @@ def c_buffer(init, size=None):
|
||||||
return create_string_buffer(init, size)
|
return create_string_buffer(init, size)
|
||||||
|
|
||||||
_c_functype_cache = {}
|
_c_functype_cache = {}
|
||||||
def CFUNCTYPE(restype, *argtypes, **kw):
|
def CFUNCTYPE(restype, *argtypes):
|
||||||
"""CFUNCTYPE(restype, *argtypes,
|
"""CFUNCTYPE(restype, *argtypes) -> function prototype.
|
||||||
use_errno=False, use_last_error=False) -> function prototype.
|
|
||||||
|
|
||||||
restype: the result type
|
restype: the result type
|
||||||
argtypes: a sequence specifying the argument types
|
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((ordinal number, dll object)[, paramflags]) -> foreign function exported by ordinal
|
||||||
prototype((function name, dll object)[, paramflags]) -> foreign function exported by name
|
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:
|
try:
|
||||||
return _c_functype_cache[(restype, argtypes, flags)]
|
return _c_functype_cache[(restype, argtypes)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
class CFunctionType(_CFuncPtr):
|
class CFunctionType(_CFuncPtr):
|
||||||
_argtypes_ = argtypes
|
_argtypes_ = argtypes
|
||||||
_restype_ = restype
|
_restype_ = restype
|
||||||
_flags_ = flags
|
_flags_ = _FUNCFLAG_CDECL
|
||||||
_c_functype_cache[(restype, argtypes, flags)] = CFunctionType
|
_c_functype_cache[(restype, argtypes)] = CFunctionType
|
||||||
return CFunctionType
|
return CFunctionType
|
||||||
|
|
||||||
if _os.name in ("nt", "ce"):
|
if _os.name in ("nt", "ce"):
|
||||||
|
@ -116,23 +106,16 @@ class CFunctionType(_CFuncPtr):
|
||||||
_FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
|
_FUNCFLAG_STDCALL = _FUNCFLAG_CDECL
|
||||||
|
|
||||||
_win_functype_cache = {}
|
_win_functype_cache = {}
|
||||||
def WINFUNCTYPE(restype, *argtypes, **kw):
|
def WINFUNCTYPE(restype, *argtypes):
|
||||||
# docstring set later (very similar to CFUNCTYPE.__doc__)
|
# 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:
|
try:
|
||||||
return _win_functype_cache[(restype, argtypes, flags)]
|
return _win_functype_cache[(restype, argtypes)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
class WinFunctionType(_CFuncPtr):
|
class WinFunctionType(_CFuncPtr):
|
||||||
_argtypes_ = argtypes
|
_argtypes_ = argtypes
|
||||||
_restype_ = restype
|
_restype_ = restype
|
||||||
_flags_ = flags
|
_flags_ = _FUNCFLAG_STDCALL
|
||||||
_win_functype_cache[(restype, argtypes, flags)] = WinFunctionType
|
_win_functype_cache[(restype, argtypes)] = WinFunctionType
|
||||||
return WinFunctionType
|
return WinFunctionType
|
||||||
if WINFUNCTYPE.__doc__:
|
if WINFUNCTYPE.__doc__:
|
||||||
WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
|
WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE")
|
||||||
|
@ -141,7 +124,6 @@ class WinFunctionType(_CFuncPtr):
|
||||||
from _ctypes import dlopen as _dlopen
|
from _ctypes import dlopen as _dlopen
|
||||||
|
|
||||||
from _ctypes import sizeof, byref, addressof, alignment, resize
|
from _ctypes import sizeof, byref, addressof, alignment, resize
|
||||||
from _ctypes import get_errno, set_errno
|
|
||||||
from _ctypes import _SimpleCData
|
from _ctypes import _SimpleCData
|
||||||
|
|
||||||
def _check_size(typ, typecode=None):
|
def _check_size(typ, typecode=None):
|
||||||
|
@ -331,24 +313,12 @@ class CDLL(object):
|
||||||
Calling the functions releases the Python GIL during the call and
|
Calling the functions releases the Python GIL during the call and
|
||||||
reacquires it afterwards.
|
reacquires it afterwards.
|
||||||
"""
|
"""
|
||||||
_func_flags_ = _FUNCFLAG_CDECL
|
|
||||||
_func_restype_ = c_int
|
|
||||||
|
|
||||||
def __init__(self, name, mode=DEFAULT_MODE, handle=None,
|
|
||||||
use_errno=False,
|
|
||||||
use_last_error=False):
|
|
||||||
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):
|
class _FuncPtr(_CFuncPtr):
|
||||||
_flags_ = flags
|
_flags_ = _FUNCFLAG_CDECL
|
||||||
_restype_ = self._func_restype_
|
_restype_ = c_int # default, can be overridden in instances
|
||||||
self._FuncPtr = _FuncPtr
|
|
||||||
|
|
||||||
|
def __init__(self, name, mode=DEFAULT_MODE, handle=None):
|
||||||
|
self._name = name
|
||||||
if handle is None:
|
if handle is None:
|
||||||
self._handle = _dlopen(self._name, mode)
|
self._handle = _dlopen(self._name, mode)
|
||||||
else:
|
else:
|
||||||
|
@ -378,7 +348,9 @@ class PyDLL(CDLL):
|
||||||
access Python API functions. The GIL is not released, and
|
access Python API functions. The GIL is not released, and
|
||||||
Python exceptions are handled correctly.
|
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"):
|
if _os.name in ("nt", "ce"):
|
||||||
|
|
||||||
|
@ -386,7 +358,9 @@ class WinDLL(CDLL):
|
||||||
"""This class represents a dll exporting functions using the
|
"""This class represents a dll exporting functions using the
|
||||||
Windows stdcall calling convention.
|
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?
|
# XXX Hm, what about HRESULT as normal parameter?
|
||||||
# Mustn't it derive from c_long then?
|
# Mustn't it derive from c_long then?
|
||||||
|
@ -410,8 +384,9 @@ class OleDLL(CDLL):
|
||||||
HRESULT error values are automatically raised as WindowsError
|
HRESULT error values are automatically raised as WindowsError
|
||||||
exceptions.
|
exceptions.
|
||||||
"""
|
"""
|
||||||
_func_flags_ = _FUNCFLAG_STDCALL
|
class _FuncPtr(_CFuncPtr):
|
||||||
_func_restype_ = HRESULT
|
_flags_ = _FUNCFLAG_STDCALL
|
||||||
|
_restype_ = HRESULT
|
||||||
|
|
||||||
class LibraryLoader(object):
|
class LibraryLoader(object):
|
||||||
def __init__(self, dlltype):
|
def __init__(self, dlltype):
|
||||||
|
@ -449,7 +424,6 @@ def LoadLibrary(self, name):
|
||||||
GetLastError = windll.kernel32.GetLastError
|
GetLastError = windll.kernel32.GetLastError
|
||||||
else:
|
else:
|
||||||
GetLastError = windll.coredll.GetLastError
|
GetLastError = windll.coredll.GetLastError
|
||||||
from _ctypes import get_last_error, set_last_error
|
|
||||||
|
|
||||||
def WinError(code=None, descr=None):
|
def WinError(code=None, descr=None):
|
||||||
if code is None:
|
if code is None:
|
||||||
|
|
|
@ -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
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
- Issue #1798: Add ctypes calling convention that allows safe access
|
|
||||||
to errno.
|
|
||||||
|
|
||||||
- Patch #2125: Add GetInteger and GetString methods for
|
- Patch #2125: Add GetInteger and GetString methods for
|
||||||
msilib.Record objects.
|
msilib.Record objects.
|
||||||
|
|
||||||
|
|
|
@ -3271,7 +3271,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
thunk = AllocFunctionCallback(callable,
|
thunk = AllocFunctionCallback(callable,
|
||||||
dict->argtypes,
|
dict->argtypes,
|
||||||
dict->restype,
|
dict->restype,
|
||||||
dict->flags);
|
dict->flags & FUNCFLAG_CDECL);
|
||||||
if (!thunk)
|
if (!thunk)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -5273,17 +5273,6 @@ init_ctypes(void)
|
||||||
if (!m)
|
if (!m)
|
||||||
return;
|
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();
|
_pointer_type_cache = PyDict_New();
|
||||||
if (_pointer_type_cache == NULL)
|
if (_pointer_type_cache == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -5405,8 +5394,6 @@ init_ctypes(void)
|
||||||
PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL));
|
PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL));
|
||||||
#endif
|
#endif
|
||||||
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL));
|
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_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI));
|
||||||
PyModule_AddStringConstant(m, "__version__", "1.1.0");
|
PyModule_AddStringConstant(m, "__version__", "1.1.0");
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,6 @@ static void _CallPythonObject(void *mem,
|
||||||
SETFUNC setfunc,
|
SETFUNC setfunc,
|
||||||
PyObject *callable,
|
PyObject *callable,
|
||||||
PyObject *converters,
|
PyObject *converters,
|
||||||
int flags,
|
|
||||||
void **pArgs)
|
void **pArgs)
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
@ -272,22 +271,8 @@ static void _CallPythonObject(void *mem,
|
||||||
#define CHECK(what, x) \
|
#define CHECK(what, x) \
|
||||||
if (x == NULL) _AddTraceback(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
|
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);
|
result = PyObject_CallObject(callable, arglist);
|
||||||
CHECK("'calling callback function'", result);
|
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) {
|
if ((restype != &ffi_type_void) && result) {
|
||||||
PyObject *keep;
|
PyObject *keep;
|
||||||
assert(setfunc);
|
assert(setfunc);
|
||||||
|
@ -337,7 +322,6 @@ static void closure_fcn(ffi_cif *cif,
|
||||||
p->setfunc,
|
p->setfunc,
|
||||||
p->callable,
|
p->callable,
|
||||||
p->converters,
|
p->converters,
|
||||||
p->flags,
|
|
||||||
args);
|
args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +351,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
|
||||||
CThunkObject *AllocFunctionCallback(PyObject *callable,
|
CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||||
PyObject *converters,
|
PyObject *converters,
|
||||||
PyObject *restype,
|
PyObject *restype,
|
||||||
int flags)
|
int is_cdecl)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
CThunkObject *p;
|
CThunkObject *p;
|
||||||
|
@ -387,7 +371,6 @@ CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->flags = flags;
|
|
||||||
for (i = 0; i < nArgs; ++i) {
|
for (i = 0; i < nArgs; ++i) {
|
||||||
PyObject *cnv = PySequence_GetItem(converters, i);
|
PyObject *cnv = PySequence_GetItem(converters, i);
|
||||||
if (cnv == NULL)
|
if (cnv == NULL)
|
||||||
|
@ -415,7 +398,7 @@ CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||||
|
|
||||||
cc = FFI_DEFAULT_ABI;
|
cc = FFI_DEFAULT_ABI;
|
||||||
#if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
|
#if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64)
|
||||||
if ((flags & FUNCFLAG_CDECL) == 0)
|
if (is_cdecl == 0)
|
||||||
cc = FFI_STDCALL;
|
cc = FFI_STDCALL;
|
||||||
#endif
|
#endif
|
||||||
result = ffi_prep_cif(&p->cif, cc,
|
result = ffi_prep_cif(&p->cif, cc,
|
||||||
|
|
|
@ -83,133 +83,6 @@
|
||||||
#define DONT_USE_SEH
|
#define DONT_USE_SEH
|
||||||
#endif
|
#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
|
#ifdef MS_WIN32
|
||||||
PyObject *ComError;
|
PyObject *ComError;
|
||||||
|
|
||||||
|
@ -787,11 +660,7 @@ static int _call_function_pointer(int flags,
|
||||||
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
||||||
Py_UNBLOCK_THREADS
|
Py_UNBLOCK_THREADS
|
||||||
#endif
|
#endif
|
||||||
if (flags & FUNCFLAG_USE_ERRNO)
|
|
||||||
_swap_errno();
|
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
|
||||||
_swap_last_error();
|
|
||||||
#ifndef DONT_USE_SEH
|
#ifndef DONT_USE_SEH
|
||||||
__try {
|
__try {
|
||||||
#endif
|
#endif
|
||||||
|
@ -806,11 +675,7 @@ static int _call_function_pointer(int flags,
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (flags & FUNCFLAG_USE_LASTERROR)
|
|
||||||
_swap_last_error();
|
|
||||||
#endif
|
#endif
|
||||||
if (flags & FUNCFLAG_USE_ERRNO)
|
|
||||||
_swap_errno();
|
|
||||||
#ifdef WITH_THREAD
|
#ifdef WITH_THREAD
|
||||||
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
if ((flags & FUNCFLAG_PYTHONAPI) == 0)
|
||||||
Py_BLOCK_THREADS
|
Py_BLOCK_THREADS
|
||||||
|
@ -1802,8 +1667,6 @@ pointer(PyObject *self, PyObject *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyMethodDef module_methods[] = {
|
PyMethodDef module_methods[] = {
|
||||||
{"get_errno", get_errno, METH_NOARGS},
|
|
||||||
{"set_errno", set_errno, METH_VARARGS},
|
|
||||||
{"POINTER", POINTER, METH_O },
|
{"POINTER", POINTER, METH_O },
|
||||||
{"pointer", pointer, METH_O },
|
{"pointer", pointer, METH_O },
|
||||||
{"_unpickle", unpickle, METH_VARARGS },
|
{"_unpickle", unpickle, METH_VARARGS },
|
||||||
|
@ -1812,8 +1675,6 @@ PyMethodDef module_methods[] = {
|
||||||
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
||||||
#endif
|
#endif
|
||||||
#ifdef MS_WIN32
|
#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},
|
{"CopyComPointer", copy_com_pointer, METH_VARARGS, copy_com_pointer_doc},
|
||||||
{"FormatError", format_error, METH_VARARGS, format_error_doc},
|
{"FormatError", format_error, METH_VARARGS, format_error_doc},
|
||||||
{"LoadLibrary", load_library, METH_VARARGS, load_library_doc},
|
{"LoadLibrary", load_library, METH_VARARGS, load_library_doc},
|
||||||
|
|
|
@ -87,7 +87,6 @@ typedef struct {
|
||||||
PyObject_VAR_HEAD
|
PyObject_VAR_HEAD
|
||||||
ffi_closure *pcl; /* the C callable */
|
ffi_closure *pcl; /* the C callable */
|
||||||
ffi_cif cif;
|
ffi_cif cif;
|
||||||
int flags;
|
|
||||||
PyObject *converters;
|
PyObject *converters;
|
||||||
PyObject *callable;
|
PyObject *callable;
|
||||||
PyObject *restype;
|
PyObject *restype;
|
||||||
|
@ -186,7 +185,7 @@ extern PyMethodDef module_methods[];
|
||||||
extern CThunkObject *AllocFunctionCallback(PyObject *callable,
|
extern CThunkObject *AllocFunctionCallback(PyObject *callable,
|
||||||
PyObject *converters,
|
PyObject *converters,
|
||||||
PyObject *restype,
|
PyObject *restype,
|
||||||
int flags);
|
int stdcall);
|
||||||
/* a table entry describing a predefined ctypes type */
|
/* a table entry describing a predefined ctypes type */
|
||||||
struct fielddesc {
|
struct fielddesc {
|
||||||
char code;
|
char code;
|
||||||
|
@ -304,8 +303,6 @@ PyObject *_CallProc(PPROC pProc,
|
||||||
#define FUNCFLAG_CDECL 0x1
|
#define FUNCFLAG_CDECL 0x1
|
||||||
#define FUNCFLAG_HRESULT 0x2
|
#define FUNCFLAG_HRESULT 0x2
|
||||||
#define FUNCFLAG_PYTHONAPI 0x4
|
#define FUNCFLAG_PYTHONAPI 0x4
|
||||||
#define FUNCFLAG_USE_ERRNO 0x8
|
|
||||||
#define FUNCFLAG_USE_LASTERROR 0x10
|
|
||||||
|
|
||||||
#define TYPEFLAG_ISPOINTER 0x100
|
#define TYPEFLAG_ISPOINTER 0x100
|
||||||
#define TYPEFLAG_HASPOINTER 0x200
|
#define TYPEFLAG_HASPOINTER 0x200
|
||||||
|
@ -424,16 +421,8 @@ extern int IsSimpleSubType(PyObject *obj);
|
||||||
|
|
||||||
extern PyObject *_pointer_type_cache;
|
extern PyObject *_pointer_type_cache;
|
||||||
|
|
||||||
extern void _swap_errno(void);
|
|
||||||
|
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
|
|
||||||
extern void _swap_last_error(void);
|
|
||||||
|
|
||||||
extern PyObject *ComError;
|
extern PyObject *ComError;
|
||||||
|
|
||||||
extern DWORD dwTlsIndex_LastError;
|
|
||||||
extern DWORD dwTlsIndex_errno;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue