add thread support based in proposal #398495 by Joseph Winston

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@7929 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Marcelo Matus 2005-12-06 06:39:24 +00:00
commit 0fd2fe23cf
16 changed files with 337 additions and 37 deletions

View file

@ -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 <lib>- Set the lib name to <lib>\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);
/*