Index: Modules/md5module.c =================================================================== --- Modules/md5module.c (Revision 68185) +++ Modules/md5module.c (Arbeitskopie) @@ -18,7 +18,26 @@ #include "Python.h" +#define GIL_MINSIZE 8192 +#ifdef WITH_THREAD + #include "pythread.h" + #define ENTER_MD5(obj) \ + if ((obj)->lock) { \ + Py_BEGIN_ALLOW_THREADS \ + PyThread_acquire_lock((obj)->lock, 1); \ + Py_END_ALLOW_THREADS \ + } + #define LEAVE_MD5(obj) \ + if ((obj)->lock) { \ + PyThread_release_lock((obj)->lock); \ + } +#else + #define ENTER_MD5(obj) + #define LEAVE_MD5(obj) +#endif + + /* Some useful types */ #if SIZEOF_INT == 4 @@ -43,8 +62,10 @@ typedef struct { PyObject_HEAD - struct md5_state hash_state; + #ifdef WITH_THREAD + PyThread_type_lock lock; + #endif } MD5object; @@ -318,19 +339,28 @@ static MD5object * newMD5object(void) { - return (MD5object *)PyObject_New(MD5object, &MD5type); + MD5object *retval = (MD5object *)PyObject_New(MD5object, &MD5type); + #ifdef WITH_THREAD + if (retval != NULL) { + retval->lock = NULL; + } + #endif + + return retval; } - /* Internal methods for a hash object */ static void MD5_dealloc(PyObject *ptr) { + #ifdef WITH_THREAD + if (((MD5object *)ptr)->lock != NULL) + PyThread_free_lock(((MD5object *)ptr)->lock); + #endif PyObject_Del(ptr); } - /* External methods for a hash object */ PyDoc_STRVAR(MD5_copy__doc__, "Return a copy of the hash object."); @@ -340,15 +370,12 @@ { MD5object *newobj; - if (Py_TYPE(self) == &MD5type) { - if ( (newobj = newMD5object())==NULL) - return NULL; - } else { - if ( (newobj = newMD5object())==NULL) - return NULL; - } + if ( (newobj = newMD5object())==NULL) + return NULL; + ENTER_MD5(self); newobj->hash_state = self->hash_state; + LEAVE_MD5(self); return (PyObject *)newobj; } @@ -361,8 +388,10 @@ unsigned char digest[MD5_DIGESTSIZE]; struct md5_state temp; + ENTER_MD5(self); temp = self->hash_state; md5_done(&temp, digest); + LEAVE_MD5(self); return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE); } @@ -379,8 +408,10 @@ int i, j; /* Get the raw (binary) digest value */ + ENTER_MD5(self); temp = self->hash_state; md5_done(&temp, digest); + LEAVE_MD5(self); /* Create a new string */ retval = PyUnicode_FromStringAndSize(NULL, MD5_DIGESTSIZE * 2); @@ -405,20 +436,60 @@ 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(MD5_update__doc__, "Update this hash object's state with the provided string."); static PyObject * MD5_update(MD5object *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); - md5_process(&self->hash_state, buf.buf, buf.len); - - PyBuffer_Release(&buf); + #ifdef WITH_THREAD + if (self->lock == NULL && buf.len >= GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + md5_process(&self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + md5_process(&self->hash_state, buf.buf, buf.len); + } + #else + md5_process(&self->hash_state, buf.buf, buf.len); + #endif + + PyBuffer_Release(&buf); Py_INCREF(Py_None); return Py_None; } @@ -511,27 +582,29 @@ { static char *kwlist[] = {"string", NULL}; MD5object *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 = newMD5object()) == NULL) return NULL; - md5_init(&new->hash_state); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; + + if (data_obj) { + if (buf.len > GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS; + md5_process(&new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS; + } else { + md5_process(&new->hash_state, buf.buf, buf.len); + } + PyBuffer_Release(&buf); } - if (buf.buf) { - md5_process(&new->hash_state, buf.buf, buf.len); - PyBuffer_Release(&buf); - } return (PyObject *)new; }