[Python-checkins] CVS: python/dist/src/Modules zlibmodule.c,2.40,2.41

Martin v. L?wis loewis@users.sourceforge.net
Fri, 07 Sep 2001 09:27:34 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv19848

Modified Files:
	zlibmodule.c 
Log Message:
Patch #450702: allow threads when calling into zlib, protect usage of
the module in multiple threads with a global lock.


Index: zlibmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/zlibmodule.c,v
retrieving revision 2.40
retrieving revision 2.41
diff -C2 -d -r2.40 -r2.41
*** zlibmodule.c	2001/02/22 15:52:55	2.40
--- zlibmodule.c	2001/09/07 16:27:31	2.41
***************
*** 8,11 ****
--- 8,59 ----
  #include "zlib.h"
  
+ #ifdef WITH_THREAD
+ #include "pythread.h"
+ 
+ /* #defs ripped off from _tkinter.c, even though the situation here is much
+    simpler, because we don't have to worry about waiting for Tcl
+    events!  And, since zlib itself is threadsafe, we don't need to worry
+    about re-entering zlib functions.
+ 
+    What we _do_ have to worry about is releasing the global lock _in
+    general_ in the zlibmodule functions, because of all the calls to
+    Python functions, which assume that the global lock is held.  So
+    only two types of calls are wrapped in Py_BEGIN/END_ALLOW_THREADS:
+    those that grab the zlib lock, and those that involve other
+    time-consuming functions where we need to worry about holding up
+    other Python threads.
+ 
+    We don't need to worry about the string inputs being modified out
+    from underneath us, because string objects are immutable.  However,
+    we do need to make sure we take on ownership, so that the strings
+    are not deleted out from under us during a thread swap.
+ 
+    N.B.
+ 
+    Since ENTER_ZLIB and LEAVE_ZLIB only need to be called on functions
+    that modify the components of preexisting de/compress objects, it
+    could prove to be a performance gain on multiprocessor machines if
+    there was an de/compress object-specific lock.  However, for the
+    moment the ENTER_ZLIB and LEAVE_ZLIB calls are global for ALL
+    de/compress objects.
+ 
+  */
+ 
+ static PyThread_type_lock zlib_lock = NULL; /* initialized on module load */
+ 
+ #define ENTER_ZLIB \
+        { Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(zlib_lock, 1); \
+          Py_END_ALLOW_THREADS
+ 
+ #define LEAVE_ZLIB \
+        PyThread_release_lock(zlib_lock); }
+ 
+ #else
+ 
+ #define ENTER_ZLIB
+ #define LEAVE_ZLIB
+ 
+ #endif
+ 
  /* The following parameters are copied from zutil.h, version 0.95 */
  #define DEFLATED   8
