From 2eeef5275d441260d82256a6b4e2bbc5057fe316 Mon Sep 17 00:00:00 2001 From: Marcelo Matus Date: Tue, 6 Dec 2005 19:35:03 +0000 Subject: [PATCH] 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 --- CHANGES.current | 37 ++++---------- Examples/test-suite/python/director_thread.i | 1 - Lib/python/pyrun.swg | 13 ----- Lib/python/pythreads.swg | 34 ++++++------- Lib/python/pyuserdir.swg | 27 ++++++----- Source/Modules/python.cxx | 51 +++++++++----------- 6 files changed, 62 insertions(+), 101 deletions(-) diff --git a/CHANGES.current b/CHANGES.current index 5151594fd..d511498b6 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -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. diff --git a/Examples/test-suite/python/director_thread.i b/Examples/test-suite/python/director_thread.i index 3f09db4eb..dd0aa3d3e 100644 --- a/Examples/test-suite/python/director_thread.i +++ b/Examples/test-suite/python/director_thread.i @@ -8,7 +8,6 @@ class Foo; extern "C" void* working(void* t); %} -%threads; %director Foo; %inline { diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index 3d99caa40..44c54a2d4 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -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)) diff --git a/Lib/python/pythreads.swg b/Lib/python/pythreads.swg index 6ee6dad84..f1dba7946 100644 --- a/Lib/python/pythreads.swg +++ b/Lib/python/pythreads.swg @@ -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 diff --git a/Lib/python/pyuserdir.swg b/Lib/python/pyuserdir.swg index 1b8207780..6482826bb 100644 --- a/Lib/python/pyuserdir.swg +++ b/Lib/python/pyuserdir.swg @@ -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 */ diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index 944c4f3d2..cc0cb5971 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -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 */