Make python bindings threaded, by dropping/acquiring Python GIL where needed

This commit is contained in:
Daniel P. Berrange 2006-10-24 20:28:16 +00:00
parent 297a77f6da
commit 9e5645393e
4 changed files with 87 additions and 3 deletions

View File

@ -1,3 +1,12 @@
Tue Oct 24 15:31:23 EDT 2006 Daniel P.Berrange <berrange@redhat.com>
* python/generator.py, python/libvir.c: Drop python interpreter
lock when calling into C functions, and re-grab when invoking
error callback.
* python/libvirt_wrap.h: Convenience macros for grabbing / dropping
the python interpreter lock in threaded environment.
Mon Oct 16 17:10:15 CEST 2006 Daniel Veillard <veillard@redhat.com>
* config.h.in configure.in libvirt.spec.in docs/libvir.html

View File

@ -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 != "":

View File

@ -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);
}

View File

@ -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