***************
*** 66,77 ****
  PyZlib_compress(PyObject *self, PyObject *args)
  {
!   PyObject *ReturnVal;
    Byte *input, *output;
    int length, level=Z_DEFAULT_COMPRESSION, err;
    z_stream zst;
    
!   if (!PyArg_ParseTuple(args, "s#|i:compress", &input, &length, &level))
      return NULL;
    zst.avail_out = length + length/1000 + 12 + 1;
    output=(Byte*)malloc(zst.avail_out);
    if (output==NULL) 
--- 114,134 ----
  PyZlib_compress(PyObject *self, PyObject *args)
  {
!   PyObject *ReturnVal = NULL;
    Byte *input, *output;
    int length, level=Z_DEFAULT_COMPRESSION, err;
    z_stream zst;
+   int return_error;
+   PyObject * inputString;
    
!   /* require Python string object, optional 'level' arg */
!   if (!PyArg_ParseTuple(args, "S|i:compress", &inputString, &level))
!     return NULL;
! 
!   /* now get a pointer to the internal string */
!   if (PyString_AsStringAndSize(inputString, &input, &length) == -1)
      return NULL;
+ 
    zst.avail_out = length + length/1000 + 12 + 1;
+ 
    output=(Byte*)malloc(zst.avail_out);
    if (output==NULL) 
***************
*** 79,85 ****
--- 136,149 ----
        PyErr_SetString(PyExc_MemoryError,
                        "Can't allocate memory to compress data");
+       free(output);
+ 
        return NULL;
      }
  
+   /* Past the point of no return.  From here on out, we need to make sure
+      we clean up mallocs & INCREFs. */
+ 
+   Py_INCREF(inputString);	/* increment so that we hold ref */
+ 
    zst.zalloc=(alloc_func)NULL;
    zst.zfree=(free_func)Z_NULL;
***************
*** 88,91 ****
--- 152,157 ----
    zst.avail_in=length;
    err=deflateInit(&zst, level);
+ 
+   return_error = 0;
    switch(err) 
      {
***************
*** 95,105 ****
        PyErr_SetString(PyExc_MemoryError,
                        "Out of memory while compressing data");
!       free(output);
!       return NULL;
      case(Z_STREAM_ERROR):
        PyErr_SetString(ZlibError,
                        "Bad compression level");
!       free(output);
!       return NULL;
      default:
        {
--- 161,171 ----
        PyErr_SetString(PyExc_MemoryError,
                        "Out of memory while compressing data");
!       return_error = 1;
!       break;
      case(Z_STREAM_ERROR):
        PyErr_SetString(ZlibError,
                        "Bad compression level");
!       return_error = 1;
!       break;
      default:
        {
***************
*** 111,153 ****
  			 err, zst.msg);  
          deflateEnd(&zst);
!         free(output);
!         return NULL;
        }
      }
!  
!   err=deflate(&zst, Z_FINISH);
!   switch(err)
!   {
!     case(Z_STREAM_END):
!       break;
!       /* Are there other errors to be trapped here? */
!     default: 
!     {
! 	if (zst.msg == Z_NULL)
  	    PyErr_Format(ZlibError, "Error %i while compressing data",
  			 err); 
! 	else
  	    PyErr_Format(ZlibError, "Error %i while compressing data: %.200s",
  			 err, zst.msg);  
! 	deflateEnd(&zst);
! 	free(output);
! 	return NULL;
      }
    }
!   err=deflateEnd(&zst);
!   if (err!=Z_OK) 
!   {
!       if (zst.msg == Z_NULL)
! 	  PyErr_Format(ZlibError, "Error %i while finishing compression",
! 		       err); 
!       else
! 	  PyErr_Format(ZlibError,
! 		       "Error %i while finishing compression: %.200s",
! 		       err, zst.msg);  
!       free(output);
!       return NULL;
!     }
!   ReturnVal=PyString_FromStringAndSize((char *)output, zst.total_out);
    free(output);
    return ReturnVal;
  }
--- 177,231 ----
  			 err, zst.msg);  
          deflateEnd(&zst);
! 	return_error = 1;
        }
      }
! 
!   if (!return_error) {
!     Py_BEGIN_ALLOW_THREADS
!     err=deflate(&zst, Z_FINISH);
!     Py_END_ALLOW_THREADS
! 
!     switch(err)
!       {
!       case(Z_STREAM_END):
! 	break;
! 	/* Are there other errors to be trapped here? */
!       default: 
! 	{
! 	  if (zst.msg == Z_NULL)
  	    PyErr_Format(ZlibError, "Error %i while compressing data",
  			 err); 
! 	  else
  	    PyErr_Format(ZlibError, "Error %i while compressing data: %.200s",
  			 err, zst.msg);  
! 
! 	  deflateEnd(&zst);
! 
! 	  return_error = 1;
! 	}
!       }
!     
!     if (!return_error) {
!       err=deflateEnd(&zst);
!       if (err == Z_OK)
! 	ReturnVal = PyString_FromStringAndSize((char *)output, zst.total_out);
!       else {
! 	{
! 	  if (zst.msg == Z_NULL)
! 	    PyErr_Format(ZlibError, "Error %i while finishing compression",
! 			 err); 
! 	  else
! 	    PyErr_Format(ZlibError,
! 			 "Error %i while finishing compression: %.200s",
! 			 err, zst.msg);  
! 	}
!       }
! 
      }
    }
! 
    free(output);
+   Py_DECREF(inputString);
+ 
    return ReturnVal;
  }
