Skip to content

use atomics for started and activity flags #2019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions coverage/ctracer/tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
return RET_OK;
#endif

if (!self->started) {
if (!atomic_load(&self->started)) {
/* If CTracer.stop() has been called from another thread, the tracer
is still active in the current thread. Let's deactivate ourselves
now. */
Expand Down Expand Up @@ -848,7 +848,7 @@ CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse
Py_DECREF(ascii);
#endif

self->activity = TRUE;
atomic_store(&self->activity, TRUE);

switch (what) {
case PyTrace_CALL:
Expand Down Expand Up @@ -981,9 +981,10 @@ CTracer_call(CTracer *self, PyObject *args, PyObject *kwds)
static PyObject *
CTracer_start(CTracer *self, PyObject *args_unused)
{
assert(atomic_load(&self->started) == FALSE);
PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
self->started = TRUE;
self->tracing_arcs = self->trace_arcs && PyObject_IsTrue(self->trace_arcs);
atomic_store(&self->started, TRUE);

/* start() returns a trace function usable with sys.settrace() */
Py_INCREF(self);
Expand All @@ -993,21 +994,19 @@ CTracer_start(CTracer *self, PyObject *args_unused)
static PyObject *
CTracer_stop(CTracer *self, PyObject *args_unused)
{
if (self->started) {
/* Set the started flag only. The actual call to
PyEval_SetTrace(NULL, NULL) is delegated to the callback
itself to ensure that it called from the right thread.
*/
self->started = FALSE;
}
/* Set the started flag only. The actual call to
PyEval_SetTrace(NULL, NULL) is delegated to the callback
itself to ensure that it called from the right thread.
*/
atomic_store(&self->started, FALSE);

Py_RETURN_NONE;
}

static PyObject *
CTracer_activity(CTracer *self, PyObject *args_unused)
{
if (self->activity) {
if (atomic_load(&self->activity)) {
Py_RETURN_TRUE;
}
else {
Expand All @@ -1018,7 +1017,7 @@ CTracer_activity(CTracer *self, PyObject *args_unused)
static PyObject *
CTracer_reset_activity(CTracer *self, PyObject *args_unused)
{
self->activity = FALSE;
atomic_store(&self->activity, FALSE);
Py_RETURN_NONE;
}

Expand Down
4 changes: 2 additions & 2 deletions coverage/ctracer/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ typedef struct CTracer {
PyObject * disable_plugin;

/* Has the tracer been started? */
BOOL started;
_Atomic BOOL started;
/* Are we tracing arcs, or just lines? */
BOOL tracing_arcs;
/* Have we had any activity? */
BOOL activity;
_Atomic BOOL activity;
/* The current dynamic context. */
PyObject * context;

Expand Down
1 change: 1 addition & 0 deletions coverage/ctracer/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define _COVERAGE_UTIL_H

#include <Python.h>
#include <stdatomic.h>

/* Compile-time debugging helpers */
#undef WHAT_LOG /* Define to log the WHAT params in the trace function. */
Expand Down
5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ def run(self):

def build_extension(self, ext):
"""Wrap `build_extension` with `BuildFailed`."""
if self.compiler.compiler_type == "msvc":
ext.extra_compile_args = (ext.extra_compile_args or []) + [
"/std:c11",
"/experimental:c11atomics",
]
try:
# Uncomment to test compile failure handling:
# raise errors.CCompilerError("OOPS")
Expand Down
Loading