diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index c4d9b6968a3..e1e5a28fb71 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -7,6 +7,7 @@ from cStringIO import StringIO import os import subprocess import sys +import threading import bz2 from bz2 import BZ2File, BZ2Compressor, BZ2Decompressor @@ -284,6 +285,23 @@ class BZ2FileTest(BaseTest): bz2f.close() self.assertEqual(xlines, ['Test']) + def testThreading(self): + # Using a BZ2File from several threads doesn't deadlock (issue #7205). + data = "1" * 2**20 + nthreads = 10 + f = bz2.BZ2File(self.filename, 'wb') + try: + def comp(): + for i in range(5): + f.write(data) + threads = [threading.Thread(target=comp) for i in range(nthreads)] + for t in threads: + t.start() + for t in threads: + t.join() + finally: + f.close() + class BZ2CompressorTest(BaseTest): def testCompress(self): diff --git a/Misc/NEWS b/Misc/NEWS index 99eaa6d787e..6f61c49d10a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Core and Builtins Library ------- +- Issue #7205: Fix a possible deadlock when using a BZ2File object from + several threads at once. + - Issue #7048: Force Decimal.logb to round its result when that result is too large to fit in the current precision. diff --git a/Modules/bz2module.c b/Modules/bz2module.c index b5542bf968d..a53d1a50f8d 100644 --- a/Modules/bz2module.c +++ b/Modules/bz2module.c @@ -78,7 +78,12 @@ typedef fpos_t Py_off_t; #ifdef WITH_THREAD -#define ACQUIRE_LOCK(obj) PyThread_acquire_lock(obj->lock, 1) +#define ACQUIRE_LOCK(obj) do { \ + if (!PyThread_acquire_lock(obj->lock, 0)) { \ + Py_BEGIN_ALLOW_THREADS \ + PyThread_acquire_lock(obj->lock, 1); \ + Py_END_ALLOW_THREADS \ + } } while(0) #define RELEASE_LOCK(obj) PyThread_release_lock(obj->lock) #else #define ACQUIRE_LOCK(obj)