***************
*** 167,171 ****
    int wsize=DEF_WBITS, r_strlen=DEFAULTALLOC;
    z_stream zst;
!   if (!PyArg_ParseTuple(args, "s#|ii:decompress", &input, &length, &wsize, &r_strlen))
      return NULL;
  
--- 245,254 ----
    int wsize=DEF_WBITS, r_strlen=DEFAULTALLOC;
    z_stream zst;
!   int return_error;
!   PyObject * inputString;
! 
!   if (!PyArg_ParseTuple(args, "S|ii:decompress", &inputString, &wsize, &r_strlen))
!     return NULL;
!   if (PyString_AsStringAndSize(inputString, &input, &length) == -1)
      return NULL;
  
***************
*** 175,178 ****
--- 258,262 ----
    zst.avail_in=length;
    zst.avail_out=r_strlen;
+ 
    if (!(result_str = PyString_FromStringAndSize(NULL, r_strlen)))
    {
***************
*** 181,184 ****
--- 265,274 ----
        return NULL;
    }
+ 
+   /* Past the point of no return.  From here on out, we need to make sure
+      we clean up mallocs & INCREFs. */
+ 
+   Py_INCREF(inputString);	/* increment so that we hold ref */
+ 
    zst.zalloc=(alloc_func)NULL;
    zst.zfree=(free_func)Z_NULL;
***************
*** 186,189 ****
--- 276,281 ----
    zst.next_in =(Byte *)input;
    err=inflateInit2(&zst, wsize);
+ 
+   return_error = 0;
    switch(err)
      {
***************
*** 193,198 ****
        PyErr_SetString(PyExc_MemoryError,
                        "Out of memory while decompressing data");
!       Py_DECREF(result_str);
!       return NULL;
      default:
        {
--- 285,289 ----
        PyErr_SetString(PyExc_MemoryError,
                        "Out of memory while decompressing data");
!       return_error = 1;
      default:
        {
***************
*** 205,215 ****
  			 err, zst.msg);  
          inflateEnd(&zst);
! 	Py_DECREF(result_str);
!         return NULL;
        }
      }
    do 
      {
        err=inflate(&zst, Z_FINISH);
        switch(err) 
          {
--- 296,313 ----
  			 err, zst.msg);  
          inflateEnd(&zst);
! 
! 	return_error = 1;
        }
      }
+ 
    do 
      {
+       if (return_error)
+ 	break;
+ 
+       Py_BEGIN_ALLOW_THREADS
        err=inflate(&zst, Z_FINISH);
+       Py_END_ALLOW_THREADS
+ 
        switch(err) 
          {
***************
*** 227,232 ****
                             err);
                inflateEnd(&zst);
!               Py_DECREF(result_str);
!               return NULL;
              }
  	    /* fall through */
--- 325,330 ----
                             err);
                inflateEnd(&zst);
! 	      return_error = 1;
! 	      break;
              }
  	    /* fall through */
***************
*** 238,242 ****
                                "Out of memory while decompressing data");
                inflateEnd(&zst);
!               return NULL;
              }
  	    zst.next_out = (unsigned char *)PyString_AsString(result_str) + r_strlen;
--- 336,341 ----
                                "Out of memory while decompressing data");
                inflateEnd(&zst);
! 	      result_str = NULL;
! 	      return_error = 1;
              }
  	    zst.next_out = (unsigned char *)PyString_AsString(result_str) + r_strlen;
***************
*** 254,278 ****
  			       err, zst.msg);  
              inflateEnd(&zst);
! 	    Py_DECREF(result_str);
!             return NULL;
            }
          }
      } while(err!=Z_STREAM_END);
!   
!   err=inflateEnd(&zst);
!   if (err!=Z_OK) 
!   {
!       if (zst.msg == Z_NULL)
  	  PyErr_Format(ZlibError,
  		       "Error %i while finishing data decompression",
  		       err); 
!       else
  	  PyErr_Format(ZlibError,
  		       "Error %i while finishing data decompression: %.200s",
  		       err, zst.msg);  
!       Py_DECREF(result_str);
        return NULL;
      }
!   _PyString_Resize(&result_str, zst.total_out);
    return result_str;
  }
