diff -r 89521ac669f0 Include/ceval.h --- a/Include/ceval.h Sun May 31 21:44:15 2015 -0400 +++ b/Include/ceval.h Sun May 31 22:03:14 2015 -0400 @@ -23,8 +23,9 @@ #ifndef Py_LIMITED_API PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); -PyAPI_FUNC(void) PyEval_SetCoroutineWrapper(PyObject *wrapper); -PyAPI_FUNC(PyObject *) PyEval_GetCoroutineWrapper(void); +PyAPI_FUNC(void) _PyEval_SetCoroutineWrapper(PyObject *wrapper); +PyAPI_FUNC(PyObject *) _PyEval_GetCoroutineWrapper(void); +PyAPI_FUNC(PyObject *) _PyEval_ApplyCoroutineWrapper(PyObject *gen); #endif struct _frame; /* Avoid including frameobject.h */ diff -r 89521ac669f0 Include/pystate.h --- a/Include/pystate.h Sun May 31 21:44:15 2015 -0400 +++ b/Include/pystate.h Sun May 31 22:03:14 2015 -0400 @@ -135,6 +135,7 @@ void *on_delete_data; PyObject *coroutine_wrapper; + int in_coroutine_wrapper; /* XXX signal handlers should also be here */ diff -r 89521ac669f0 Python/ceval.c --- a/Python/ceval.c Sun May 31 21:44:15 2015 -0400 +++ b/Python/ceval.c Sun May 31 22:03:14 2015 -0400 @@ -3921,7 +3921,6 @@ if (co->co_flags & CO_GENERATOR) { PyObject *gen; - PyObject *coroutine_wrapper; /* Don't need to keep the reference to f_back, it will be set * when the generator is resumed. */ @@ -3935,14 +3934,9 @@ if (gen == NULL) return NULL; - if (co->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE)) { - coroutine_wrapper = PyEval_GetCoroutineWrapper(); - if (coroutine_wrapper != NULL) { - PyObject *wrapped = - PyObject_CallFunction(coroutine_wrapper, "N", gen); - gen = wrapped; - } - } + if (co->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE)) + return _PyEval_ApplyCoroutineWrapper(gen); + return gen; } @@ -4390,7 +4384,7 @@ } void -PyEval_SetCoroutineWrapper(PyObject *wrapper) +_PyEval_SetCoroutineWrapper(PyObject *wrapper) { PyThreadState *tstate = PyThreadState_GET(); @@ -4401,13 +4395,36 @@ } PyObject * -PyEval_GetCoroutineWrapper(void) +_PyEval_GetCoroutineWrapper(void) { PyThreadState *tstate = PyThreadState_GET(); return tstate->coroutine_wrapper; } PyObject * +_PyEval_ApplyCoroutineWrapper(PyObject *gen) +{ + PyObject *wrapped; + PyThreadState *tstate = PyThreadState_GET(); + PyObject *wrapper = tstate->coroutine_wrapper; + + if (tstate->in_coroutine_wrapper) { + PyErr_SetString(PyExc_RuntimeError, + "Cannot call coroutine wrapper recursively"); + return NULL; + } + + if (wrapper == NULL) { + return gen; + } + + tstate->in_coroutine_wrapper = 1; + wrapped = PyObject_CallFunction(wrapper, "N", gen); + tstate->in_coroutine_wrapper = 0; + return wrapped; +} + +PyObject * PyEval_GetBuiltins(void) { PyFrameObject *current_frame = PyEval_GetFrame(); diff -r 89521ac669f0 Python/pystate.c --- a/Python/pystate.c Sun May 31 21:44:15 2015 -0400 +++ b/Python/pystate.c Sun May 31 22:03:14 2015 -0400 @@ -213,6 +213,7 @@ tstate->on_delete_data = NULL; tstate->coroutine_wrapper = NULL; + tstate->in_coroutine_wrapper = 0; if (init) _PyThreadState_Init(tstate); diff -r 89521ac669f0 Python/sysmodule.c --- a/Python/sysmodule.c Sun May 31 21:44:15 2015 -0400 +++ b/Python/sysmodule.c Sun May 31 22:03:14 2015 -0400 @@ -655,10 +655,10 @@ Py_TYPE(wrapper)->tp_name); return NULL; } - PyEval_SetCoroutineWrapper(wrapper); + _PyEval_SetCoroutineWrapper(wrapper); } else { - PyEval_SetCoroutineWrapper(NULL); + _PyEval_SetCoroutineWrapper(NULL); } Py_RETURN_NONE; } @@ -672,7 +672,7 @@ static PyObject * sys_get_coroutine_wrapper(PyObject *self, PyObject *args) { - PyObject *wrapper = PyEval_GetCoroutineWrapper(); + PyObject *wrapper = _PyEval_GetCoroutineWrapper(); if (wrapper == NULL) { wrapper = Py_None; }