diff -r 41d761a58a53 Lib/test/lock_tests.py --- a/Lib/test/lock_tests.py Tue Apr 14 10:18:50 2015 -0400 +++ b/Lib/test/lock_tests.py Tue Apr 14 14:27:23 2015 -0400 @@ -149,7 +149,6 @@ Tests for non-recursive, weak locks (which can be acquired and released from different threads). """ - @unittest.skipIf(support.is_jython, "Jython only supports recursive locks") def test_reacquire(self): # Lock needs to be released before re-acquiring. lock = self.locktype() @@ -169,7 +168,6 @@ _wait() self.assertEqual(len(phase), 2) - @unittest.skipIf(support.is_jython, "Java does not allow locks to be released from different threads") def test_different_thread(self): # Lock can be released from a different thread. lock = self.locktype() @@ -291,10 +289,9 @@ results2.append((r, t2 - t1)) Bunch(f, N).wait_for_finished() self.assertEqual(results1, [False] * N) - epsilon = 1e-5 # wait time is hard to test precisely, so keep low resolution for r, dt in results2: self.assertFalse(r) - self.assertTrue(dt >= (0.2 - epsilon), dt) + self.assertTrue(dt >= 0.2, dt) # The event is set results1 = [] results2 = [] @@ -321,13 +318,13 @@ lock = threading.Lock() cond = self.condtype(lock) cond.acquire() - self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(lock.acquire(False)) cond.release() self.assertTrue(lock.acquire(False)) - self.assertTrue(cond.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(cond.acquire(False)) lock.release() with cond: - self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive! + self.assertFalse(lock.acquire(False)) def test_unacquired_wait(self): cond = self.condtype() @@ -355,17 +352,9 @@ b.wait_for_started() _wait() self.assertEqual(results1, []) - # FIXME: notify(n) is not currently implemented in Jython, trying - # repeated notifies instead. (and honestly w/o understanding what - # notify(n) really even means for CPython...). - # Notify 3 threads at first cond.acquire() - ###cond.notify(3) - cond.notify() - cond.notify() - cond.notify() - + cond.notify(3) _wait() phase_num = 1 cond.release() @@ -375,12 +364,7 @@ self.assertEqual(results2, []) # Notify 5 threads: they might be in their first or second wait cond.acquire() - ###cond.notify(5) - cond.notify() - cond.notify() - cond.notify() - cond.notify() - cond.notify() + cond.notify(5) _wait() phase_num = 2 cond.release() @@ -419,9 +403,8 @@ results.append(t2 - t1) Bunch(f, N).wait_for_finished() self.assertEqual(len(results), 5) - epsilon = 1e-5 # wait time is hard to test precisely, so keep low resolution for dt in results: - self.assertTrue(dt >= (0.2 - epsilon), dt) + self.assertTrue(dt >= 0.2, dt) class BaseSemaphoreTests(BaseTestCase): diff -r 41d761a58a53 src/org/python/modules/_threading/Lock.java --- a/src/org/python/modules/_threading/Lock.java Tue Apr 14 10:18:50 2015 -0400 +++ b/src/org/python/modules/_threading/Lock.java Tue Apr 14 14:27:23 2015 -0400 @@ -1,8 +1,7 @@ package org.python.modules._threading; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.Semaphore; import org.python.core.ContextManager; -import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyNewWrapper; import org.python.core.PyObject; @@ -18,27 +17,28 @@ public class Lock extends PyObject implements ContextManager { public static final PyType TYPE = PyType.fromClass(Lock.class); - final ReentrantLock _lock; + // see http://bugs.jython.org/issue2328 - need to support another thread + // releasing this lock, per CPython semantics, so support semantics with + // Semaphore(1), not a ReentrantLock + final Semaphore _lock; public Lock() { - _lock = new ReentrantLock(); + _lock = new Semaphore(1); } @ExposedNew final static PyObject Lock___new__ (PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { - final int nargs = args.length; return new Lock(); } - @ExposedMethod(defaults = "true") final boolean Lock_acquire(boolean blocking) { if (blocking) { - _lock.lock(); + _lock.acquireUninterruptibly(); return true; } else { - return _lock.tryLock(); + return _lock.tryAcquire(); } } @@ -52,21 +52,18 @@ @ExposedMethod final PyObject Lock___enter__() { - _lock.lock(); + _lock.acquireUninterruptibly(); return this; } public PyObject __enter__(ThreadState ts) { - _lock.lock(); + _lock.acquireUninterruptibly(); return this; } @ExposedMethod final void Lock_release() { - if (!_lock.isHeldByCurrentThread() || _lock.getHoldCount() <= 0) { - throw Py.RuntimeError("cannot release un-acquired lock"); - } - _lock.unlock(); + _lock.release(); } public void release() { @@ -75,30 +72,22 @@ @ExposedMethod final boolean Lock___exit__(PyObject type, PyObject value, PyObject traceback) { - _lock.unlock(); + _lock.release(); return false; } public boolean __exit__(ThreadState ts, PyException exception) { - _lock.unlock(); + _lock.release(); return false; } @ExposedMethod final boolean Lock_locked() { - return _lock.isLocked(); + return _lock.availablePermits() == 0; } public boolean locked() { return Lock_locked(); } - @ExposedMethod - final boolean Lock__is_owned() { - return _lock.isHeldByCurrentThread(); - } - - public boolean _is_owned() { - return Lock__is_owned(); - } } diff -r 41d761a58a53 src/org/python/modules/_threading/_threading.java --- a/src/org/python/modules/_threading/_threading.java Tue Apr 14 10:18:50 2015 -0400 +++ b/src/org/python/modules/_threading/_threading.java Tue Apr 14 14:27:23 2015 -0400 @@ -10,9 +10,9 @@ public static void classDictInit(PyObject dict) { dict.__setitem__("__name__", Py.newString("_threading")); dict.__setitem__("Lock", Lock.TYPE); - dict.__setitem__("RLock", Lock.TYPE); + dict.__setitem__("RLock", RLock.TYPE); dict.__setitem__("_Lock", Lock.TYPE); - dict.__setitem__("_RLock", Lock.TYPE); + dict.__setitem__("_RLock", RLock.TYPE); dict.__setitem__("Condition", Condition.TYPE); // Hide from Python