--- 353,386 ----
  			       err, zst.msg);  
              inflateEnd(&zst);
! 	    return_error = 1;
            }
          }
      } while(err!=Z_STREAM_END);
! 
!   if (!return_error) {
!     err=inflateEnd(&zst);
!     if (err!=Z_OK) 
!       {
! 	if (zst.msg == Z_NULL)
  	  PyErr_Format(ZlibError,
  		       "Error %i while finishing data decompression",
  		       err); 
! 	else
  	  PyErr_Format(ZlibError,
  		       "Error %i while finishing data decompression: %.200s",
  		       err, zst.msg);  
! 	
! 	return_error = 1;
        return NULL;
      }
!   }
! 
!   if (!return_error)
!     _PyString_Resize(&result_str, zst.total_out);
!   else {
!     Py_XDECREF(result_str);	/* sets result_str == NULL, if not already */
!   }
!   Py_DECREF(inputString);
! 
    return result_str;
  }
***************
*** 373,380 ****
--- 481,492 ----
  Comp_dealloc(compobject *self)
  {
+     ENTER_ZLIB
+ 
      if (self->is_initialised)
        deflateEnd(&self->zst);
      Py_XDECREF(self->unused_data);
      PyObject_Del(self);
+ 
+     LEAVE_ZLIB
  }
  
***************
*** 382,389 ****
--- 494,505 ----
  Decomp_dealloc(compobject *self)
  {
+     ENTER_ZLIB
+ 
      if (self->is_initialised)
        inflateEnd(&self->zst);
      Py_XDECREF(self->unused_data);
      PyObject_Del(self);
+ 
+     LEAVE_ZLIB
  }
  
***************
*** 403,409 ****
    Byte *input;
    unsigned long start_total_out;
    
!   if (!PyArg_ParseTuple(args, "s#:compress", &input, &inplen))
      return NULL;
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
--- 519,530 ----
    Byte *input;
    unsigned long start_total_out;
+   int return_error;
+   PyObject * inputString;
    
!   if (!PyArg_ParseTuple(args, "S:compress", &inputString))
      return NULL;
+   if (PyString_AsStringAndSize(inputString, &input, &inplen) == -1)
+     return NULL;
+ 
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
***************
*** 411,414 ****
--- 532,540 ----
      return NULL;
    }
+ 
+   ENTER_ZLIB
+ 
+   Py_INCREF(inputString);
+   
    start_total_out = self->zst.total_out;
    self->zst.avail_in = inplen;
***************
*** 416,420 ****
--- 542,552 ----
    self->zst.avail_out = length;
    self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
+ 
+   Py_BEGIN_ALLOW_THREADS
    err = deflate(&(self->zst), Z_NO_FLUSH);
+   Py_END_ALLOW_THREADS
+ 
+   return_error = 0;
+ 
    /* while Z_OK and the output buffer is full, there might be more output,
      so extend the output buffer and try again */
***************
*** 423,446 ****
        PyErr_SetString(PyExc_MemoryError,
  		      "Can't allocate memory to compress data");
!       return NULL;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
      err = deflate(&(self->zst), Z_NO_FLUSH);
    }
    /* We will only get Z_BUF_ERROR if the output buffer was full but there 
      wasn't more output when we tried again, so it is not an error condition */
!   if (err != Z_OK && err != Z_BUF_ERROR) {
!     if (self->zst.msg == Z_NULL)
!       PyErr_Format(ZlibError, "Error %i while compressing",
! 		   err); 
!     else
!       PyErr_Format(ZlibError, "Error %i while compressing: %.200s",
! 		   err, self->zst.msg);  
!     Py_DECREF(RetVal);
!     return NULL;
    }
!   _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
    return RetVal;
  }
--- 555,595 ----
        PyErr_SetString(PyExc_MemoryError,
  		      "Can't allocate memory to compress data");
!       return_error = 1;
!       break;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
+     
+     Py_BEGIN_ALLOW_THREADS
      err = deflate(&(self->zst), Z_NO_FLUSH);
+     Py_END_ALLOW_THREADS
    }
    /* We will only get Z_BUF_ERROR if the output buffer was full but there 
      wasn't more output when we tried again, so it is not an error condition */
