summaryrefslogtreecommitdiff
path: root/coverage/ctracer
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/ctracer')
-rw-r--r--coverage/ctracer/datastack.h2
-rw-r--r--coverage/ctracer/stats.h1
-rw-r--r--coverage/ctracer/tracer.c72
-rw-r--r--coverage/ctracer/tracer.h3
-rw-r--r--coverage/ctracer/util.h4
5 files changed, 76 insertions, 6 deletions
diff --git a/coverage/ctracer/datastack.h b/coverage/ctracer/datastack.h
index 78f85f7e..13149798 100644
--- a/coverage/ctracer/datastack.h
+++ b/coverage/ctracer/datastack.h
@@ -27,6 +27,8 @@ typedef struct DataStackEntry {
-1 means there was no previous line, as when entering a code object.
*/
int last_line;
+
+ int started_context;
} DataStackEntry;
/* A data stack is a dynamically allocated vector of DataStackEntry's. */
diff --git a/coverage/ctracer/stats.h b/coverage/ctracer/stats.h
index ceba79bd..a72117cf 100644
--- a/coverage/ctracer/stats.h
+++ b/coverage/ctracer/stats.h
@@ -24,6 +24,7 @@ typedef struct Stats {
unsigned int stack_reallocs;
unsigned int errors;
unsigned int pycalls;
+ unsigned int start_context_calls;
#endif
} Stats;
diff --git a/coverage/ctracer/tracer.c b/coverage/ctracer/tracer.c
index 681c9a97..02a613c0 100644
--- a/coverage/ctracer/tracer.c
+++ b/coverage/ctracer/tracer.c
@@ -73,6 +73,8 @@ CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
self->cur_entry.last_line = -1;
+ self->context = Py_None;
+
ret = RET_OK;
goto ok;
@@ -99,6 +101,9 @@ CTracer_dealloc(CTracer *self)
Py_XDECREF(self->data);
Py_XDECREF(self->file_tracers);
Py_XDECREF(self->should_trace_cache);
+ Py_XDECREF(self->should_start_context);
+ Py_XDECREF(self->switch_context);
+ Py_XDECREF(self->context);
DataStack_dealloc(&self->stats, &self->data_stack);
if (self->data_stacks) {
@@ -126,7 +131,7 @@ indent(int n)
return spaces + strlen(spaces) - n*2;
}
-static int logging = 0;
+static int logging = FALSE;
/* Set these constants to be a file substring and line number to start logging. */
static const char * start_file = "tests/views";
static int start_line = 27;
@@ -338,6 +343,7 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame)
STATS( self->stats.calls++; )
+
/* Grow the stack. */
if (CTracer_set_pdata_stack(self) < 0) {
goto error;
@@ -349,6 +355,37 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame)
/* Push the current state on the stack. */
self->pdata_stack->stack[self->pdata_stack->depth] = self->cur_entry;
+ /* See if this frame begins a new context. */
+ if (self->should_start_context && self->context == Py_None) {
+ PyObject * context;
+ /* We're looking for our context, ask should_start_context if this is the start. */
+ STATS( self->stats.start_context_calls++; )
+ STATS( self->stats.pycalls++; )
+ context = PyObject_CallFunctionObjArgs(self->should_start_context, frame, NULL);
+ if (context == NULL) {
+ goto error;
+ }
+ if (context != Py_None) {
+ PyObject * val;
+ Py_DECREF(self->context);
+ self->context = context;
+ self->cur_entry.started_context = TRUE;
+ STATS( self->stats.pycalls++; )
+ val = PyObject_CallFunctionObjArgs(self->switch_context, context, NULL);
+ if (val == NULL) {
+ goto error;
+ }
+ Py_DECREF(val);
+ }
+ else {
+ Py_DECREF(context);
+ self->cur_entry.started_context = FALSE;
+ }
+ }
+ else {
+ self->cur_entry.started_context = FALSE;
+ }
+
/* Check if we should trace this line. */
filename = frame->f_code->co_filename;
disposition = PyDict_GetItem(self->should_trace_cache, filename);
@@ -722,6 +759,22 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame)
}
}
+ /* If this frame started a context, then returning from it ends the context. */
+ if (self->cur_entry.started_context) {
+ PyObject * val;
+ Py_DECREF(self->context);
+ self->context = Py_None;
+ Py_INCREF(self->context);
+ STATS( self->stats.pycalls++; )
+
+ val = PyObject_CallFunctionObjArgs(self->switch_context, self->context, NULL);
+ if (val == NULL) {
+ goto error;
+ }
+ Py_DECREF(val);
+ }
+
+ /* Pop the stack. */
SHOWLOG(self->pdata_stack->depth, frame->f_lineno, frame->f_code->co_filename, "return");
self->cur_entry = self->pdata_stack->stack[self->pdata_stack->depth];
self->pdata_stack->depth--;
@@ -781,7 +834,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
#if TRACE_LOG
ascii = MyText_AS_BYTES(frame->f_code->co_filename);
if (strstr(MyBytes_AS_STRING(ascii), start_file) && frame->f_lineno == start_line) {
- logging = 1;
+ logging = TRUE;
}
Py_DECREF(ascii);
#endif
@@ -944,7 +997,7 @@ static PyObject *
CTracer_start(CTracer *self, PyObject *args_unused)
{
PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
- self->started = 1;
+ self->started = TRUE;
self->tracing_arcs = self->trace_arcs && PyObject_IsTrue(self->trace_arcs);
/* start() returns a trace function usable with sys.settrace() */
@@ -957,7 +1010,7 @@ CTracer_stop(CTracer *self, PyObject *args_unused)
{
if (self->started) {
PyEval_SetTrace(NULL, NULL);
- self->started = 0;
+ self->started = FALSE;
}
Py_RETURN_NONE;
@@ -968,7 +1021,7 @@ CTracer_get_stats(CTracer *self)
{
#if COLLECT_STATS
return Py_BuildValue(
- "{sI,sI,sI,sI,sI,sI,sI,sI,si,sI,sI}",
+ "{sI,sI,sI,sI,sI,sI,sI,sI,si,sI,sI,sI}",
"calls", self->stats.calls,
"lines", self->stats.lines,
"returns", self->stats.returns,
@@ -979,7 +1032,8 @@ CTracer_get_stats(CTracer *self)
"stack_reallocs", self->stats.stack_reallocs,
"stack_alloc", self->pdata_stack->alloc,
"errors", self->stats.errors,
- "pycalls", self->stats.pycalls
+ "pycalls", self->stats.pycalls,
+ "start_context_calls", self->stats.start_context_calls
);
#else
Py_RETURN_NONE;
@@ -1012,6 +1066,12 @@ CTracer_members[] = {
{ "trace_arcs", T_OBJECT, offsetof(CTracer, trace_arcs), 0,
PyDoc_STR("Should we trace arcs, or just lines?") },
+ { "should_start_context", T_OBJECT, offsetof(CTracer, should_start_context), 0,
+ PyDoc_STR("Function for starting contexts.") },
+
+ { "switch_context", T_OBJECT, offsetof(CTracer, switch_context), 0,
+ PyDoc_STR("Function for switch to a new context.") },
+
{ NULL }
};
diff --git a/coverage/ctracer/tracer.h b/coverage/ctracer/tracer.h
index 053fbf62..7769b2c2 100644
--- a/coverage/ctracer/tracer.h
+++ b/coverage/ctracer/tracer.h
@@ -25,6 +25,9 @@ typedef struct CTracer {
PyObject * file_tracers;
PyObject * should_trace_cache;
PyObject * trace_arcs;
+ PyObject * should_start_context;
+ PyObject * switch_context;
+ PyObject * context;
/* Has the tracer been started? */
int started;
diff --git a/coverage/ctracer/util.h b/coverage/ctracer/util.h
index 1f536194..78d9204c 100644
--- a/coverage/ctracer/util.h
+++ b/coverage/ctracer/util.h
@@ -47,4 +47,8 @@
#define RET_OK 0
#define RET_ERROR -1
+/* Nicer booleans */
+#define FALSE 0
+#define TRUE 1
+
#endif /* _COVERAGE_UTIL_H */