simplify the thread implementation, use feature 'nothread' to disable threads instead of 'thread' to enable them, plus other fixes around threads

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7933 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Marcelo Matus 2005-12-06 19:35:03 +00:00
commit 2eeef5275d
6 changed files with 62 additions and 101 deletions

View file

@ -21,49 +21,32 @@ Version 1.3.28 (unreleased).
1.- the module thread support is enable via the "threads" module
option, ie
%module("threads"=1)
2.- For each method you want to add full thread support, you
should use the "threads" feature, as in
%feature("threads") method;
or in the directive form
%threads method;
3.- Since threads is a feature, you can enable it for the
entire interface as follow
%module("threads"=1)
%threads;
4.- Equivalent to that, is the following swig option
2.- Equivalent to that, is the following swig option
swig -threads -python ...
ie, swig enables thread support for the module and all
the methods.
ie, swig enables thread support for the module.
5.- You can partially disable thread support for each
3.- You can partially disable thread support for a given
method using:
%feature("nothreads") method;
%feature("nothread") method;
also, you can disable sections of the thread support,
for example
%feature("nothreadsblock") method;
%feature("nothreadsallow") method;
%feature("nothreadblock") method;
%feature("nothreadallow") method;
the first disable the C++/python thread protection, and the
second the python/C++ thread protection. See
pythreads.swg for more information.
the first disables the C++/python thread protection, and the
second disables the python/C++ thread protection.
6.- The current thread support is based in the PyGIL
4.- The current thread support is based in the PyGIL
extension present in python version 2.3 or later, but
you can provide the thread code for older versions by
defining the macros described in pythreads.swg.
defining the macros in pythreads.swg.
If you get a working implementation for older versions,
please send us a patch.

View file

@ -8,7 +8,6 @@ class Foo;
extern "C" void* working(void* t);
%}
%threads;
%director Foo;
%inline {

View file

@ -643,7 +643,6 @@ SWIG_Python_GetSwigThis(PyObject *pyobj)
if (pyobj && PySwigObject_Check(pyobj)) {
return (PySwigObject *) pyobj;
} else {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyObject *obj = 0;
#ifndef SWIG_PYTHON_SLOW_GETSET_THIS
if (PyInstance_Check(pyobj)) {
@ -664,13 +663,11 @@ SWIG_Python_GetSwigThis(PyObject *pyobj)
#endif
if (!obj || PyErr_Occurred()) {
PyErr_Clear();
SWIG_PYTHON_THREAD_END_BLOCK;
return 0;
}
if (!PySwigObject_Check(obj)) {
obj = 0;
}
SWIG_PYTHON_THREAD_END_BLOCK;
return (PySwigObject *)obj;
}
}
@ -828,11 +825,9 @@ SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) {
if (!ptr) {
return SWIG_Py_Void();
} else if (!type) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError, "Swig: null type passed to NewPointerObj");
}
SWIG_PYTHON_THREAD_END_BLOCK;
return NULL;
} else {
int own = (flags & SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0;
@ -872,7 +867,6 @@ void *SWIG_ReturnGlobalTypeList(void *);
SWIGRUNTIME swig_module_info *
SWIG_Python_GetModule(void) {
static void *type_pointer = (void *)0;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
/* first check if module already created */
if (!type_pointer) {
#ifdef SWIG_LINK_RUNTIME
@ -886,7 +880,6 @@ SWIG_Python_GetModule(void) {
}
#endif
}
SWIG_PYTHON_THREAD_END_BLOCK;
return (swig_module_info *) type_pointer;
}
@ -898,27 +891,21 @@ PyModule_AddObject(PyObject *m, char *name, PyObject *o)
{
PyObject *dict;
if (!PyModule_Check(m)) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_TypeError,
"PyModule_AddObject() needs module as first arg");
SWIG_PYTHON_THREAD_END_BLOCK;
return SWIG_ERROR;
}
if (!o) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_TypeError,
"PyModule_AddObject() needs non-NULL value");
SWIG_PYTHON_THREAD_END_BLOCK;
return SWIG_ERROR;
}
dict = PyModule_GetDict(m);
if (dict == NULL) {
/* Internal error -- modules must have a dict! */
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__",
PyModule_GetName(m));
SWIG_PYTHON_THREAD_END_BLOCK;
return SWIG_ERROR;
}
if (PyDict_SetItemString(dict, name, o))