! 
!   if (!return_error) {
!     if (err != Z_OK && err != Z_BUF_ERROR) {
!       if (self->zst.msg == Z_NULL)
! 	PyErr_Format(ZlibError, "Error %i while compressing",
! 		     err); 
!       else
! 	PyErr_Format(ZlibError, "Error %i while compressing: %.200s",
! 		     err, self->zst.msg);  
! 
!       return_error = 1;
!       Py_DECREF(RetVal);
!     }
    }
! 
!   if (return_error)
!     RetVal = NULL;		/* should have been handled by DECREF */
!   else
!     _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
! 
!   Py_DECREF(inputString);
! 
!   LEAVE_ZLIB
! 
    return RetVal;
  }
***************
*** 460,466 ****
    Byte *input;
    unsigned long start_total_out;
  
!   if (!PyArg_ParseTuple(args, "s#:decompress", &input, &inplen))
      return NULL;
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
--- 609,620 ----
    Byte *input;
    unsigned long start_total_out;
+   int return_error;
+   PyObject * inputString;
  
!   if (!PyArg_ParseTuple(args, "S:decompress", &inputString))
!     return NULL;
!   if (PyString_AsStringAndSize(inputString, &input, &inplen) == -1)
      return NULL;
+ 
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
***************
*** 468,471 ****
--- 622,631 ----
      return NULL;
    }
+ 
+   ENTER_ZLIB
+   return_error = 0;
+ 
+   Py_INCREF(inputString);
+ 
    start_total_out = self->zst.total_out;
    self->zst.avail_in = inplen;
***************
*** 473,477 ****
--- 633,641 ----
    self->zst.avail_out = length;
    self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
+ 
+   Py_BEGIN_ALLOW_THREADS
    err = inflate(&(self->zst), Z_SYNC_FLUSH);
+   Py_END_ALLOW_THREADS
+ 
    /* while Z_OK and the output buffer is full, there might be more output,
      so extend the output buffer and try again */
***************
*** 480,517 ****
        PyErr_SetString(PyExc_MemoryError,
                        "Can't allocate memory to compress data");
!       return NULL;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
      err = inflate(&(self->zst), Z_SYNC_FLUSH);
    }
    /* The end of the compressed data has been reached, so set the unused_data 
      attribute to a string containing the remainder of the data in the string. 
      Note that this is also a logical place to call inflateEnd, but the old
      behaviour of only calling it on flush() is preserved.*/
!   if (err == Z_STREAM_END) {
!     Py_XDECREF(self->unused_data);  /* Free the original, empty string */
!     self->unused_data = PyString_FromStringAndSize((char *)self->zst.next_in,
  						   self->zst.avail_in);
!     if (self->unused_data == NULL) {
!       PyErr_SetString(PyExc_MemoryError,
!                       "Can't allocate memory to unused_data");
        Py_DECREF(RetVal);
!       return NULL;
      }
-   /* We will only get Z_BUF_ERROR if the output buffer was full but there 
-     wasn't more output when we tried again, so it is not an error condition */
-   } else if (err != Z_OK && err != Z_BUF_ERROR) {
-     if (self->zst.msg == Z_NULL)
-       PyErr_Format(ZlibError, "Error %i while decompressing",
- 		   err); 
-     else
-       PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
- 		   err, self->zst.msg);  
-     Py_DECREF(RetVal);
-     return NULL;
    }
!   _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
    return RetVal;
  }
--- 644,698 ----
        PyErr_SetString(PyExc_MemoryError,
                        "Can't allocate memory to compress data");
!       return_error = 1;
!       break;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
+     Py_BEGIN_ALLOW_THREADS
      err = inflate(&(self->zst), Z_SYNC_FLUSH);
+     Py_END_ALLOW_THREADS
    }
+ 
    /* The end of the compressed data has been reached, so set the unused_data 
      attribute to a string containing the remainder of the data in the string. 
      Note that this is also a logical place to call inflateEnd, but the old
      behaviour of only calling it on flush() is preserved.*/
