summaryrefslogtreecommitdiff
path: root/coverage/ctracer/tracer.c
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2016-01-30 15:51:08 -0500
committerNed Batchelder <ned@nedbatchelder.com>2016-01-30 15:51:08 -0500
commit58d4c073a8ab0c7b5d2ca1d700e77729a07e3aa7 (patch)
treed81a55facc686fdacde985590a5ee6c72b83b614 /coverage/ctracer/tracer.c
parent2002903f2257a361ad42ab4f2e338e5212f8eaf6 (diff)
parent60297f4fda470bc7d44de20384efd96fbbaea7de (diff)
downloadpython-coveragepy-git-58d4c073a8ab0c7b5d2ca1d700e77729a07e3aa7.tar.gz
Merged who-tests-what-170
Diffstat (limited to 'coverage/ctracer/tracer.c')
-rw-r--r--coverage/ctracer/tracer.c72
1 files changed, 66 insertions, 6 deletions
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 }
};