diff options
author | Just van Rossum <just@letterror.com> | 2003-05-03 00:18:55 (GMT) |
---|---|---|
committer | Just van Rossum <just@letterror.com> | 2003-05-03 00:18:55 (GMT) |
commit | 6767eed22a8a3beecaf4a4e0d2bde109dc73d895 (patch) | |
tree | f4f00e3b6d457bd3c163c45179bc82486456183c /Mac/Modules/autoGIL.c | |
parent | d797e7b5070a96f27ef03d6cbef6103508552ea8 (diff) | |
download | cpython-6767eed22a8a3beecaf4a4e0d2bde109dc73d895.zip cpython-6767eed22a8a3beecaf4a4e0d2bde109dc73d895.tar.gz cpython-6767eed22a8a3beecaf4a4e0d2bde109dc73d895.tar.bz2 |
Short and sweet module doing something very useful: for event loop
based threads, release the GIL when the event loop goes to sleep,
and acquire it again when the event loop wakes up again. OSX-only.
Diffstat (limited to 'Mac/Modules/autoGIL.c')
-rw-r--r-- | Mac/Modules/autoGIL.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/Mac/Modules/autoGIL.c b/Mac/Modules/autoGIL.c new file mode 100644 index 0000000..4ee1e75 --- /dev/null +++ b/Mac/Modules/autoGIL.c @@ -0,0 +1,149 @@ +#include "Python.h" +#include <CoreFoundation/CFRunLoop.h> + +/* These macros are defined in Python 2.3 but not 2.2 */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC void +#endif +#ifndef PyDoc_STRVAR +#define PyDoc_STRVAR(Var,Str) static char Var[] = Str +#endif + + +#undef AUTOGIL_DEBUG + +static PyObject *AutoGILError; + + +static void autoGILCallback(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, + void *info) { + PyThreadState **p_tstate = (PyThreadState **)info; + + switch (activity) { + case kCFRunLoopBeforeWaiting: + /* going to sleep, release GIL */ +#ifdef AUTOGIL_DEBUG + fprintf(stderr, "going to sleep, release GIL\n"); +#endif + *p_tstate = PyEval_SaveThread(); + break; + case kCFRunLoopAfterWaiting: + /* waking up, acquire GIL */ +#ifdef AUTOGIL_DEBUG + fprintf(stderr, "waking up, acquire GIL\n"); +#endif + PyEval_RestoreThread(*p_tstate); + *p_tstate = NULL; + break; + default: + break; + } +} + +static void infoRelease(const void *info) { + /* XXX This should get called when the run loop is deallocated, + but this doesn't seem to happen. So for now: leak. */ + PyMem_Free((void *)info); +} + +static PyObject * +autoGIL_installAutoGIL(PyObject *self) +{ + PyObject *tstate_dict = PyThreadState_GetDict(); + PyObject *v; + CFRunLoopRef rl; + PyThreadState **p_tstate; /* for use in the info field */ + CFRunLoopObserverContext context = {0, NULL, NULL, NULL, NULL}; + CFRunLoopObserverRef observer; + + if (tstate_dict == NULL) + return NULL; + v = PyDict_GetItemString(tstate_dict, "autoGIL.InstalledAutoGIL"); + if (v != NULL) { + /* we've already installed a callback for this thread */ + Py_INCREF(Py_None); + return Py_None; + } + + rl = CFRunLoopGetCurrent(); + if (rl == NULL) { + PyErr_SetString(AutoGILError, + "can't get run loop for current thread"); + return NULL; + } + + p_tstate = PyMem_Malloc(sizeof(PyThreadState *)); + if (p_tstate == NULL) { + PyErr_SetString(PyExc_MemoryError, + "not enough memory to allocate " + "tstate pointer"); + return NULL; + } + *p_tstate = NULL; + context.info = (void *)p_tstate; + context.release = infoRelease; + + observer = CFRunLoopObserverCreate( + NULL, + kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting, + 1, 0, autoGILCallback, &context); + if (observer == NULL) { + PyErr_SetString(AutoGILError, + "can't create event loop observer"); + return NULL; + } + CFRunLoopAddObserver(rl, observer, kCFRunLoopDefaultMode); + /* XXX how to check for errors? */ + + /* register that we have installed a callback for this thread */ + if (PyDict_SetItemString(tstate_dict, "autoGIL.InstalledAutoGIL", + Py_None) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(autoGIL_installAutoGIL_doc, +"installAutoGIL() -> None\n\ +Install an observer callback in the event loop (CFRunLoop) for the\n\ +current thread that will lock and unlock the Global Interpreter Lock\n\ +(GIL) at appropriate times, allowing other Python threads to run while\n\ +the event loop is running." +); + +static PyMethodDef autoGIL_methods[] = { + { + "installAutoGIL", + (PyCFunction)autoGIL_installAutoGIL, + METH_NOARGS, + autoGIL_installAutoGIL_doc + }, + { 0, 0, 0, 0 } /* sentinel */ +}; + +PyDoc_STRVAR(autoGIL_docs, +"The autoGIL module provides a function (installAutoGIL) that\n\ +automatically locks and unlocks Python's Global Interpreter Lock\n\ +when running an event loop." +); + +PyMODINIT_FUNC +initautoGIL(void) +{ + PyObject *mod; + + mod = Py_InitModule4("autoGIL", autoGIL_methods, autoGIL_docs, + NULL, PYTHON_API_VERSION); + if (mod == NULL) + return; + AutoGILError = PyErr_NewException("autoGIL.AutoGILError", + PyExc_Exception, NULL); + if (AutoGILError == NULL) + return; + Py_INCREF(AutoGILError); + if (PyModule_AddObject(mod, "AutoGILError", + AutoGILError) < 0) + return; +} |