!   if (!return_error) {
!     if (err == Z_STREAM_END) {
!       Py_XDECREF(self->unused_data);  /* Free the original, empty string */
!       self->unused_data = PyString_FromStringAndSize((char *)self->zst.next_in,
  						   self->zst.avail_in);
!       if (self->unused_data == NULL) {
! 	PyErr_SetString(PyExc_MemoryError,
! 			"Can't allocate memory to unused_data");
! 	Py_DECREF(RetVal);
! 	return_error = 1;
!     }
!       /* We will only get Z_BUF_ERROR if the output buffer was full but there 
! 	 wasn't more output when we tried again, so it is not an error
! 	 condition */
!     } else if (err != Z_OK && err != Z_BUF_ERROR) {
!       if (self->zst.msg == Z_NULL)
! 	PyErr_Format(ZlibError, "Error %i while decompressing",
! 		     err); 
!       else
! 	PyErr_Format(ZlibError, "Error %i while decompressing: %.200s",
! 		     err, self->zst.msg);  
        Py_DECREF(RetVal);
!       return_error = 1;
      }
    }
! 
!   if (!return_error) {
!     _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
!   }
!   else
!     RetVal = NULL;		/* should be handled by DECREF */
! 
!   Py_DECREF(inputString);
! 
!   LEAVE_ZLIB
! 
    return RetVal;
  }
***************
*** 532,535 ****
--- 713,717 ----
    int flushmode = Z_FINISH;
    unsigned long start_total_out;
+   int return_error;
  
    if (!PyArg_ParseTuple(args, "|i:flush", &flushmode))
***************
*** 541,545 ****
      return PyString_FromStringAndSize(NULL, 0);
    }
!   
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
--- 723,727 ----
      return PyString_FromStringAndSize(NULL, 0);
    }
! 
    if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
      PyErr_SetString(PyExc_MemoryError,
***************
*** 547,555 ****
--- 729,746 ----
      return NULL;
    }
+ 
+   ENTER_ZLIB
+   
    start_total_out = self->zst.total_out;
    self->zst.avail_in = 0;
    self->zst.avail_out = length;
    self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
+ 
+   Py_BEGIN_ALLOW_THREADS
    err = deflate(&(self->zst), flushmode);
+   Py_END_ALLOW_THREADS
+ 
+   return_error = 0;
+ 
    /* while Z_OK and the output buffer is full, there might be more output,
      so extend the output buffer and try again */
***************
*** 558,597 ****
        PyErr_SetString(PyExc_MemoryError,
  		      "Can't allocate memory to compress data");
!       return NULL;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
      err = deflate(&(self->zst), flushmode);
    }
    /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free
      various data structures. Note we should only get Z_STREAM_END when 
      flushmode is Z_FINISH, but checking both for safety*/
!   if (err == Z_STREAM_END && flushmode == Z_FINISH) {
!     err=deflateEnd(&(self->zst));
!     if (err!=Z_OK) {
        if (self->zst.msg == Z_NULL)
! 	PyErr_Format(ZlibError, "Error %i from deflateEnd()",
  		     err); 
        else
!  	PyErr_Format(ZlibError,"Error %i from deflateEnd(): %.200s",
  		     err, self->zst.msg);  
        Py_DECREF(RetVal);
!       return NULL;
      }
-     self->is_initialised = 0;
-   /* We will only get Z_BUF_ERROR if the output buffer was full but there 
-     wasn't more output when we tried again, so it is not an error condition */
-   } else if (err!=Z_OK && err!=Z_BUF_ERROR) {
-     if (self->zst.msg == Z_NULL)
-       PyErr_Format(ZlibError, "Error %i while flushing",
- 		   err); 
-     else
-       PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
- 		   err, self->zst.msg);  
-     Py_DECREF(RetVal);
-     return NULL;
    }
!   _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
    return RetVal;
  }
--- 749,806 ----
        PyErr_SetString(PyExc_MemoryError,
  		      "Can't allocate memory to compress data");
!       return_error = 1;
!       break;
      }
      self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length;
      self->zst.avail_out = length;
      length = length << 1;
+ 
+     Py_BEGIN_ALLOW_THREADS
      err = deflate(&(self->zst), flushmode);
