[Jython-checkins] jython: Fixed bugs corresponding to test_threading skips for Jython, as
jim.baker
jython-checkins at python.org
Tue Apr 15 21:58:56 CEST 2014
http://hg.python.org/jython/rev/b236e2db7a80
changeset: 7204:b236e2db7a80
user: Jim Baker <jim.baker at rackspace.com>
date: Tue Apr 15 13:58:53 2014 -0600
summary:
Fixed bugs corresponding to test_threading skips for Jython, as
well as bug 2125 (missing threading.Thread.daemon attribute).
files:
Lib/test/lock_tests.py | 23 +++-----
Lib/test/test_threading.py | 19 +-----
Lib/threading.py | 27 ++++++++-
src/org/python/modules/_threading/Condition.java | 26 +++++++--
src/org/python/modules/_threading/Lock.java | 4 +-
5 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -149,7 +149,7 @@
Tests for non-recursive, weak locks
(which can be acquired and released from different threads).
"""
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
+ @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,6 +169,7 @@
_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()
@@ -194,7 +195,6 @@
lock.release()
lock.release()
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_release_unacquired(self):
# Cannot release an unacquired lock
lock = self.locktype()
@@ -207,7 +207,6 @@
lock.release()
self.assertRaises(RuntimeError, lock.release)
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_different_thread(self):
# Cannot release from a different thread
lock = self.locktype()
@@ -271,7 +270,6 @@
self.assertEqual(results1, [True] * N)
self.assertEqual(results2, [True] * N)
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_notify(self):
evt = self.eventtype()
self._check_notify(evt)
@@ -280,7 +278,6 @@
evt.clear()
self._check_notify(evt)
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_timeout(self):
evt = self.eventtype()
results1 = []
@@ -294,9 +291,10 @@
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, dt)
+ self.assertTrue(dt >= (0.2 - epsilon), dt)
# The event is set
results1 = []
results2 = []
@@ -312,7 +310,6 @@
Tests for condition variables.
"""
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_acquire(self):
cond = self.condtype()
# Be default we have an RLock: the condition can be acquired multiple
@@ -324,20 +321,18 @@
lock = threading.Lock()
cond = self.condtype(lock)
cond.acquire()
- self.assertFalse(lock.acquire(False))
+ self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive!
cond.release()
self.assertTrue(lock.acquire(False))
- self.assertFalse(cond.acquire(False))
+ self.assertTrue(cond.acquire(False)) # All locks in Jython are recursive!
lock.release()
with cond:
- self.assertFalse(lock.acquire(False))
+ self.assertTrue(lock.acquire(False)) # All locks in Jython are recursive!
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_unacquired_wait(self):
cond = self.condtype()
self.assertRaises(RuntimeError, cond.wait)
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_unacquired_notify(self):
cond = self.condtype()
self.assertRaises(RuntimeError, cond.notify)
@@ -411,7 +406,6 @@
# A second time, to check internal state is still ok.
self._check_notify(cond)
- @unittest.skipIf(support.is_jython, "FIXME: not working properly on Jython")
def test_timeout(self):
cond = self.condtype()
results = []
@@ -425,8 +419,9 @@
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, dt)
+ self.assertTrue(dt >= (0.2 - epsilon), dt)
class BaseSemaphoreTests(BaseTestCase):
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -102,7 +102,6 @@
print 'all tasks done'
self.assertEqual(numrunning.get(), 0)
- @unittest.skipIf(is_jython, "FIXME: not working on Jython")
def test_ident_of_no_threading_threads(self):
# The ident still must work for the main thread and dummy threads.
self.assertFalse(threading.currentThread().ident is None)
@@ -118,7 +117,6 @@
del threading._active[ident[0]]
# run with a small(ish) thread stack size (256kB)
- @unittest.skipIf(is_jython, "FIXME: not working on Jython")
def test_various_ops_small_stack(self):
if verbose:
print 'with 256kB thread stack size...'
@@ -132,7 +130,6 @@
threading.stack_size(0)
# run with a large thread stack size (1MB)
- @unittest.skipIf(is_jython, "FIXME: not working on Jython")
def test_various_ops_large_stack(self):
if verbose:
print 'with 1MB thread stack size...'
@@ -256,7 +253,7 @@
t.join()
# else the thread is still running, and we have no way to kill it
- @unittest.skipIf(is_jython, "FIXME: not working properly on Jython")
+ @unittest.skipIf(is_jython, "Does not apply to Jython")
def test_limbo_cleanup(self):
# Issue 7481: Failure to start thread should cleanup the limbo map.
def fail_new_thread(*args):
@@ -272,7 +269,7 @@
finally:
threading._start_new_thread = _start_new_thread
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
+ @unittest.skipIf(is_jython, "Does not apply to Jython")
def test_finalize_runnning_thread(self):
# Issue 1402: the PyGILState_Ensure / _Release functions may be called
# very late on python exit: on deallocation of a running thread for
@@ -311,7 +308,6 @@
"""])
self.assertEqual(rc, 42)
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
def test_finalize_with_trace(self):
# Issue1733757
# Avoid a deadlock when sys.settrace steps into threading._shutdown
@@ -346,7 +342,6 @@
self.assertTrue(rc == 0,
"Unexpected error: " + repr(stderr))
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
def test_join_nondaemon_on_shutdown(self):
# Issue 1722344
# Raising SystemExit skipped threading._shutdown
@@ -368,8 +363,8 @@
self.addCleanup(p.stdout.close)
self.addCleanup(p.stderr.close)
stdout, stderr = p.communicate()
- self.assertEqual(stdout.strip(),
- "Woke up, sleep function is: <built-in function sleep>")
+ self.assertTrue(stdout.strip().startswith(
+ "Woke up, sleep function is: <java function sleep"))
stderr = re.sub(r"^\[\d+ refs\]", "", stderr, re.MULTILINE).strip()
self.assertEqual(stderr, "")
@@ -676,23 +671,19 @@
class ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called
# multiple times.
- @unittest.skipIf(is_jython, "FIXME: not working properly on Jython")
def test_start_thread_again(self):
thread = threading.Thread()
thread.start()
self.assertRaises(RuntimeError, thread.start)
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
def test_joining_current_thread(self):
current_thread = threading.current_thread()
self.assertRaises(RuntimeError, current_thread.join);
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
def test_joining_inactive_thread(self):
thread = threading.Thread()
self.assertRaises(RuntimeError, thread.join)
- @unittest.skipIf(is_jython, "FIXME: investigate on Jython")
def test_daemonize_active_thread(self):
thread = threading.Thread()
thread.start()
@@ -708,7 +699,6 @@
class EventTests(lock_tests.EventTests):
eventtype = staticmethod(threading.Event)
- at unittest.skipIf(is_jython, "FIXME: investigate on Jython")
class ConditionAsRLockTests(lock_tests.RLockTests):
# An Condition uses an RLock by default and exports its API.
locktype = staticmethod(threading.Condition)
@@ -719,7 +709,6 @@
class SemaphoreTests(lock_tests.SemaphoreTests):
semtype = staticmethod(threading.Semaphore)
- at unittest.skipIf(is_jython, "FIXME: investigate on Jython")
class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests):
semtype = staticmethod(threading.BoundedSemaphore)
diff --git a/Lib/threading.py b/Lib/threading.py
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -1,4 +1,4 @@
-from java.lang import InterruptedException
+from java.lang import IllegalThreadStateException, InterruptedException
from java.util import Collections, WeakHashMap
from java.util.concurrent import Semaphore, CyclicBarrier
from java.util.concurrent.locks import ReentrantLock
@@ -111,12 +111,19 @@
return not self.__eq__(other)
def start(self):
- self._thread.start()
+ try:
+ self._thread.start()
+ except IllegalThreadStateException:
+ raise RuntimeError("threads can only be started once")
def run(self):
self._thread.run()
def join(self, timeout=None):
+ if self._thread == java.lang.Thread.currentThread():
+ raise RuntimeError("cannot join current thread")
+ elif self._thread.getState() == java.lang.Thread.State.NEW:
+ raise RuntimeError("cannot join thread before it is started")
if timeout:
millis = timeout * 1000.
millis_int = int(millis)
@@ -147,7 +154,18 @@
return self._thread.isDaemon()
def setDaemon(self, daemonic):
- self._thread.setDaemon(bool(daemonic))
+ if self._thread.getState() != java.lang.Thread.State.NEW:
+ # thread could in fact be dead... Python uses the same error
+ raise RuntimeError("cannot set daemon status of active thread")
+ try:
+ self._thread.setDaemon(bool(daemonic))
+ except IllegalThreadStateException:
+ # changing daemonization only makes sense in Java when the
+ # thread is alive; need extra test on the exception
+ # because of possible races on interrogating with getState
+ raise RuntimeError("cannot set daemon status of active thread")
+
+ daemon = property(isDaemon, setDaemon)
def __tojava__(self, c):
if isinstance(self._thread, c):
@@ -328,7 +346,8 @@
# After Tim Peters' semaphore class, but not quite the same (no maximum)
def __init__(self, value=1, verbose=None):
- assert value >= 0, "Semaphore initial value must be >= 0"
+ if value < 0:
+ raise ValueError("Semaphore initial value must be >= 0")
_Verbose.__init__(self, verbose)
self.__cond = Condition(Lock())
self.__value = value
diff --git a/src/org/python/modules/_threading/Condition.java b/src/org/python/modules/_threading/Condition.java
--- a/src/org/python/modules/_threading/Condition.java
+++ b/src/org/python/modules/_threading/Condition.java
@@ -87,11 +87,15 @@
@ExposedMethod(defaults = "Py.None")
final void Condition_wait(PyObject timeout) throws InterruptedException {
- if (timeout == Py.None) {
- _condition.await();
- } else {
- long nanos = (long) (timeout.asDouble() * 1e9);
- _condition.awaitNanos(nanos);
+ try {
+ if (timeout == Py.None) {
+ _condition.await();
+ } else {
+ long nanos = (long) (timeout.asDouble() * 1e9);
+ _condition.awaitNanos(nanos);
+ }
+ } catch (IllegalMonitorStateException ex) {
+ throw Py.RuntimeError("cannot wait on un-acquired lock");
}
}
@@ -101,7 +105,11 @@
@ExposedMethod
final void Condition_notify() {
- _condition.signal();
+ try {
+ _condition.signal();
+ } catch (IllegalMonitorStateException ex) {
+ throw Py.RuntimeError("cannot notify on un-acquired lock");
+ }
}
public void notifyAll$() {
@@ -110,7 +118,11 @@
@ExposedMethod
final void Condition_notifyAll() {
- _condition.signalAll();
+ try {
+ _condition.signalAll();
+ } catch (IllegalMonitorStateException ex) {
+ throw Py.RuntimeError("cannot notify on un-acquired lock");
+ }
}
@ExposedMethod
diff --git a/src/org/python/modules/_threading/Lock.java b/src/org/python/modules/_threading/Lock.java
--- a/src/org/python/modules/_threading/Lock.java
+++ b/src/org/python/modules/_threading/Lock.java
@@ -61,8 +61,8 @@
@ExposedMethod
final void Lock_release() {
- if (!_lock.isHeldByCurrentThread()) {
- throw Py.AssertionError("release() of un-acquire()d lock");
+ if (!_lock.isHeldByCurrentThread() || _lock.getHoldCount() <= 0) {
+ throw Py.RuntimeError("cannot release un-acquired lock");
}
_lock.unlock();
}
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list