summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-11-18 06:27:13 -0600
committerJason Madden <jamadden@gmail.com>2020-11-18 06:27:13 -0600
commit3af5e994b9782c0c91d0ad9c575ef72655a23664 (patch)
treea7fed4cec69b1c5208495c96f4b6e6d7b92c6cd6
parent34ee3cbe99983d192c1a28abecfa62c5eb409eb7 (diff)
downloadgreenlet-issue207.tar.gz
Always complie with support for tracing, garbage collection and contextvars (where applicable).issue207
Remove undocumented compiler macros that let those things be switched off; they were never tested. Fixes #207
-rw-r--r--CHANGES.rst7
-rw-r--r--docs/development.rst3
-rw-r--r--src/greenlet/__init__.py4
-rw-r--r--src/greenlet/greenlet.c119
-rw-r--r--src/greenlet/greenlet.h15
5 files changed, 60 insertions, 88 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index cf9c04a..3c80a6e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -35,6 +35,13 @@
<https://github.com/python-greenlet/greenlet/pull/197>`_.
- (C API) The undocumented ``GREENLET_VERSION`` macro that defined a string
giving the greenlet version is now deprecated and will not be updated.
+- greenlet is now always built with support for tracing and garbage
+ collection, and, on Python 3.7 and above, support for context
+ variables. The internal and undocumented C preprocessor macros that could be used to
+ alter that at compile time have been removed (no combination other
+ than the defaults was ever tested). This helps define a
+ stable ABI.
+
0.4.17 (2020-09-22)
===================
diff --git a/docs/development.rst b/docs/development.rst
index 6c61208..651924a 100644
--- a/docs/development.rst
+++ b/docs/development.rst
@@ -20,8 +20,7 @@ greenlet uses Semantic Versions; this includes changes to the ABI
Releases are made using `zest.releaser
<https://zestreleaser.readthedocs.io/en/latest/>`_.
-.. code-block::
- :language: shell
+.. code-block:: shell
$ pip install zest.releaser[recommended]
$ fullrelease
diff --git a/src/greenlet/__init__.py b/src/greenlet/__init__.py
index c12e060..11f4de3 100644
--- a/src/greenlet/__init__.py
+++ b/src/greenlet/__init__.py
@@ -53,7 +53,9 @@ except ImportError:
###
# Constants
-# These constants aren't documented and aren't recommended
+# These constants aren't documented and aren't recommended.
+# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS
+# is the same as ``sys.version_info[:2] >= 3.7``
###
from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import
from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import
diff --git a/src/greenlet/greenlet.c b/src/greenlet/greenlet.c
index 06731a9..11c15bb 100644
--- a/src/greenlet/greenlet.c
+++ b/src/greenlet/greenlet.c
@@ -84,13 +84,10 @@ The running greenlet's stack_start is undefined but not NULL.
extern PyTypeObject PyGreenlet_Type;
-/* Defines that customize greenlet module behaviour */
-#ifndef GREENLET_USE_GC
-#define GREENLET_USE_GC 1
-#endif
-
-#ifndef GREENLET_USE_TRACING
-#define GREENLET_USE_TRACING 1
+#if PY_VERSION_HEX >= 0x030700A3
+# define GREENLET_PY37 1
+#else
+# define GREENLET_PY37 0
#endif
#ifndef Py_SET_REFCNT
@@ -127,35 +124,24 @@ static PyObject* volatile ts_passaround_kwargs = NULL;
static PyObject* ts_curkey;
static PyObject* ts_delkey;
-#if GREENLET_USE_TRACING
static PyObject* ts_tracekey;
static PyObject* ts_event_switch;
static PyObject* ts_event_throw;
-#endif
static PyObject* PyExc_GreenletError;
static PyObject* PyExc_GreenletExit;
static PyObject* ts_empty_tuple;
static PyObject* ts_empty_dict;
-#if GREENLET_USE_GC
#define GREENLET_GC_FLAGS Py_TPFLAGS_HAVE_GC
#define GREENLET_tp_alloc PyType_GenericAlloc
#define GREENLET_tp_free PyObject_GC_Del
#define GREENLET_tp_traverse green_traverse
#define GREENLET_tp_clear green_clear
#define GREENLET_tp_is_gc green_is_gc
-#else /* GREENLET_USE_GC */
-#define GREENLET_GC_FLAGS 0
-#define GREENLET_tp_alloc 0
-#define GREENLET_tp_free 0
-#define GREENLET_tp_traverse 0
-#define GREENLET_tp_clear 0
-#define GREENLET_tp_is_gc 0
-#endif /* !GREENLET_USE_GC */
static void green_clear_exc(PyGreenlet* g)
{
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
g->exc_info = NULL;
g->exc_state.exc_type = NULL;
g->exc_state.exc_value = NULL;
@@ -475,10 +461,10 @@ static int g_switchstack(void)
PyThreadState* tstate = PyThreadState_GET();
current->recursion_depth = tstate->recursion_depth;
current->top_frame = tstate->frame;
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
current->context = tstate->context;
#endif
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
current->exc_info = tstate->exc_info;
current->exc_state = tstate->exc_state;
#else
@@ -491,7 +477,7 @@ static int g_switchstack(void)
if (err < 0) { /* error */
PyGreenlet* current = ts_current;
current->top_frame = NULL;
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
green_clear_exc(current);
#else
current->exc_type = NULL;
@@ -510,7 +496,7 @@ static int g_switchstack(void)
tstate->frame = target->top_frame;
target->top_frame = NULL;
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
tstate->context = target->context;
target->context = NULL;
/* Incrementing this value invalidates the contextvars cache,
@@ -518,7 +504,7 @@ static int g_switchstack(void)
tstate->context_ver++;
#endif
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
tstate->exc_state = target->exc_state;
tstate->exc_info = target->exc_info ? target->exc_info : &tstate->exc_state;
#else
@@ -537,7 +523,7 @@ static int g_switchstack(void)
return err;
}
-#if GREENLET_USE_TRACING
+
static int
g_calltrace(PyObject* tracefunc, PyObject* event, PyGreenlet* origin, PyGreenlet* target)
{
@@ -566,7 +552,7 @@ g_calltrace(PyObject* tracefunc, PyObject* event, PyGreenlet* origin, PyGreenlet
PyErr_Restore(exc_type, exc_val, exc_tb);
return 0;
}
-#endif
+
static PyObject *
g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
@@ -630,13 +616,11 @@ g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
Py_CLEAR(args);
} else {
PyGreenlet *origin;
-#if GREENLET_USE_TRACING
PyGreenlet *current;
PyObject *tracefunc;
-#endif
origin = ts_origin;
ts_origin = NULL;
-#if GREENLET_USE_TRACING
+
current = ts_current;
if ((tracefunc = PyDict_GetItem(current->run_info, ts_tracekey)) != NULL) {
Py_INCREF(tracefunc);
@@ -647,7 +631,7 @@ g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
}
Py_DECREF(tracefunc);
}
-#endif
+
Py_DECREF(origin);
}
@@ -797,9 +781,7 @@ static int GREENLET_NOINLINE(g_initialstub)(void* mark)
if (err == 1) {
/* in the new greenlet */
PyGreenlet* origin;
-#if GREENLET_USE_TRACING
PyObject* tracefunc;
-#endif
PyObject* result;
PyGreenlet* parent;
self->stack_start = (char*) 1; /* running */
@@ -814,7 +796,7 @@ static int GREENLET_NOINLINE(g_initialstub)(void* mark)
Py_INCREF(self->run_info);
Py_XDECREF(o);
-#if GREENLET_USE_TRACING
+
if ((tracefunc = PyDict_GetItem(self->run_info, ts_tracekey)) != NULL) {
Py_INCREF(tracefunc);
if (g_calltrace(tracefunc, args ? ts_event_switch : ts_event_throw, origin, self) < 0) {
@@ -824,7 +806,7 @@ static int GREENLET_NOINLINE(g_initialstub)(void* mark)
}
Py_DECREF(tracefunc);
}
-#endif
+
Py_DECREF(origin);
if (args == NULL) {
@@ -949,7 +931,7 @@ static int kill_greenlet(PyGreenlet* self)
}
}
-#if GREENLET_USE_GC
+
static int
green_traverse(PyGreenlet *self, visitproc visit, void *arg)
{
@@ -959,10 +941,10 @@ green_traverse(PyGreenlet *self, visitproc visit, void *arg)
- frames are not visited: alive greenlets are not garbage collected anyway */
Py_VISIT((PyObject*)self->parent);
Py_VISIT(self->run_info);
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
Py_VISIT(self->context);
#endif
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
Py_VISIT(self->exc_state.exc_type);
Py_VISIT(self->exc_state.exc_value);
Py_VISIT(self->exc_state.exc_traceback);
@@ -994,10 +976,10 @@ static int green_clear(PyGreenlet* self)
so even if it switches we are relatively safe. */
Py_CLEAR(self->parent);
Py_CLEAR(self->run_info);
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
Py_CLEAR(self->context);
#endif
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
Py_CLEAR(self->exc_state.exc_type);
Py_CLEAR(self->exc_state.exc_value);
Py_CLEAR(self->exc_state.exc_traceback);
@@ -1009,16 +991,14 @@ static int green_clear(PyGreenlet* self)
Py_CLEAR(self->dict);
return 0;
}
-#endif
+
static void green_dealloc(PyGreenlet* self)
{
PyObject *error_type, *error_value, *error_traceback;
Py_ssize_t refcnt;
-#if GREENLET_USE_GC
PyObject_GC_UnTrack(self);
-#endif
if (PyGreenlet_ACTIVE(self) && self->run_info != NULL && !PyGreenlet_MAIN(self)) {
/* Hacks hacks hacks copied from instance_dealloc() */
@@ -1060,9 +1040,9 @@ static void green_dealloc(PyGreenlet* self)
/* Resurrected! */
_Py_NewReference((PyObject*) self);
Py_SET_REFCNT(self, refcnt);
-#if GREENLET_USE_GC
+
PyObject_GC_Track((PyObject *)self);
-#endif
+
_Py_DEC_REFTOTAL;
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
@@ -1075,10 +1055,10 @@ static void green_dealloc(PyGreenlet* self)
PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->parent);
Py_CLEAR(self->run_info);
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
Py_CLEAR(self->context);
#endif
-#ifdef GREENLET_USE_EXC_INFO
+#if GREENLET_PY37
Py_CLEAR(self->exc_state.exc_type);
Py_CLEAR(self->exc_state.exc_value);
Py_CLEAR(self->exc_state.exc_traceback);
@@ -1088,7 +1068,7 @@ static void green_dealloc(PyGreenlet* self)
Py_CLEAR(self->exc_traceback);
#endif
Py_CLEAR(self->dict);
- Py_TYPE(self)->tp_free((PyObject*) self);
+ Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject* single_result(PyObject* results)
@@ -1360,7 +1340,7 @@ static int green_setparent(PyGreenlet* self, PyObject* nparent, void* c)
static PyObject* green_getcontext(PyGreenlet* self, void* c)
{
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
PyThreadState* tstate = PyThreadState_GET();
PyObject* result;
@@ -1399,7 +1379,7 @@ static PyObject* green_getcontext(PyGreenlet* self, void* c)
static int green_setcontext(PyGreenlet* self, PyObject* nctx, void* c)
{
-#if GREENLET_USE_CONTEXT_VARS
+#if GREENLET_PY37
PyThreadState* tstate;
PyObject* octx = NULL;
if (!STATE_OK) {
@@ -1674,7 +1654,7 @@ static PyObject* mod_getcurrent(PyObject* self)
return (PyObject*) ts_current;
}
-#if GREENLET_USE_TRACING
+
PyDoc_STRVAR(mod_settrace_doc,
"settrace(callback) -> object\n"
"\n"
@@ -1721,14 +1701,12 @@ static PyObject* mod_gettrace(PyObject* self)
Py_INCREF(tracefunc);
return tracefunc;
}
-#endif
+
static PyMethodDef GreenMethods[] = {
{"getcurrent", (PyCFunction)mod_getcurrent, METH_NOARGS, mod_getcurrent_doc},
-#if GREENLET_USE_TRACING
{"settrace", (PyCFunction)mod_settrace, METH_VARARGS, mod_settrace_doc},
{"gettrace", (PyCFunction)mod_gettrace, METH_NOARGS, mod_gettrace_doc},
-#endif
{NULL, NULL} /* Sentinel */
};
@@ -1736,10 +1714,8 @@ static char* copy_on_greentype[] = {
"getcurrent",
"error",
"GreenletExit",
-#if GREENLET_USE_TRACING
"settrace",
"gettrace",
-#endif
NULL
};
@@ -1781,22 +1757,17 @@ init_greenlet(void)
}
#if PY_MAJOR_VERSION >= 3
- ts_curkey = PyUnicode_InternFromString("__greenlet_ts_curkey");
- ts_delkey = PyUnicode_InternFromString("__greenlet_ts_delkey");
-#if GREENLET_USE_TRACING
- ts_tracekey = PyUnicode_InternFromString("__greenlet_ts_tracekey");
- ts_event_switch = PyUnicode_InternFromString("switch");
- ts_event_throw = PyUnicode_InternFromString("throw");
-#endif
+# define Greenlet_Intern PyUnicode_InternFromString
#else
- ts_curkey = PyString_InternFromString("__greenlet_ts_curkey");
- ts_delkey = PyString_InternFromString("__greenlet_ts_delkey");
-#if GREENLET_USE_TRACING
- ts_tracekey = PyString_InternFromString("__greenlet_ts_tracekey");
- ts_event_switch = PyString_InternFromString("switch");
- ts_event_throw = PyString_InternFromString("throw");
-#endif
+# define Greenlet_Intern PyString_InternFromString
#endif
+ ts_curkey = Greenlet_Intern("__greenlet_ts_curkey");
+ ts_delkey = Greenlet_Intern("__greenlet_ts_delkey");
+ ts_tracekey = Greenlet_Intern("__greenlet_ts_tracekey");
+ ts_event_switch = Greenlet_Intern("switch");
+ ts_event_throw = Greenlet_Intern("throw");
+#undef Greenlet_Intern
+
if (ts_curkey == NULL || ts_delkey == NULL)
{
INITERROR;
@@ -1841,9 +1812,13 @@ init_greenlet(void)
PyModule_AddObject(m, "error", PyExc_GreenletError);
Py_INCREF(PyExc_GreenletExit);
PyModule_AddObject(m, "GreenletExit", PyExc_GreenletExit);
- PyModule_AddObject(m, "GREENLET_USE_GC", PyBool_FromLong(GREENLET_USE_GC));
- PyModule_AddObject(m, "GREENLET_USE_TRACING", PyBool_FromLong(GREENLET_USE_TRACING));
- PyModule_AddObject(m, "GREENLET_USE_CONTEXT_VARS", PyBool_FromLong(GREENLET_USE_CONTEXT_VARS));
+
+ PyModule_AddObject(m, "GREENLET_USE_GC",
+ PyBool_FromLong(1));
+ PyModule_AddObject(m, "GREENLET_USE_TRACING",
+ PyBool_FromLong(1));
+ PyModule_AddObject(m, "GREENLET_USE_CONTEXT_VARS",
+ PyBool_FromLong(GREENLET_PY37));
/* also publish module-level data as attributes of the greentype. */
/* XXX: Why? */
diff --git a/src/greenlet/greenlet.h b/src/greenlet/greenlet.h
index de67ebc..d31cae7 100644
--- a/src/greenlet/greenlet.h
+++ b/src/greenlet/greenlet.h
@@ -14,17 +14,6 @@ extern "C" {
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
-#if PY_VERSION_HEX >= 0x030700A3
-# define GREENLET_USE_EXC_INFO
-#endif
-
-#ifndef GREENLET_USE_CONTEXT_VARS
-#ifdef Py_CONTEXT_H
-#define GREENLET_USE_CONTEXT_VARS 1
-#else
-#define GREENLET_USE_CONTEXT_VARS 0
-#endif
-#endif
typedef struct _greenlet {
PyObject_HEAD
@@ -38,7 +27,7 @@ typedef struct _greenlet {
struct _frame* top_frame;
int recursion_depth;
PyObject* weakreflist;
-#ifdef GREENLET_USE_EXC_INFO
+#if PY_VERSION_HEX >= 0x030700A3
_PyErr_StackItem* exc_info;
_PyErr_StackItem exc_state;
#else
@@ -47,7 +36,7 @@ typedef struct _greenlet {
PyObject* exc_traceback;
#endif
PyObject* dict;
-#if GREENLET_USE_CONTEXT_VARS
+#if PY_VERSION_HEX >= 0x030700A3
PyObject* context;
#endif
} PyGreenlet;