+     Py_END_ALLOW_THREADS
    }
+ 
    /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free
      various data structures. Note we should only get Z_STREAM_END when 
      flushmode is Z_FINISH, but checking both for safety*/
!   if (!return_error) {
!     if (err == Z_STREAM_END && flushmode == Z_FINISH) {
!       err=deflateEnd(&(self->zst));
!       if (err!=Z_OK) {
! 	if (self->zst.msg == Z_NULL)
! 	  PyErr_Format(ZlibError, "Error %i from deflateEnd()",
! 		       err); 
! 	else
! 	  PyErr_Format(ZlibError,"Error %i from deflateEnd(): %.200s",
! 		       err, self->zst.msg);  
! 
! 	Py_DECREF(RetVal);
! 	return_error = 1;
!       }
!       else
! 	self->is_initialised = 0;
! 
!       /* We will only get Z_BUF_ERROR if the output buffer was full but there 
! 	 wasn't more output when we tried again, so it is not an error
! 	 condition */
!     } else if (err!=Z_OK && err!=Z_BUF_ERROR) {
        if (self->zst.msg == Z_NULL)
! 	PyErr_Format(ZlibError, "Error %i while flushing",
  		     err); 
        else
! 	PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
  		     err, self->zst.msg);  
        Py_DECREF(RetVal);
!       return_error = 1;
      }
    }
! 
!   if (!return_error)
!     _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
!   else
!     RetVal = NULL;		/* should have been handled by DECREF */
!     
!   LEAVE_ZLIB
! 
    return RetVal;
  }
***************
*** 610,616 ****
--- 819,829 ----
  {
    int err;
+   PyObject * retval;
    
    if (!PyArg_ParseTuple(args, ""))
      return NULL;
+ 
+   ENTER_ZLIB
+ 
    err=inflateEnd(&(self->zst));
    if (err!=Z_OK) {
***************
*** 621,628 ****
        PyErr_Format(ZlibError, "Error %i from inflateEnd(): %.200s",
  		   err, self->zst.msg);  
!     return NULL;
    }
!   self->is_initialised = 0;
!   return PyString_FromStringAndSize(NULL, 0);
  }
  
--- 834,848 ----
        PyErr_Format(ZlibError, "Error %i from inflateEnd(): %.200s",
  		   err, self->zst.msg);  
! 
!     retval = NULL;
! 
!   } else {
!     self->is_initialised = 0;
!     retval = PyString_FromStringAndSize(NULL, 0);
    }
! 
!   LEAVE_ZLIB
! 
!   return retval;
  }
  
***************
*** 648,652 ****
  Comp_getattr(compobject *self, char *name)
  {
!         return Py_FindMethod(comp_methods, (PyObject *)self, name);
  }
  
--- 868,875 ----
  Comp_getattr(compobject *self, char *name)
  {
!   /* No ENTER/LEAVE_ZLIB is necessary because this fn doesn't touch
!      internal data. */
! 
!   return Py_FindMethod(comp_methods, (PyObject *)self, name);
  }
  
***************
*** 654,663 ****
  Decomp_getattr(compobject *self, char *name)
  {
          if (strcmp(name, "unused_data") == 0) 
  	  {  
  	    Py_INCREF(self->unused_data);
! 	    return self->unused_data;
  	  }
!         return Py_FindMethod(Decomp_methods, (PyObject *)self, name);
  }
  
--- 877,895 ----
  Decomp_getattr(compobject *self, char *name)
  {
+         PyObject * retval;
+ 
+         ENTER_ZLIB
+ 
          if (strcmp(name, "unused_data") == 0) 
  	  {  
  	    Py_INCREF(self->unused_data);
!             retval = self->unused_data;
  	  }
! 	else 
! 	  retval = Py_FindMethod(Decomp_methods, (PyObject *)self, name);
! 
!         LEAVE_ZLIB
! 
!         return retval;
  }
  
***************
*** 826,828 ****
--- 1058,1064 ----
                  Py_DECREF(ver);
          }
+ 
+ #ifdef WITH_THREAD
+ 	zlib_lock = PyThread_allocate_lock();
+ #endif // WITH_THREAD
  }