diff --git a/Examples/test-suite/python/director_thread.i b/Examples/test-suite/python/director_thread.i index 306176271..3f09db4eb 100644 --- a/Examples/test-suite/python/director_thread.i +++ b/Examples/test-suite/python/director_thread.i @@ -1,4 +1,4 @@ -%module(directors="1") director_thread +%module(directors="1",threads="1") director_thread %{ #include @@ -8,8 +8,8 @@ class Foo; extern "C" void* working(void* t); %} - -%feature("director") Foo; +%threads; +%director Foo; %inline { class Foo { @@ -38,7 +38,7 @@ extern "C" void* working(void* t); %inline { extern "C" void* working(void* t) { - Foo* f = static_cast(t); + Foo* f = static_cast(t); while (1) { sleep(1); f->do_foo(); diff --git a/Examples/test-suite/python/director_thread_runme.py b/Examples/test-suite/python/director_thread_runme.py index 93882976c..d3427dff0 100644 --- a/Examples/test-suite/python/director_thread_runme.py +++ b/Examples/test-suite/python/director_thread_runme.py @@ -12,4 +12,5 @@ d = Derived() d.run() if d.val >= 0: + print d.val raise RuntimeError diff --git a/Lib/python/argcargv.i b/Lib/python/argcargv.i index 1795f342c..8629ce95b 100644 --- a/Lib/python/argcargv.i +++ b/Lib/python/argcargv.i @@ -28,15 +28,19 @@ SWIG_AsArgcArgv(PyObject* input, argv[i] = 0; } } else { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_Clear(); PyErr_SetString(PyExc_TypeError,"list or tuple must contain strings only"); + SWIG_PYTHON_THREAD_END_BLOCK; } } argv[i] = 0; return argv; } else { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; *argc = 0; PyErr_SetString(PyExc_TypeError,"a list or tuple is expected"); + SWIG_PYTHON_THREAD_END_BLOCK; return 0; } } else { diff --git a/Lib/python/defarg.swg b/Lib/python/defarg.swg index 8d10aec69..2e0a623de 100644 --- a/Lib/python/defarg.swg +++ b/Lib/python/defarg.swg @@ -21,16 +21,17 @@ */ SWIGINTERN PyObject *swig_call_defargs(PyObject *self, PyObject *args) { - PyObject *func; - PyObject *parms; - - if (!PyArg_ParseTuple(args,"OO",&func,&parms)) - return NULL; - - if (!PyCallable_Check(func)) { - PyErr_SetString(PyExc_TypeError, "__call_defarg : Need a callable object!"); - return NULL; - } - return PyEval_CallObject(func,parms); - + PyObject *func; + PyObject *parms; + + if (!PyArg_ParseTuple(args,"OO",&func,&parms)) + return NULL; + + if (!PyCallable_Check(func)) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyErr_SetString(PyExc_TypeError, "__call_defarg : Need a callable object!"); + SWIG_PYTHON_THREAD_END_BLOCK; + return NULL; + } + return PyEval_CallObject(func,parms); } diff --git a/Lib/python/director_h.swg b/Lib/python/director_h.swg index 9aa18541c..abcc6c9be 100644 --- a/Lib/python/director_h.swg +++ b/Lib/python/director_h.swg @@ -221,6 +221,7 @@ namespace Swig { DirectorException(PyObject *error, const char* hdr ="", const char* msg ="") : swig_msg(hdr) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; if (strlen(msg)) { swig_msg += " "; swig_msg += msg; @@ -230,6 +231,7 @@ namespace Swig { } else { SWIG_Python_AddErrorMsg(getMessage()); } + SWIG_PYTHON_THREAD_END_BLOCK; } const char *getMessage() const @@ -359,7 +361,9 @@ namespace Swig { /* decrement the reference count of the wrapped python object */ void swig_decref() const { if (swig_disown_flag) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; Py_DECREF(swig_self); + SWIG_PYTHON_THREAD_END_BLOCK; } } diff --git a/Lib/python/pycontainer.swg b/Lib/python/pycontainer.swg index 09daa27e5..0a717d1b3 100644 --- a/Lib/python/pycontainer.swg +++ b/Lib/python/pycontainer.swg @@ -13,6 +13,7 @@ #include %} + /**** The PySequence C++ Wrap ***/ %insert(header) %{ @@ -104,7 +105,13 @@ namespace std { { bool operator()(PyObject * v, PyObject *w) const - { return PyObject_Compare(v, w) < 0; } + { + bool res; + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + res = PyObject_Compare(v, w) < 0; + SWIG_PYTHON_THREAD_END_BLOCK; + return res; + } }; template <> @@ -112,7 +119,9 @@ namespace std { { bool operator()(const swig::PyObject_ptr& v, const swig::PyObject_ptr& w) const - { return PyObject_Compare(v, w) < 0; } + { + return std::less()(v, w); + } }; template <> @@ -120,7 +129,9 @@ namespace std { { bool operator()(const swig::PyObject_var& v, const swig::PyObject_var& w) const - { return PyObject_Compare(v, w) < 0; } + { + return std::less()(v, w); + } }; } @@ -262,10 +273,15 @@ namespace swig { %ignore stop_iteration; %typemap(throws) stop_iteration { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetObject(PyExc_StopIteration, SWIG_Py_Void()); + SWIG_PYTHON_THREAD_END_BLOCK; + SWIG_fail; } } + + namespace swig { %newobject PySequence_OutputIterator::operator +; %newobject PySequence_OutputIterator::operator - (ptrdiff_t n) const; @@ -478,6 +494,7 @@ namespace swig try { return swig::as(item, true); } catch (std::exception& e) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; char msg[1024]; snprintf(msg, sizeof(msg), "in sequence element %d ", _index); if (!PyErr_Occurred()) { @@ -485,6 +502,7 @@ namespace swig } SWIG_Python_AddErrorMsg(msg); SWIG_Python_AddErrorMsg(e.what()); + SWIG_PYTHON_THREAD_END_BLOCK; throw; } } @@ -895,8 +913,11 @@ namespace swig } } catch (std::exception& e) { if (seq) { - if (!PyErr_Occurred()) + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, e.what()); + } + SWIG_PYTHON_THREAD_END_BLOCK; } return 0; } @@ -934,8 +955,10 @@ namespace swig } return obj; } else { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "sequence size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } } diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg index 5d9b641db..09892dc3b 100644 --- a/Lib/python/pyinit.swg +++ b/Lib/python/pyinit.swg @@ -61,27 +61,35 @@ swig_varlink_dealloc(swig_varlinkobject *v) { SWIGINTERN PyObject * swig_varlink_getattr(swig_varlinkobject *v, char *n) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; swig_globalvar *var = v->vars; while (var) { if (strcmp(var->name,n) == 0) { - return (*var->get_attr)(); + PyObject *obj = (*var->get_attr)(); + SWIG_PYTHON_THREAD_END_BLOCK; + return obj; } var = var->next; } PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } SWIGINTERN int swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; swig_globalvar *var = v->vars; while (var) { if (strcmp(var->name,n) == 0) { - return (*var->set_attr)(p); + int res = (*var->set_attr)(p); + SWIG_PYTHON_THREAD_END_BLOCK; + return res; } var = var->next; } PyErr_SetString(PyExc_NameError,"Unknown C global variable"); + SWIG_PYTHON_THREAD_END_BLOCK; return 1; } diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg index e2a66c20d..882f26783 100644 --- a/Lib/python/pyrun.swg +++ b/Lib/python/pyrun.swg @@ -43,7 +43,7 @@ /* Error manipulation */ #define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) -#define SWIG_Error(code, msg) PyErr_SetString(SWIG_Python_ErrorType(code), msg) +#define SWIG_Error(code, msg) {SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(SWIG_Python_ErrorType(code), msg); SWIG_PYTHON_THREAD_END_BLOCK; } #define SWIG_fail goto fail /* @@ -652,6 +652,7 @@ 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)) { @@ -669,16 +670,17 @@ SWIG_Python_GetSwigThis(PyObject *pyobj) #else obj = PyObject_GetAttr(pyobj,SWIG_This()); Py_XDECREF(obj); -#endif +#endif if (!obj || PyErr_Occurred()) { PyErr_Clear(); + SWIG_PYTHON_THREAD_END_BLOCK; return 0; } - if (PySwigObject_Check(obj)) { - return (PySwigObject *)obj; - } else { - return 0; - } + if (!PySwigObject_Check(obj)) { + obj = 0; + } + SWIG_PYTHON_THREAD_END_BLOCK; + return (PySwigObject *)obj; } } @@ -836,7 +838,9 @@ SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int flags) { return SWIG_Py_Void(); } else if (!type) { if (!PyErr_Occurred()) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_TypeError, "Swig: null type passed to NewPointerObj"); + SWIG_PYTHON_THREAD_END_BLOCK; } return NULL; } else { @@ -901,21 +905,27 @@ 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/pyruntime.swg b/Lib/python/pyruntime.swg index 021579eb5..8a42565ec 100644 --- a/Lib/python/pyruntime.swg +++ b/Lib/python/pyruntime.swg @@ -34,6 +34,7 @@ PyString_FromFormat(const char *fmt, ...) { %} %insert(runtime) "swigrun.swg"; /* SWIG API */ %insert(runtime) "swigerrors.swg" /* SWIG errors */ +%insert(runtime) "pythreads.swg"; /* Python thread code */ %insert(runtime) "pyapi.swg"; /* Pyton API */ %insert(runtime) "pyrun.swg"; /* Python run-time code */ diff --git a/Lib/python/pythreads.swg b/Lib/python/pythreads.swg new file mode 100644 index 000000000..69e86fd43 --- /dev/null +++ b/Lib/python/pythreads.swg @@ -0,0 +1,72 @@ +#if !defined(SWIG_PYTHON_NO_THREADING) +# if !defined(SWIG_PYTHON_THREADING) +# define SWIG_PYTHON_THREADING +# endif +#else +# if defined(SWIG_PYTHON_THREADING) +# undef SWIG_PYTHON_THREADING +# endif +#endif +#if defined(SWIG_PYTHON_THREADING) /* 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 + class SWIG_Python_Thread_Block { + bool status; + PyGILState_STATE state; + public: + void begin() { if (!status) { state = PyGILState_Ensure(); status = true;} } + void end() { if (status) { PyGILState_Release(state); status = false;} } + SWIG_Python_Thread_Block() : status(false) { begin(); } + ~SWIG_Python_Thread_Block() { end(); } + }; + class SWIG_Python_Thread_Allow { + bool status; + PyThreadState *save; + 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(); } + }; +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK SWIG_Python_Thread_Block _swig_thread_block +# 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 +# endif +# else /* Old thread way, not implemented, user must provide it */ +# if !defined(SWIG_PYTHON_INITIALIZE_THREADING) +# define SWIG_PYTHON_INITIALIZE_THREADING +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_BLOCK) +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_END_BLOCK) +# define SWIG_PYTHON_THREAD_END_BLOCK +# endif +# if !defined(SWIG_PYTHON_THREAD_BEGIN_ALLOW) +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# endif +# if !defined(SWIG_PYTHON_THREAD_END_ALLOW) +# define SWIG_PYTHON_THREAD_END_ALLOW +# endif +# endif +#else /* No thread support */ +# define SWIG_PYTHON_INITIALIZE_THREADING +# define SWIG_PYTHON_THREAD_BEGIN_BLOCK +# define SWIG_PYTHON_THREAD_END_BLOCK +# define SWIG_PYTHON_THREAD_BEGIN_ALLOW +# define SWIG_PYTHON_THREAD_END_ALLOW +#endif diff --git a/Lib/python/pytypemaps.swg b/Lib/python/pytypemaps.swg index e58447a04..4a7c720b6 100644 --- a/Lib/python/pytypemaps.swg +++ b/Lib/python/pytypemaps.swg @@ -56,7 +56,9 @@ /* raise */ %define %raise(obj, type, desc) PyObject *_obj = obj; + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetObject(SWIG_Python_ExceptionType(desc), _obj); + SWIG_PYTHON_THREAD_END_BLOCK; Py_DECREF(_obj); SWIG_fail %enddef diff --git a/Lib/python/pyuserdir.swg b/Lib/python/pyuserdir.swg index 849d6dbd1..1b8207780 100644 --- a/Lib/python/pyuserdir.swg +++ b/Lib/python/pyuserdir.swg @@ -2,11 +2,14 @@ * 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. @@ -47,6 +50,8 @@ so, it works with old python versions. #define %clearpythonnondynamic %feature("python:nondynamic", "") #define %pythondynamic %nopythonnondynamic + +/* ----------------------------------------------------------------------------- */ /* Use %pythonmaybecall to flag a method like __add__ or __radd__, which @@ -60,6 +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 @@ -105,6 +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 */ @@ -124,3 +131,31 @@ These methods "may be called" if needed. #define %nocallback %nopythoncallback #define %clearcallback %clearpythoncallback +/* ----------------------------------------------------------------------------- */ +/* + Thread support +*/ + +#define %threads %feature("threads") +#define %nothreads %feature("threads","0") +#define %clearthreads %feature("threads","") + +#define %nothreadblock %feature("nothreadblock") +#define %threadblock %feature("nothreadblock","0") +#define %clearnothreadblock %feature("nothreadblock","") + +#define %nothreadallow %feature("nothreadallow") +#define %threadallow %feature("nothreadallow","0") +#define %clearnothreadallow %feature("nothreadallow","") + + +/* ----------------------------------------------------------------------------- */ +/* + Directors +*/ + +#define %director %feature("director") +#define %nodirector %feature("director","0") +#define %cleardirector %feature("director","") + + diff --git a/Lib/python/std_basic_string.i b/Lib/python/std_basic_string.i index cb372d2ef..7d3366db5 100644 --- a/Lib/python/std_basic_string.i +++ b/Lib/python/std_basic_string.i @@ -30,7 +30,9 @@ SWIG_AsPtr(std::basic_string)(PyObject* obj, std::string **val) PyErr_Clear(); } if (val) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_TypeError,"a string is expected"); + SWIG_PYTHON_THREAD_END_BLOCK; } return 0; } @@ -78,7 +80,9 @@ SWIGINTERN int PyErr_Clear(); } if (val) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_TypeError,"a wstring is expected"); + SWIG_PYTHON_THREAD_END_BLOCK; } return 0; } diff --git a/Lib/python/std_map.i b/Lib/python/std_map.i index 7baea64b0..1098eca15 100644 --- a/Lib/python/std_map.i +++ b/Lib/python/std_map.i @@ -25,7 +25,9 @@ ::asptr(items, val); } if (val) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_TypeError, "a dictionary is expected"); + SWIG_PYTHON_THREAD_END_BLOCK; } return 0; } @@ -41,8 +43,10 @@ size_type size = map.size(); int pysize = (size <= (size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "map size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject *obj = PyDict_New(); @@ -91,8 +95,10 @@ Map::size_type size = self->size(); int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "map size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject* keyList = PyList_New(pysize); @@ -107,8 +113,10 @@ Map::size_type size = self->size(); int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "map size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject* valList = PyTuple_New(pysize); @@ -123,8 +131,10 @@ Map::size_type size = self->size(); int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "map size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject* itemList = PyTuple_New(pysize); @@ -144,8 +154,10 @@ Map::size_type size = self->size(); int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "map size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject* keyTuple = PyTuple_New(pysize); diff --git a/Lib/python/std_multimap.i b/Lib/python/std_multimap.i index ef2b584dc..bd621dd9e 100644 --- a/Lib/python/std_multimap.i +++ b/Lib/python/std_multimap.i @@ -25,7 +25,9 @@ ::asptr(items, val); } if (val) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_TypeError, "a dictionary is expected"); + SWIG_PYTHON_THREAD_END_BLOCK; } return 0; } @@ -41,8 +43,10 @@ size_type size = multimap.size(); int pysize = (size <= (size_type) INT_MAX) ? (int) size : -1; if (pysize < 0) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; PyErr_SetString(PyExc_OverflowError, "multimap size not valid in python"); + SWIG_PYTHON_THREAD_END_BLOCK; return NULL; } PyObject *obj = PyDict_New(); diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index b2694608c..cb73437fd 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -48,7 +48,7 @@ static int classic = 0; static int modern = 1; static int apply = 0; static int new_repr = 1; -static int no_header_file = 0; +static int no_header_file = 0; /* C++ Support + Shadow Classes */ @@ -56,6 +56,9 @@ static int have_constructor; static int have_repr; static String *real_classname; +/* Thread Support */ +static int threads = 0; + /* flags for the make_autodoc function */ enum autodoc_t { AUTODOC_CLASS, @@ -72,15 +75,17 @@ Python Options (available with -python)\n\ -interface - Set the lib name to \n\ -keyword - Use keyword arguments\n\ -classic - Use classic classes only\n\ + -cppcast - Enable C++ casting operators (default) \n\ -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ - -cppcast - Enable C++ casting operators\n\ -nortti - Disable the use of the native C++ RTTI with directors\n\ - -modern - Use modern python features only, without compatibility code\n\ + -modern - Use modern python features only, without compatibility code (default)\n\ -nomodern - Don't use modern python features which are not back compatible \n\ -apply - Use apply() in proxy classes\n\ -new_vwm - New value wrapper mode, use only when everything else fails \n\ - -new_repr - Use more informative version of __repr__ in proxy classes\n\ + -new_repr - Use more informative version of __repr__ in proxy classes (default) \n\ -old_repr - Use shorter and old version of __repr__ in proxy classes\n\ + -threads - Add thread support for all the interface\n\ + -nothreads - Disable thread support for all the interface\n\ -noexcept - No automatic exception handling\n\ -noh - Don't generate the output header file\n\ -noproxy - Don't generate proxy classes \n\n"; @@ -95,13 +100,79 @@ public: "if ( $comparison ) { /* subclassed */\n", " $director_new \n", "} else {\n", + " SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n", " PyErr_SetString(PyExc_RuntimeError,", " \"accessing abstract class or protected constructor\"); \n", + " SWIG_PYTHON_THREAD_END_BLOCK;\n", " SWIG_fail;\n", "}\n", NIL); director_multiple_inheritance = 1; director_language = 1; } + + /* ------------------------------------------------------------ + * Thread Implementation + * ------------------------------------------------------------ */ + + int threads_enable(Node *n) const { + return threads && GetFlagAttr(n, "feature:threads"); + } + + int initialize_threads(String *f_init) { + if (!threads) { + return SWIG_OK; + } + + Printf(f_init,"\n"); + Printf(f_init,"/* Initialize threading */\n"); + Printf(f_init,"SWIG_PYTHON_INITIALIZE_THREADING;\n"); + + return SWIG_OK; + } + + virtual void thread_begin_block(Node *n, Wrapper *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *bb = Getattr(n,"feature:threadbeginblock"); + if (bb) { + Wrapper_add_local(f,"python_thread_state", bb); + } else { + Wrapper_add_local(f,"python_thread_state", "SWIG_PYTHON_THREAD_BEGIN_BLOCK"); + } + } + } + + virtual void thread_end_block(Node *n, Wrapper *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *eb = Getattr(n, "feature:threadendblock"); + if (eb) { + Append(f->code,eb); + } else { + Append(f->code, "SWIG_PYTHON_THREAD_END_BLOCK;\n"); + } + } + } + + virtual void thread_begin_allow(Node *n, Wrapper *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *bb = Getattr(n, "feature:threadbeginallow"); + if (bb) { + Append(f->code,bb); + } else { + Append(f->code, "SWIG_PYTHON_THREAD_BEGIN_ALLOW;\n"); + } + } + } + + virtual void thread_end_allow(Node *n, Wrapper *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *eb = Getattr(n, "feature:threadendallow"); + if (eb) { + Append(f->code, eb); + } else { + Append(f->code, "SWIG_PYTHON_THREAD_END_ALLOW;\n"); + } + } + } /* ------------------------------------------------------------ * main() @@ -163,9 +234,25 @@ public: cppcast = 0; Swig_mark_arg(i); } else if (strcmp(argv[i],"-nortti") == 0) { - /* Turn on no RTTI mode */ + /* Turn on no-RTTI mode */ 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); + Swig_mark_arg(i); } else if (strcmp(argv[i],"-modern") == 0) { apply = 0; classic = 0; @@ -230,6 +317,9 @@ public: allow_directors(); if (dirprot) allow_dirprot(); } + if (Getattr(options, "threads")) { + threads = 1; + } mod_docstring = Getattr(options, "docstring"); package = Getattr(options, "package"); } @@ -452,6 +542,7 @@ public: Printf(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); Printf(f_wrappers,"%s\n",const_code); + initialize_threads(f_init); Printf(f_init,"}\n"); Printf(f_wrappers,"#ifdef __cplusplus\n"); @@ -1125,7 +1216,9 @@ public: Printf(f->code,"Py_INCREF(Py_NotImplemented);\n"); Printf(f->code,"return Py_NotImplemented;\n"); } else { + Printf(f->code,"SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n"); Printf(f->code,"PyErr_SetString(PyExc_NotImplementedError,\"No matching function for overloaded '%s'\");\n", symname); + Printf(f->code,"SWIG_PYTHON_THREAD_END_BLOCK;\n"); Printf(f->code,"return NULL;\n"); } Printv(f->code,"}\n",NIL); @@ -1197,7 +1290,12 @@ public: cleanup = NewString(""); outarg = NewString(""); kwargs = NewString(""); + + int allow_thread = threads_enable(n); + if (allow_thread) thread_begin_block(n, f); + Wrapper_add_local(f,"errormsg", "const char *errmsg = 0"); + Wrapper_add_local(f,"errorobj", "PyObject *errorobj = 0"); Wrapper_add_local(f,"resultobj", "PyObject *resultobj = 0"); /* Write code to extract function parameters. */ @@ -1422,7 +1520,9 @@ public: Printf(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); if (dirprot_mode() && !is_public(n)) { Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); + Printf(f->code,"SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n"); Printf(f->code, "PyErr_SetString(PyExc_RuntimeError,\"accessing protected member %s\");\n", name); + Printf(f->code,"SWIG_PYTHON_THREAD_END_BLOCK;\n"); Printf(f->code, "SWIG_fail;\n"); Printf(f->code, "}\n"); } @@ -1444,18 +1544,27 @@ public: /* Emit the function call */ if (director_method) { + if (allow_thread) thread_end_block(n, f); Printf(f->code, "try {\n"); Printf(f->code, " Swig::UnknownExceptionHandler dh;\n"); + } else { + Printf(f->code, "{\n"); } + + 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 { + Printf(f->code, "}\n"); } + /* This part below still needs cleanup */ @@ -1548,7 +1657,7 @@ public: } } - + if (allow_thread) thread_end_block(n, f); Printf(f->code," return resultobj;\n"); /* Error handling code */ @@ -1557,6 +1666,7 @@ public: if (need_cleanup) { Printv(f->code,cleanup,NIL); } + if (allow_thread) thread_end_block(n, f); Printv(f->code,tab4,"return NULL;\n",NIL); @@ -2885,7 +2995,8 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { p = nextSibling(p); } - /* add the method name as a PyString */ + +/* add the method name as a PyString */ String *pyname = Getattr(n,"sym:name"); Wrapper_add_localv(w, "swig_method_index", "const size_t swig_method_index =", NewStringf("%d", director_method_index++), NIL); Wrapper_add_localv(w, "swig_method_name", "const char * const swig_method_name =", NewStringf("\"%s\"",pyname), NIL); @@ -2897,10 +3008,13 @@ int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { if (!is_void) { Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL); } - + + 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)); @@ -2925,11 +3039,13 @@ 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"); @@ -2955,15 +3071,18 @@ 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); /*