Index: Modules/sha512module.c =================================================================== --- Modules/sha512module.c (Revision 68196) +++ Modules/sha512module.c (Arbeitskopie) @@ -21,6 +21,27 @@ #ifdef PY_LONG_LONG /* If no PY_LONG_LONG, don't compile anything! */ +#define SHA512_GIL_MINSIZE 8192 +#ifdef WITH_THREAD + #include "pythread.h" + + #define ENTER_SHA512(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_SHA512(obj) \ + if ((obj)->lock) \ + PyThread_release_lock((obj)->lock); +#else + #define ENTER_SHA256(obj) + #define LEAVE_SHA256(obj) +#endif + + /* Endianness testing and definitions */ #define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} @@ -54,6 +75,9 @@ int Endianness; int local; /* unprocessed amount in data */ int digestsize; + #ifdef WITH_THREAD + PyThread_type_lock lock; + #endif } SHAobject; /* When run on a little-endian CPU we need to perform byte reversal on an @@ -448,13 +472,25 @@ static SHAobject * newSHA384object(void) { - return (SHAobject *)PyObject_New(SHAobject, &SHA384type); + SHAobject *retvalue = PyObject_New(SHAobject, &SHA384type); + #ifdef WITH_THREAD + if (retvalue) + retvalue->lock = NULL; + #endif + + return retvalue; } static SHAobject * newSHA512object(void) { - return (SHAobject *)PyObject_New(SHAobject, &SHA512type); + SHAobject *retvalue = PyObject_New(SHAobject, &SHA512type); + #ifdef WITH_THREAD + if (retvalue) + retvalue->lock = NULL; + #endif + + return retvalue; } /* Internal methods for a hash object */ @@ -462,6 +498,10 @@ static void SHA512_dealloc(PyObject *ptr) { + #ifdef WITH_THREAD + if (((SHAobject *)ptr)->lock) + PyThread_free_lock(((SHAobject *)ptr)->lock); + #endif PyObject_Del(ptr); } @@ -483,7 +523,9 @@ return NULL; } + ENTER_SHA512(self); SHAcopy(self, newobj); + LEAVE_SHA512(self); return (PyObject *)newobj; } @@ -495,8 +537,10 @@ { unsigned char digest[SHA_DIGESTSIZE]; SHAobject temp; - + + ENTER_SHA512(self); SHAcopy(self, &temp); + LEAVE_SHA512(self); sha512_final(digest, &temp); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -514,7 +558,9 @@ int i, j; /* Get the raw (binary) digest value */ + ENTER_SHA512(self); SHAcopy(self, &temp); + LEAVE_SHA512(self); sha512_final(digest, &temp); /* Create a new string */ @@ -540,20 +586,61 @@ 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(SHA512_update__doc__, "Update this hash object's state with the provided string."); static PyObject * SHA512_update(SHAobject *self, PyObject *args) { - unsigned char *cp; - int len; + PyObject *obj; + Py_buffer buf; - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; - sha512_update(self, cp, len); + MY_GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + #ifdef WITH_THREAD + if (self->lock == NULL && buf.len >= SHA512_GIL_MINSIZE) + self->lock = PyThread_allocate_lock(); + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS; + PyThread_acquire_lock(self->lock, 1); + sha512_update(self, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS; + } else { + sha512_update(self, buf.buf, buf.len); + } + #else + sha512_update(self, buf.buf, buf.len); + #endif + + PyBuffer_Release(&buf); + Py_INCREF(Py_None); return Py_None; } @@ -680,25 +767,32 @@ { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, &data_obj)) return NULL; - } - if ((new = newSHA512object()) == NULL) + if (data_obj) + MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + + if ((new = newSHA512object()) == NULL) { + if (data_obj) + PyBuffer_Release(&buf); return NULL; - + } sha512_init(new); - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; + if (data_obj) { + if (buf.len > SHA512_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS; + sha512_update(new, buf.buf, buf.len); + Py_END_ALLOW_THREADS; + } else { + sha512_update(new, buf.buf, buf.len); + } + PyBuffer_Release(&buf); } - if (cp) - sha512_update(new, cp, len); return (PyObject *)new; } @@ -711,25 +805,32 @@ { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, &data_obj)) return NULL; - } - if ((new = newSHA384object()) == NULL) + if (data_obj) + MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + + if ((new = newSHA384object()) == NULL) { + if (data_obj) + PyBuffer_Release(&buf); return NULL; - + } sha384_init(new); - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; + if (data_obj) { + if (buf.len > SHA512_GIL_MINSIZE) { + Py_BEGIN_ALLOW_THREADS; + sha512_update(new, buf.buf, buf.len); + Py_END_ALLOW_THREADS; + } else { + sha512_update(new, buf.buf, buf.len); + } + PyBuffer_Release(&buf); } - if (cp) - sha512_update(new, cp, len); return (PyObject *)new; }