Commit dbb55b10 authored by Jason Madden's avatar Jason Madden

Straighten out the test__threading_2 reference leak.

This should fix the refleaks in general (it was a frame object that was leaking).
Submitting to CI for broad test, and if it is good then we will try backing out the test__util changes too.

Also make it possible for gevent.config to show help.
parent 07569cc3
...@@ -234,7 +234,6 @@ def cythonize1(ext): ...@@ -234,7 +234,6 @@ def cythonize1(ext):
'.', '.',
] ]
try: try:
print("XXX: Drop compile_time_env")
new_ext = cythonize( new_ext = cythonize(
[ext], [ext],
include_path=standard_include_paths, include_path=standard_include_paths,
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
#include <Python.h> #include <Python.h>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
...@@ -31,7 +36,7 @@ extern "C" { ...@@ -31,7 +36,7 @@ extern "C" {
need to increment the refcount before returning, not just to match the need to increment the refcount before returning, not just to match the
official functions, but to match what Cython expects an API like this to official functions, but to match what Cython expects an API like this to
return. Otherwise we get crashes. */ return. Otherwise we get crashes. */
static void* PyFrame_GetBack(PyFrameObject* frame) static PyObject* PyFrame_GetBack(PyFrameObject* frame)
{ {
PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_back; PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_back;
Py_XINCREF(result); Py_XINCREF(result);
...@@ -41,13 +46,38 @@ static void* PyFrame_GetBack(PyFrameObject* frame) ...@@ -41,13 +46,38 @@ static void* PyFrame_GetBack(PyFrameObject* frame)
static PyObject* PyFrame_GetCode(PyFrameObject* frame) static PyObject* PyFrame_GetCode(PyFrameObject* frame)
{ {
PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_code; PyObject* result = (PyObject*)((PyFrameObject*)frame)->f_code;
Py_XINCREF(result); /* There is always code! */
Py_INCREF(result);
return result; return result;
} }
#endif /* support 3.8 and below. */ #endif /* support 3.8 and below. */
#endif #endif
/**
Unlike PyFrame_GetBack, which can return NULL,
this method is guaranteed to return a new reference to an object.
The object is either a frame object or None.
This is necessary to help Cython deal correctly with reference counting.
(There are other ways of dealing with this having to do with exactly how
variables/return types are declared IIRC, but this is the most
straightforward. Still, it is critical that the cython declaration of
this function use ``object`` as its return type.)
*/
static PyObject* Gevent_PyFrame_GetBack(PyFrameObject* frame)
{
PyObject* back = (PyObject*)PyFrame_GetBack(frame);
if (back) {
return back;
}
Py_RETURN_NONE;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif #endif
#endif /* _COMPAT_H */ #endif /* _COMPAT_H */
...@@ -6,6 +6,11 @@ This should be used as ``from gevent import config``. That variable ...@@ -6,6 +6,11 @@ This should be used as ``from gevent import config``. That variable
is an object of :class:`Config`. is an object of :class:`Config`.
.. versionadded:: 1.3a2 .. versionadded:: 1.3a2
.. versionchanged:: NEXT
Invoking this module like ``python -m gevent._config`` will
print a help message about available configuration properties.
This is handy to quickly look for environment variables.
""" """
from __future__ import print_function, absolute_import, division from __future__ import print_function, absolute_import, division
...@@ -206,6 +211,12 @@ class Config(object): ...@@ -206,6 +211,12 @@ class Config(object):
def __dir__(self): def __dir__(self):
return list(self.settings) return list(self.settings)
def print_help(self):
for k, v in self.settings.items():
print(k)
print(textwrap.indent(v.__doc__.lstrip(), ' ' * 4))
print()
class ImportableSetting(object): class ImportableSetting(object):
...@@ -473,7 +484,9 @@ class TrackGreenletTree(BoolSettingMixin, Setting): ...@@ -473,7 +484,9 @@ class TrackGreenletTree(BoolSettingMixin, Setting):
Setting this to a false value will make spawning `Greenlet` Setting this to a false value will make spawning `Greenlet`
objects and using `spawn_raw` faster, but the objects and using `spawn_raw` faster, but the
``spawning_greenlet``, ``spawn_tree_locals`` and ``spawning_stack`` ``spawning_greenlet``, ``spawn_tree_locals`` and ``spawning_stack``
will not be captured. will not be captured. Setting this to a false value can also
reduce memory usage because capturing the stack captures
some information about Python frames.
.. versionadded:: 1.3b1 .. versionadded:: 1.3b1
""" """
...@@ -717,3 +730,7 @@ try: ...@@ -717,3 +730,7 @@ try:
Loop().get() Loop().get()
except ImportError: # pragma: no cover except ImportError: # pragma: no cover
pass pass
if __name__ == '__main__':
config.print_help()
...@@ -57,19 +57,13 @@ ctypedef object CodeType ...@@ -57,19 +57,13 @@ ctypedef object CodeType
cdef extern from "_compat.h": cdef extern from "_compat.h":
int PyFrame_GetLineNumber(FrameType frame) int PyFrame_GetLineNumber(FrameType frame)
CodeType PyFrame_GetCode(FrameType frame) CodeType PyFrame_GetCode(FrameType frame)
void* PyFrame_GetBack(FrameType frame) object Gevent_PyFrame_GetBack(FrameType frame)
ctypedef class types.FrameType [object PyFrameObject]: ctypedef class types.FrameType [object PyFrameObject]:
pass pass
@cython.nonecheck(False) @cython.nonecheck(False)
cdef inline FrameType get_f_back(FrameType frame): cdef inline object get_f_back(FrameType frame):
# We cannot just call the original version, because it return Gevent_PyFrame_GetBack(frame)
# can return NULL even when there is no exception set. That confuses
# Cython and CPython. We need to manually check for NULL here.
f_back = PyFrame_GetBack(frame)
if f_back != NULL:
return <FrameType>f_back
cdef void _init() cdef void _init()
......
...@@ -413,7 +413,6 @@ class ThreadTests(unittest.TestCase): ...@@ -413,7 +413,6 @@ class ThreadTests(unittest.TestCase):
if not hasattr(sys, 'pypy_version_info'): if not hasattr(sys, 'pypy_version_info'):
def test_no_refcycle_through_target(self): def test_no_refcycle_through_target(self):
self.skipTest('WARNING: LEAKING.Debugging.')
class RunSelfFunction(object): class RunSelfFunction(object):
def __init__(self, should_raise): def __init__(self, should_raise):
# The links in this refcycle from Thread back to self # The links in this refcycle from Thread back to self
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment