Index: Modules/sha1module.c =================================================================== --- Modules/sha1module.c (Revision 68196) +++ Modules/sha1module.c (Arbeitskopie) @@ -18,6 +18,25 @@ #include "Python.h" +#define SHA1_GIL_MINSIZE 8192 +#ifdef WITH_THREAD + #include "pythread.h" + + #define ENTER_SHA1(obj) \ + if ((obj)->lock) { \ + if (!PyThread_acquire_lock((obj)->lock, 0)) { \ + Py_BEGIN_ALLOW_THREADS; \ + PyThread_acquire_lock((obj)->lock, 1); \ + Py_END_ALLOW_THREADS; \ + } \ + } + #define LEAVE_SHA1(obj) \ + if ((obj)->lock) \ + PyThread_release_lock((obj)->lock); +#else + #define ENTER_SHA1(obj) + #define LEAVE_SHA1(obj) +#endif /* Some useful types */ @@ -43,8 +62,10 @@ typedef struct { PyObject_HEAD - struct sha1_state hash_state; + #ifdef WITH_THREAD + PyThread_type_lock lock; + #endif } SHA1object; @@ -294,7 +315,13 @@ static SHA1object * newSHA1object(void) { - return (SHA1object *)PyObject_New(SHA1object, &SHA1type); + SHA1object *retval = PyObject_New(SHA1object, &SHA1type); + #ifdef WITH_THREAD + if (retval != NULL) + retval->lock = NULL; + #endif + + return retval; } @@ -303,6 +330,10 @@ static void SHA1_dealloc(PyObject *ptr) { + #ifdef WITH_THREAD + if (((SHA1object *)ptr)->lock != NULL) + PyThread_free_lock(((SHA1object *)ptr)->lock); + #endif PyObject_Del(ptr); } @@ -316,15 +347,12 @@ { SHA1object *newobj; - if (Py_TYPE(self) == &SHA1type) { - if ( (newobj = newSHA1object())==NULL) - return NULL; - } else { - if ( (newobj = newSHA1object())==NULL) - return NULL; - } + if ( (newobj = newSHA1object())==NULL) + return NULL; + ENTER_SHA1(self); newobj->hash_state = self->hash_state; + LEAVE_SHA1(self); return (PyObject *)newobj; } @@ -337,7 +365,9 @@ unsigned char digest[SHA1_DIGESTSIZE]; struct sha1_state temp; + ENTER_SHA1(self); temp = self->hash_state; + LEAVE_SHA1(self); sha1_done(&temp, digest); return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE); } @@ -355,7 +385,9 @@ int i, j; /* Get the raw (binary) digest value */ + ENTER_SHA1(self); temp = self->hash_state; + LEAVE_SHA1(self); sha1_done(&temp, digest); /* Create a new string */ @@ -381,19 +413,59 @@ return retval; } +#define MY_GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \ + if (PyUnicode_Check((obj))) { \ + PyErr_SetString(PyExc_TypeError, \ + "Unicode-objects must be encoded before hashing");\ + return NULL; \ + } \ + if (!PyObject_CheckBuffer((obj))) { \ + PyErr_SetString(PyExc_TypeError, \ + "object supporting the buffer API required"); \ + return NULL; \ + } \ + if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \ + return NULL; \ + } \ + if ((viewp)->ndim > 1) { \ + PyErr_SetString(PyExc_BufferError, \ + "Buffer must be single dimension"); \ + PyBuffer_Release((viewp)); \ + return NULL; \ + } \ + } while(0); + PyDoc_STRVAR(SHA1_update__doc__, "Update this hash object's state with the provided string."); static PyObject * SHA1_update(SHA1object *self, PyObject *args) { + PyObject *obj; Py_buffer buf; - if (!PyArg_ParseTuple(args, "s*:update", &buf)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; + + MY_GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + + #ifdef WITH_THREAD + if (self->lock == NULL && buf.len >= SHA1_GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + sha1_process(&self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS; + } else { + sha1_process(&self->hash_state, buf.buf, buf.len); + } + #else + sha1_process(&self->hash_state, buf.buf, buf.len); + #endif - sha1_process(&self->hash_state, buf.buf, buf.len); - PyBuffer_Release(&buf); Py_INCREF(Py_None); return Py_None; @@ -487,27 +559,32 @@ { static char *kwlist[] = {"string", NULL}; SHA1object *new; + PyObject *data_obj = NULL; Py_buffer buf; - buf.buf = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s*:new", kwlist, - &buf)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, &data_obj)) return NULL; - } + + if (data_obj) + MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); - if ((new = newSHA1object()) == NULL) + if ((new = newSHA1object()) == NULL) { + if (data_obj) + PyBuffer_Release(&buf); return NULL; - + } sha1_init(&new->hash_state); - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; + if (data_obj) { + if (buf.len > SHA1_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS; + sha1_process(&new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS; + } else { + sha1_process(&new->hash_state, buf.buf, buf.len); + } + PyBuffer_Release(&buf); } - if (buf.buf) { - sha1_process(&new->hash_state, buf.buf, buf.len); - PyBuffer_Release(&buf); - } return (PyObject *)new; }