View file

@ -1,24 +1,22 @@
#if defined(SWIG_PYTHON_NO_THREADING)
# if defined(SWIG_PYTHON_THREADING)
# undef SWIG_PYTHON_THREADING
#if defined(SWIG_PYTHON_NO_THREADS)
# if defined(SWIG_PYTHON_THREADS)
# undef SWIG_PYTHON_THREADS
# endif
#endif
#if defined(SWIG_PYTHON_THREADING) /* Threading support is enabled */
#if defined(SWIG_PYTHON_THREADS) /* Threading support is enabled */
# if !defined(SWIG_PYTHON_USE_GIL) && !defined(SWIG_PYTHON_NO_USE_GIL)
# if (PY_VERSION_HEX >= 0x02030000) /* For 2.3 or later, use the PyGILState calls */
# define SWIG_PYTHON_USE_GIL
# endif
# endif
# if defined(SWIG_PYTHON_USE_GIL) /* Use PyGILState threads calls */
# if !defined(SWIG_PYTHON_INITIALIZE_THREADING)
# define SWIG_PYTHON_INITIALIZE_THREADING PyEval_InitThreads()
# endif
# ifdef __cplusplus
# define SWIG_PYTHON_INITIALIZE_THREADS PyEval_InitThreads()
# ifdef __cplusplus /* C++ code */
class SWIG_Python_Thread_Block {
bool status;
PyGILState_STATE state;
public:
void begin() { if (!status) { state = PyGILState_Ensure(); status = true;} }
public:
void end() { if (status) { PyGILState_Release(state); status = false;} }
SWIG_Python_Thread_Block() : status(false) { begin(); }
~SWIG_Python_Thread_Block() { end(); }
@ -26,8 +24,8 @@
class SWIG_Python_Thread_Allow {
bool status;
PyThreadState *save;
void begin() { if (!status) { status = true; save = PyEval_SaveThread(); } }
public:
void begin() { if (!status) { status = true; save = PyEval_SaveThread(); }}
void end() { if (status) { PyEval_RestoreThread(save); status = false; }}
SWIG_Python_Thread_Allow() : status(false) { begin(); }
~SWIG_Python_Thread_Allow() { end(); }
@ -36,15 +34,15 @@
# define SWIG_PYTHON_THREAD_END_BLOCK _swig_thread_block.end()
# define SWIG_PYTHON_THREAD_BEGIN_ALLOW SWIG_Python_Thread_Allow _swig_thread_allow
# define SWIG_PYTHON_THREAD_END_ALLOW _swig_thread_allow.end()
# else /* C++ */
# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_allow = PyGILState_Ensure()
# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_allow)
# define SWIG_PYTHON_THREAD_BEGIN_ALLOW Py_BEGIN_ALLOW_THREADS
# define SWIG_PYTHON_THREAD_END_ALLOW Py_END_ALLOW_THREADS
# else /* C code */
# define SWIG_PYTHON_THREAD_BEGIN_BLOCK PyGILState_STATE _swig_thread_block = PyGILState_Ensure()
# define SWIG_PYTHON_THREAD_END_BLOCK PyGILState_Release(_swig_thread_block)
# define SWIG_PYTHON_THREAD_BEGIN_ALLOW PyThreadState *_swig_thread_allow = PyEval_SaveThread()
# define SWIG_PYTHON_THREAD_END_ALLOW PyEval_RestoreThread(_swig_thread_allow)
# endif
# else /* Old thread way, not implemented, user must provide it */
# if !defined(SWIG_PYTHON_INITIALIZE_THREADING)
# define SWIG_PYTHON_INITIALIZE_THREADING
# if !defined(SWIG_PYTHON_INITIALIZE_THREADS)
# define SWIG_PYTHON_INITIALIZE_THREADS
# endif
# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK)
# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
@ -60,7 +58,7 @@
# endif
# endif
#else /* No thread support */
# define SWIG_PYTHON_INITIALIZE_THREADING
# define SWIG_PYTHON_INITIALIZE_THREADS
# define SWIG_PYTHON_THREAD_BEGIN_BLOCK
# define SWIG_PYTHON_THREAD_END_BLOCK
# define SWIG_PYTHON_THREAD_BEGIN_ALLOW

View file

@ -1,15 +1,15 @@
/* -----------------------------------------------------------------------------
/* -------------------------------------------------------------------------
* Special user directives
* ----------------------------------------------------------------------------- */
* ------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* shadow code */
#define %shadow %insert("shadow")
#define %pythoncode %insert("python")
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
Use the "nondynamic" feature to make a wrapped class behaves as a "nondynamic"
one, ie, a python class that doesn't dynamically add new attributes.
@ -51,7 +51,7 @@ so, it works with old python versions.
#define %pythondynamic %nopythonnondynamic
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
Use %pythonmaybecall to flag a method like __add__ or __radd__, which
@ -65,7 +65,7 @@ These methods "may be called" if needed.
#define %nopythonmaybecall %feature("python:maybecall", "0")
#define %clearpythonmaybecall %feature("python:maybecall", "")
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
The %pythoncallback feature produce a more natural callback wrap
than the %callback mechanism, ie, it use the original name for
@ -111,7 +111,7 @@ These methods "may be called" if needed.
#define %nopythoncallback %feature("python:callback","0")
#define %clearpythoncallback %feature("python:callback","")
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
Support for the old %callback directive name
*/
@ -131,14 +131,15 @@ These methods "may be called" if needed.
#define %nocallback %nopythoncallback
#define %clearcallback %clearpythoncallback
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
Thread support
Thread support - Advance control
*/
#define %threads %feature("threads")
#define %nothreads %feature("threads","0")
#define %clearthreads %feature("threads","")
#define %nothread %feature("nothread")
#define %thread %feature("nothread","0")
#define %clearnothread %feature("nothread","")
#define %nothreadblock %feature("nothreadblock")
#define %threadblock %feature("nothreadblock","0")
@ -149,7 +150,7 @@ These methods "may be called" if needed.
#define %clearnothreadallow %feature("nothreadallow","")
/* ----------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
Directors
*/

View file

@ -58,6 +58,7 @@ static String *real_classname;
/* Thread Support */
static int threads = 0;
static int nothreads = 0;
/* flags for the make_autodoc function */
enum autodoc_t {
@ -115,7 +116,7 @@ public:
* ------------------------------------------------------------ */
int threads_enable(Node *n) const {
return threads && GetFlagAttr(n, "feature:threads");
return threads && !GetFlagAttr(n, "feature:nothread");
}
int initialize_threads(String *f_init) {
@ -124,7 +125,7 @@ public:
}
Printf(f_init,"\n");
Printf(f_init,"/* Initialize threading */\n");
Printf(f_init,"SWIG_PYTHON_INITIALIZE_THREADING;\n");
Printf(f_init,"SWIG_PYTHON_INITIALIZE_THREADS;\n");
return SWIG_OK;
}
@ -133,9 +134,9 @@ public:
if (!GetFlag(n, "feature:nothreadblock")) {
String *bb = Getattr(n,"feature:threadbeginblock");
if (bb) {
Wrapper_add_local(f,"python_thread_state", bb);
Append(f->code, bb);
} else {
Wrapper_add_local(f,"python_thread_state", "SWIG_PYTHON_THREAD_BEGIN_BLOCK");
Append(f->code,"SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n");
}
}
}
@ -237,20 +238,11 @@ public:
Preprocessor_define((DOH *) "SWIG_NORTTI", 0);
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-threads") == 0) {
Hash *features_hash = Swig_cparse_features();
String *name = NewString("");
String *fname = NewString("feature:threads");
String *fvalue = NewString("1");
Swig_feature_set(features_hash,name,0,fname,fvalue,0);
threads = 1;
Swig_mark_arg(i);
Delete(name);
Delete(fname);
Delete(fvalue);
} else if (strcmp(argv[i],"-nothreads") == 0) {
/* Turn off thread suppor mode */
threads = 0;
Preprocessor_define((DOH *) "SWIG_PYTHON_NO_THREADING", 0);
nothreads = 1;
Swig_mark_arg(i);
} else if (strcmp(argv[i],"-modern") == 0) {
apply = 0;
@ -375,8 +367,10 @@ public:
Printf(f_runtime,"#define SWIG_DIRECTORS\n");
}
if (threads) {
Printf(f_runtime,"#define SWIG_PYTHON_THREADING\n");
if (nothreads) {
Printf(f_runtime,"#define SWIG_PYTHON_NO_THREADS\n");
} else if (threads) {
Printf(f_runtime,"#define SWIG_PYTHON_THREADS\n");
}
/* Set module name */
@ -1550,18 +1544,17 @@ public:
Printf(f->code, " Swig::UnknownExceptionHandler dh;\n");
} else {
Printf(f->code, "{\n");
if (allow_thread) thread_begin_allow(n, f);
}
if (allow_thread) thread_begin_allow(n, f);
emit_action(n,f);
if (allow_thread) thread_end_allow(n, f);
if (director_method) {
Printf(f->code, "} catch (Swig::DirectorException&) {\n");
Printf(f->code, " SWIG_fail;\n");
Printf(f->code, "}\n");
} else {
if (allow_thread) thread_end_allow(n, f);
Printf(f->code, "}\n");
}
@ -3011,23 +3004,26 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
}
int allow_thread = threads_enable(n);
if (allow_thread) thread_begin_block(n, w);
/* direct call to superclass if _up is set */
Printf(w->code, "if (swig_get_up()) {\n");
if (allow_thread) thread_end_block(n, w);
if (pure_virtual) {
Printf(w->code,
"Swig::DirectorPureVirtualException::raise(\"%s.\");\n",Swig_method_call(super,l));
} else {
} else {
if (allow_thread) thread_begin_allow(n, w);
if (is_void) {
Printf(w->code, "%s;\n", Swig_method_call(super,l));
Printf(w->code, "return;\n");
} else {
Printf(w->code, "return %s;\n", Swig_method_call(super,l));
}
if (allow_thread) thread_end_allow(n, w);
}
Printf(w->code, "}\n");
Printf(w->code, "} else {\n");
if (allow_thread) thread_begin_block(n, w);
/* wrap complex arguments to PyObjects */
Printv(w->code, wrap_args, NIL);
@ -3040,13 +3036,11 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
Printf(w->code, "if (!swig_get_self()) {\n");
if (allow_thread) thread_end_block(n, w);
Printf(w->code, " Swig::DirectorException::raise(\"'self' unitialized, maybe you forgot to call %s.__init__.\");\n", classname);
Printf(w->code, "}\n");
Wrapper_add_local(w, "method", "PyObject* method = 0");
Printf(w->code, "method = swig_get_method(swig_method_index, swig_method_name);\n");
Printf(w->code, "if (method == NULL) {\n");
if (allow_thread) thread_end_block(n, w);
Printf(w->code, " Swig::DirectorMethodException::raise(\"Method '%s.%s' doesn't exist\");\n", classname, pyname);
Printf(w->code, "}\n");
@ -3072,18 +3066,15 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
Printf(w->code, "if (result == NULL) {\n");
Printf(w->code, " PyObject *error = PyErr_Occurred();\n");
if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) {
if (allow_thread) thread_end_block(n, w);
Replaceall(tm, "$error", "error");
Printv(w->code, Str(tm), "\n", NIL);
} else {
Printf(w->code, " if (error != NULL) {\n");
if (allow_thread) thread_end_block(n, w);
Printf(w->code, " Swig::DirectorMethodException::raise(\"Error detected when calling %s.%s\");\n",
classname, pyname);
Printf(w->code, " }\n");
}
Printf(w->code, "}\n");
if (allow_thread) thread_end_block(n, w);
Delete(tm);
/*
@ -3170,6 +3161,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
}
/* any existing helper functions to handle this? */
if (allow_thread) thread_end_block(n, w);
if (!is_void) {
String* rettype = SwigType_str(return_type, 0);
if (!SwigType_isreference(return_type)) {
@ -3180,6 +3172,7 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) {
Delete(rettype);
}
Printf(w->code, "}\n");
Printf(w->code, "}\n");
/* emit the director method */