Skip to content

Expose _PyCriticalSection_BeginMutex as a public API #133296

Open
@hawkinsp

Description

@hawkinsp

Feature or enhancement

Proposal:

It would be helpful to expose _PyCriticalSection_BeginMutex as a public API.

There are times when one does not have really have a PyObject, but still might want to use a critical section. For example, we wanted to use a critical section to protect some initialization code in a C extension module, where we wanted to write something like this:

static PyMutex mu;
static PyObject* mymodule = nullptr;

// It is important that we use a critical section here rather than a regular
// PyMutex, say 'M', because we need to avoid the following deadlock:
// * thread T1 holds M and calls ImportModule, which attempts to acquire a
//   critical section C.
// * thread T2 holds critical section C and attempts to call this code and
//   acquire M.
// In general, if you're going to hold a lock while calling into Python code, it had better be a critical section.

PyCriticalSection cs;
_PyCriticalSection_BeginMutex(&cs, &mu);
if (!mymodule) {
    PyObject *m = PyImport_ImportModule("mymodule");

    // Importing may have released the critical section, so it is possible
    // another thread might have populated mymodule. Make sure we clean up after
    // ourselves in that case.
    std::swap(mymodule, m);
    Py_XDECREF(m);
}
PyCriticalSection_End(&cs);

Currently one would have to write something like the following instead:

static PyObject object_for_mu;  // Not really an object, we just want its mutex.
static PyObject* mymodule = nullptr;

PyCriticalSection cs;
PyCriticalSection_Begin(&cs, &object_for_mu);
if (!mymodule) {
    PyObject *m = PyImport_ImportModule("mymodule");

    std::swap(mymodule, m);
    Py_XDECREF(m);
}
PyCriticalSection_End(&cs);

@colesbury

Has this already been discussed elsewhere?

This is a minor feature, which does not need previous discussion elsewhere

Links to previous discussion of this feature:

No response

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions