diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2016-01-30 15:51:08 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2016-01-30 15:51:08 -0500 |
commit | 58d4c073a8ab0c7b5d2ca1d700e77729a07e3aa7 (patch) | |
tree | d81a55facc686fdacde985590a5ee6c72b83b614 /coverage/ctracer/tracer.c | |
parent | 2002903f2257a361ad42ab4f2e338e5212f8eaf6 (diff) | |
parent | 60297f4fda470bc7d44de20384efd96fbbaea7de (diff) | |
download | python-coveragepy-git-58d4c073a8ab0c7b5d2ca1d700e77729a07e3aa7.tar.gz |
Merged who-tests-what-170
Diffstat (limited to 'coverage/ctracer/tracer.c')
-rw-r--r-- | coverage/ctracer/tracer.c | 72 |
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 } }; |