diff --git a/packages/google-crc32c/src/google_crc32c/_crc32c.c b/packages/google-crc32c/src/google_crc32c/_crc32c.c index c84b8839376a..b20b94d5542d 100644 --- a/packages/google-crc32c/src/google_crc32c/_crc32c.c +++ b/packages/google-crc32c/src/google_crc32c/_crc32c.c @@ -2,6 +2,16 @@ #include #include +/* The minimum buffer size in bytes (1MB) required to justify the overhead of releasing the GIL. */ +static const Py_ssize_t gil_threshold = 1024 * 1024; + +static int +_should_release_gil(Py_ssize_t length, PyObject *chunk_obj) +{ + /* Checks if the chunk is immutable (bytes) to prevent concurrent modification, + * and large enough to benefit from releasing the GIL. */ + return (length >= gil_threshold && PyBytes_Check(chunk_obj)); +} static PyObject * _crc32c_extend(PyObject *self, PyObject *args) @@ -10,12 +20,21 @@ _crc32c_extend(PyObject *self, PyObject *args) uint32_t crc; const char *chunk; Py_ssize_t length; + PyThreadState *save = NULL; if (!PyArg_ParseTuple(args, "ky#", &crc_input, &chunk, &length)) return NULL; + if (_should_release_gil(length, PyTuple_GET_ITEM(args, 1))) { + save = PyEval_SaveThread(); + } + crc = crc32c_extend((uint32_t)crc_input, (const uint8_t*)chunk, length); + if (save) { + PyEval_RestoreThread(save); + } + return PyLong_FromUnsignedLong(crc); } @@ -26,12 +45,21 @@ _crc32c_value(PyObject *self, PyObject *args) uint32_t crc; const char *chunk; Py_ssize_t length; + PyThreadState *save = NULL; if (!PyArg_ParseTuple(args, "y#", &chunk, &length)) return NULL; + if (_should_release_gil(length, PyTuple_GET_ITEM(args, 0))) { + save = PyEval_SaveThread(); + } + crc = crc32c_value((const uint8_t*)chunk, length); + if (save) { + PyEval_RestoreThread(save); + } + return PyLong_FromUnsignedLong(crc); }