From 54db0825da704d121264647798fdd829a3ade6e2 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 24 Oct 2006 20:28:16 +0000 Subject: Make python bindings threaded, by dropping/acquiring Python GIL where needed --- generator.py | 6 ++++-- libvir.c | 25 ++++++++++++++++++++++++- libvirt_wrap.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/generator.py b/generator.py index 63f7635..e973db1 100755 --- a/generator.py +++ b/generator.py @@ -421,8 +421,10 @@ def print_function_wrapper(name, output, export, include): output.write(" return(NULL);\n") if c_convert != "": output.write(c_convert) - - output.write(c_call) + + output.write("LIBVIRT_BEGIN_ALLOW_THREADS;\n"); + output.write(c_call); + output.write("LIBVIRT_END_ALLOW_THREADS;\n"); output.write(ret_convert) output.write("}\n\n") if cond != None and cond != "": diff --git a/libvir.c b/libvir.c index 907383b..3d580e5 100644 --- a/libvir.c +++ b/libvir.c @@ -18,6 +18,8 @@ void initlibvirmod(void); PyObject *libvirt_virDomainGetUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args); + + /************************************************************************ * * * Global error handler at the Python level * @@ -40,6 +42,8 @@ libvirt_virErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, virErrorPtr err) if ((err == NULL) || (err->code == VIR_ERR_OK)) return; + LIBVIRT_ENSURE_THREAD_STATE; + if ((libvirt_virPythonErrorFuncHandler == NULL) || (libvirt_virPythonErrorFuncHandler == Py_None)) { virDefaultErrorFunc(err); @@ -63,6 +67,8 @@ libvirt_virErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, virErrorPtr err) Py_XDECREF(list); Py_XDECREF(result); } + + LIBVIRT_RELEASE_THREAD_STATE; } static PyObject * @@ -124,7 +130,9 @@ libvirt_virDomainFree(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { return(NULL); domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virDomainFree(domain); + LIBVIRT_END_ALLOW_THREADS; py_retval = libvirt_intWrap((int) c_retval); return(py_retval); } @@ -140,7 +148,9 @@ libvirt_virConnectClose(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { return(NULL); conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virConnectClose(conn); + LIBVIRT_END_ALLOW_THREADS; py_retval = libvirt_intWrap((int) c_retval); return(py_retval); } @@ -158,7 +168,9 @@ libvirt_virConnectListDomainsID(PyObject *self ATTRIBUTE_UNUSED, return(NULL); conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virConnectListDomains(conn, &ids[0], 500); + LIBVIRT_END_ALLOW_THREADS; if (c_retval < 0) { Py_INCREF(Py_None); return(Py_None); @@ -182,7 +194,9 @@ libvirt_virDomainGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { return(NULL); domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virDomainGetInfo(domain, &info); + LIBVIRT_END_ALLOW_THREADS; if (c_retval < 0) { Py_INCREF(Py_None); return(Py_None); @@ -209,7 +223,9 @@ libvirt_virNodeGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { return(NULL); conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virNodeGetInfo(conn, &info); + LIBVIRT_END_ALLOW_THREADS; if (c_retval < 0) { Py_INCREF(Py_None); return(Py_None); @@ -232,6 +248,7 @@ libvirt_virDomainGetUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { unsigned char uuid[16]; virDomainPtr domain; PyObject *pyobj_domain; + int c_retval; if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetUUID", &pyobj_domain)) return(NULL); @@ -241,7 +258,11 @@ libvirt_virDomainGetUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { Py_INCREF(Py_None); return(Py_None); } - if (virDomainGetUUID(domain, &uuid[0]) < 0) { + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetUUID(domain, &uuid[0]); + LIBVIRT_END_ALLOW_THREADS; + + if (c_retval < 0) { Py_INCREF(Py_None); return(Py_None); } @@ -268,7 +289,9 @@ libvirt_virDomainLookupByUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { return(Py_None); } + LIBVIRT_BEGIN_ALLOW_THREADS; c_retval = virDomainLookupByUUID(conn, uuid); + LIBVIRT_END_ALLOW_THREADS; py_retval = libvirt_virDomainPtrWrap((virDomainPtr) c_retval); return(py_retval); } diff --git a/libvirt_wrap.h b/libvirt_wrap.h index e745215..906245a 100644 --- a/libvirt_wrap.h +++ b/libvirt_wrap.h @@ -48,3 +48,53 @@ PyObject * libvirt_charPtrConstWrap(const char *str); PyObject * libvirt_virConnectPtrWrap(virConnectPtr node); PyObject * libvirt_virDomainPtrWrap(virDomainPtr node); + +/* Provide simple macro statement wrappers (adapted from GLib, in turn from Perl): + * LIBVIRT_STMT_START { statements; } LIBVIRT_STMT_END; + * can be used as a single statement, as in + * if (x) LIBVIRT_STMT_START { ... } LIBVIRT_STMT_END; else ... + * + * When GCC is compiling C code in non-ANSI mode, it will use the + * compiler __extension__ to wrap the statements wihin `({' and '})' braces. + * When compiling on platforms where configure has defined + * HAVE_DOWHILE_MACROS, statements will be wrapped with `do' and `while (0)'. + * For any other platforms (SunOS4 is known to have this issue), wrap the + * statements with `if (1)' and `else (void) 0'. + */ +#if !(defined (LIBVIRT_STMT_START) && defined (LIBVIRT_STMT_END)) +# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) +# define LIBVIRT_STMT_START (void) __extension__ ( +# define LIBVIRT_STMT_END ) +# else /* !(__GNUC__ && !__STRICT_ANSI__ && !__cplusplus) */ +# if defined (HAVE_DOWHILE_MACROS) +# define LIBVIRT_STMT_START do +# define LIBVIRT_STMT_END while (0) +# else /* !HAVE_DOWHILE_MACROS */ +# define LIBVIRT_STMT_START if (1) +# define LIBVIRT_STMT_END else (void) 0 +# endif /* !HAVE_DOWHILE_MACROS */ +# endif /* !(__GNUC__ && !__STRICT_ANSI__ && !__cplusplus) */ +#endif + +#define LIBVIRT_BEGIN_ALLOW_THREADS \ + LIBVIRT_STMT_START { \ + PyThreadState *_save = NULL; \ + if (PyEval_ThreadsInitialized()) \ + _save = PyEval_SaveThread(); + +#define LIBVIRT_END_ALLOW_THREADS \ + if (PyEval_ThreadsInitialized()) \ + PyEval_RestoreThread(_save); \ + } LIBVIRT_STMT_END + +#define LIBVIRT_ENSURE_THREAD_STATE \ + LIBVIRT_STMT_START { \ + PyGILState_STATE _save; \ + if (PyEval_ThreadsInitialized()) \ + _save = PyGILState_Ensure(); + +#define LIBVIRT_RELEASE_THREAD_STATE \ + if (PyEval_ThreadsInitialized()) \ + PyGILState_Release(_save); \ + } LIBVIRT_STMT_END + -- cgit