2 #include <CoreFoundation/CFRunLoop.h>
4 /* These macros are defined in Python 2.3 but not 2.2 */
6 #define PyMODINIT_FUNC void
9 #define PyDoc_STRVAR(Var,Str) static char Var[] = Str
15 static PyObject
*AutoGILError
;
18 static void autoGILCallback(CFRunLoopObserverRef observer
,
19 CFRunLoopActivity activity
,
21 PyThreadState
**p_tstate
= (PyThreadState
**)info
;
24 case kCFRunLoopBeforeWaiting
:
25 /* going to sleep, release GIL */
27 fprintf(stderr
, "going to sleep, release GIL\n");
29 *p_tstate
= PyEval_SaveThread();
31 case kCFRunLoopAfterWaiting
:
32 /* waking up, acquire GIL */
34 fprintf(stderr
, "waking up, acquire GIL\n");
36 PyEval_RestoreThread(*p_tstate
);
44 static void infoRelease(const void *info
) {
45 /* XXX This should get called when the run loop is deallocated,
46 but this doesn't seem to happen. So for now: leak. */
47 PyMem_Free((void *)info
);
51 autoGIL_installAutoGIL(PyObject
*self
)
53 PyObject
*tstate_dict
= PyThreadState_GetDict();
56 PyThreadState
**p_tstate
; /* for use in the info field */
57 CFRunLoopObserverContext context
= {0, NULL
, NULL
, NULL
, NULL
};
58 CFRunLoopObserverRef observer
;
60 if (tstate_dict
== NULL
)
62 v
= PyDict_GetItemString(tstate_dict
, "autoGIL.InstalledAutoGIL");
64 /* we've already installed a callback for this thread */
69 rl
= CFRunLoopGetCurrent();
71 PyErr_SetString(AutoGILError
,
72 "can't get run loop for current thread");
76 p_tstate
= PyMem_Malloc(sizeof(PyThreadState
*));
77 if (p_tstate
== NULL
) {
78 PyErr_SetString(PyExc_MemoryError
,
79 "not enough memory to allocate "
84 context
.info
= (void *)p_tstate
;
85 context
.release
= infoRelease
;
87 observer
= CFRunLoopObserverCreate(
89 kCFRunLoopBeforeWaiting
| kCFRunLoopAfterWaiting
,
90 1, 0, autoGILCallback
, &context
);
91 if (observer
== NULL
) {
92 PyErr_SetString(AutoGILError
,
93 "can't create event loop observer");
96 CFRunLoopAddObserver(rl
, observer
, kCFRunLoopDefaultMode
);
97 /* XXX how to check for errors? */
99 /* register that we have installed a callback for this thread */
100 if (PyDict_SetItemString(tstate_dict
, "autoGIL.InstalledAutoGIL",
108 PyDoc_STRVAR(autoGIL_installAutoGIL_doc
,
109 "installAutoGIL() -> None\n\
110 Install an observer callback in the event loop (CFRunLoop) for the\n\
111 current thread, that will lock and unlock the Global Interpreter Lock\n\
112 (GIL) at appropriate times, allowing other Python threads to run while\n\
113 the event loop is idle."
116 static PyMethodDef autoGIL_methods
[] = {
119 (PyCFunction
)autoGIL_installAutoGIL
,
121 autoGIL_installAutoGIL_doc
123 { 0, 0, 0, 0 } /* sentinel */
126 PyDoc_STRVAR(autoGIL_docs
,
127 "The autoGIL module provides a function (installAutoGIL) that\n\
128 automatically locks and unlocks Python's Global Interpreter Lock\n\
129 when running an event loop."
137 if (PyErr_WarnPy3k("In 3.x, the autoGIL module is removed.", 1) < 0)
140 mod
= Py_InitModule4("autoGIL", autoGIL_methods
, autoGIL_docs
,
141 NULL
, PYTHON_API_VERSION
);
144 AutoGILError
= PyErr_NewException("autoGIL.AutoGILError",
145 PyExc_Exception
, NULL
);
146 if (AutoGILError
== NULL
)
148 Py_INCREF(AutoGILError
);
149 if (PyModule_AddObject(mod
, "AutoGILError",