Skip to content

Guard _mysql.connection with a per-connection lock on non-free-threaded CPython#781

Draft
Copilot wants to merge 6 commits into
mainfrom
copilot/modify-lightweight-lock-for-connection
Draft

Guard _mysql.connection with a per-connection lock on non-free-threaded CPython#781
Copilot wants to merge 6 commits into
mainfrom
copilot/modify-lightweight-lock-for-connection

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 8, 2026

Concurrent use of the same _mysql.connection object was still possible on non-free-threaded CPython when _mysql.c dropped the GIL around libmysql calls. This change adds a lightweight connection-local guard for that build mode and has Result reuse the same guard so connection/result state stays serialized without introducing a second lock.

  • Build-mode split

    • Use Py_GIL_DISABLED as the compile-time switch.
    • On free-threaded builds, use Python critical sections instead of adding another lock layer.
    • On non-free-threaded builds, store a PyThread_type_lock on _mysql_ConnectionObject.
  • Connection-level serialization

    • Wrap connection operations that touch libmysql state with the connection guard.
    • Keep the guard held across Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS regions so libmysql calls remain serialized even while the GIL is released.
  • Result reuses connection guard

    • Result initialization, fetch/discard/seek helpers, metadata access, and deallocation now synchronize through the owning connection.
    • No separate result lock is introduced; connection and result activity on the same underlying MYSQL* share one guard.
  • Focused regression coverage

    • Add DB-backed threading tests that assert:
      • a connection operation blocks a concurrent thread_id()
      • a result operation blocks a concurrent thread_id()

Example of the new guard shape:

#ifdef Py_GIL_DISABLED
    PyCriticalSection_Begin(&_mysql_cs, (PyObject *)self);
#else
    PyThread_acquire_lock(self->lock, WAIT_LOCK);
#endif

Py_BEGIN_ALLOW_THREADS
r = mysql_real_query(&(self->connection), query, len);
Py_END_ALLOW_THREADS

#ifdef Py_GIL_DISABLED
    PyCriticalSection_End(&_mysql_cs);
#else
    PyThread_release_lock(self->lock);
#endif

Copilot AI changed the title [WIP] Add lightweight lock on connection for thread safety Guard _mysql.connection with a per-connection lock on non-free-threaded CPython Jun 8, 2026
Copilot AI requested a review from methane June 8, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C extension bug / Uncaught in Python causing kernel to die

2 participants