*.lo
*.a
*.o
+*.aux
+*.ids
+*.idx
+*.log
+*.out
+*.toc
Makefile
Makefile.in
TAGS
tests/regression/resolving/classes1/*.class
tests/regression/resolving/classes2/*.class
tests/regression/resolving/classes3/*.class
+tests/threads/*.class
static bool lock_record_wait(threadobject *thread, lock_record_t *lr, s8 millis, s4 nanos)
{
s4 lockcount;
- bool wasinterrupted;
+ bool wasinterrupted = false;
DEBUGLOCKS(("[lock_record_wait : lr=%p, t=%p, millis=%lld, nanos=%d]",
lr, thread, millis, nanos));
/* wait until notified/interrupted/timed out */
- wasinterrupted = threads_wait_with_timeout_relative(thread, millis, nanos);
+ threads_wait_with_timeout_relative(thread, millis, nanos);
/* re-enter the monitor */
lr->count = lockcount;
+ /* We can only be signaled OR interrupted, not both. If both flags
+ are set, reset only signaled and leave the thread in
+ interrupted state. Otherwise, clear both. */
+
+ if (!thread->signaled) {
+ wasinterrupted = thread->interrupted;
+ thread->interrupted = false;
+ }
+
+ thread->signaled = false;
+
/* return if we have been interrupted */
return wasinterrupted;
waitingthread = w->thread;
- /* If the thread was already signaled but hasn't removed
- itself from the list yet, just ignore it. */
+ /* We must skip threads which have already been notified or
+ interrupted. They will remove themselves from the list. */
- if (waitingthread->signaled == true)
+ if (waitingthread->signaled || waitingthread->interrupted)
continue;
/* Enter the wait-mutex. */
DEBUGLOCKS(("[lock_record_notify: lr=%p, t=%p, waitingthread=%p, sleeping=%d, one=%d]",
lr, t, waitingthread, waitingthread->sleeping, one));
- /* Signal the thread if it's sleeping. */
+ /* Signal the thread if it's sleeping. sleeping can be false
+ when the waiting thread is blocked between giving up the
+ monitor and entering the waitmutex. It will eventually
+ observe that it's signaled and refrain from going to
+ sleep. */
if (waitingthread->sleeping)
pthread_cond_signal(&(waitingthread->waitcond));
If both tv_sec and tv_nsec are zero, this function
waits for an unlimited amount of time.
- RETURN VALUE:
- true.........if the wait has been interrupted,
- false........if the wait was ended by notification or timeout
-
*******************************************************************************/
-static bool threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
+static void threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
{
- bool wasinterrupted;
-
/* acquire the waitmutex */
pthread_mutex_lock(&t->waitmutex);
}
}
- /* check if we were interrupted */
-
- wasinterrupted = t->interrupted;
-
- /* reset all flags */
-
- t->interrupted = false;
- t->signaled = false;
t->sleeping = false;
/* release the waitmutex */
pthread_mutex_unlock(&t->waitmutex);
-
- return wasinterrupted;
}
millis.......milliseconds to wait
nanos........nanoseconds to wait
- RETURN VALUE:
- true.........if the wait has been interrupted,
- false........if the wait was ended by notification or timeout
-
*******************************************************************************/
-bool threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
+void threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
s4 nanos)
{
struct timespec wakeupTime;
/* wait */
- return threads_wait_with_timeout(thread, &wakeupTime);
+ threads_wait_with_timeout(thread, &wakeupTime);
}
thread = THREADOBJECT;
+ pthread_mutex_lock(&thread->waitmutex);
+
/* get interrupted flag */
intr = thread->interrupted;
thread->interrupted = false;
+ pthread_mutex_unlock(&thread->waitmutex);
+
return intr;
}
threads_calc_absolute_time(&wakeupTime, millis, nanos);
- wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime);
+ threads_wait_with_timeout(thread, &wakeupTime);
+
+ wasinterrupted = threads_check_if_interrupted_and_reset();
if (wasinterrupted)
exceptions_throw_interruptedexception();
void threads_sleep(s8 millis, s4 nanos);
-bool threads_wait_with_timeout_relative(threadobject *t, s8 millis, s4 nanos);
+void threads_wait_with_timeout_relative(threadobject *t, s8 millis, s4 nanos);
void threads_thread_interrupt(threadobject *thread);
bool threads_check_if_interrupted_and_reset(void);
+++ /dev/null
-public class threadInterrupt {
- public static class firstthread implements Runnable {
- private threadInterrupt s;
-
- public firstthread(threadInterrupt s_) {
- s = s_;
- }
- public void run() {
- try {
- synchronized (s.o1) {
- System.out.println("first thread!");
- Thread.sleep(500);
- System.out.println("interrupting");
- s.t2.interrupt();
- System.out.println("leaving");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public static class secondthread implements Runnable {
- private threadInterrupt s;
-
- public secondthread(threadInterrupt s_) {
- s = s_;
- }
- public void run() {
- try {
- Thread.sleep(250);
- synchronized (s.o1) {
- System.out.println("second thread!");
- s.o1.wait();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public Object o1 = new Object();
- public Thread t1 = null;
- public Thread t2 = null;
-
- public static void main(String args[]) {
- System.out.println("should exit with java.lang.InterruptedException");
- threadInterrupt s = new threadInterrupt();
- firstthread r1 = new firstthread(s);
- secondthread r2 = new secondthread(s);
-
- s.t1 = new Thread(r1, "a");
- s.t2 = new Thread(r2, "b");
- s.t1.start();
- s.t2.start();
- }
-}
-
-/*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: java
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
--- /dev/null
+public class threadInterrupt {
+ public static class firstthread implements Runnable {
+ private threadInterrupt s;
+
+ public firstthread(threadInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ try {
+ synchronized (s.o1) {
+ System.out.println("first thread!");
+ Thread.sleep(500);
+ System.out.println("interrupting");
+ s.t2.interrupt();
+ System.out.println("leaving");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class secondthread implements Runnable {
+ private threadInterrupt s;
+
+ public secondthread(threadInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ try {
+ Thread.sleep(250);
+ synchronized (s.o1) {
+ System.out.println("second thread!");
+ s.o1.wait();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public Object o1 = new Object();
+ public Thread t1 = null;
+ public Thread t2 = null;
+
+ public static void main(String args[]) {
+ System.out.println("should exit with java.lang.InterruptedException");
+ threadInterrupt s = new threadInterrupt();
+ firstthread r1 = new firstthread(s);
+ secondthread r2 = new secondthread(s);
+
+ s.t1 = new Thread(r1, "a");
+ s.t2 = new Thread(r2, "b");
+ s.t1.start();
+ s.t2.start();
+ }
+}
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: java
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
--- /dev/null
+// This test grew a bit more elaborate than anticipated...
+// It verifies that the JVM handles properly the case of a thread being
+// interrupted and notified at the same time.
+
+public class waitAndInterrupt {
+ private class semaphore {
+ private int v;
+ public semaphore(int v) {
+ this.v = v;
+ }
+ public synchronized void semwait() {
+ while (v == 0)
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ v--;
+ }
+ public synchronized void sempost() {
+ if (v == 0)
+ notify();
+ v++;
+ }
+ }
+
+ public static class firstthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public firstthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ boolean iAmFirst = Thread.currentThread() == s.t1;
+ try {
+ int i = 0;
+ int count_not = 0;
+ int count_int = 0;
+ for (;;) {
+ if (iAmFirst) {
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running, notified " + Integer.toString(count_not) + ", interrupted " + Integer.toString(count_int));
+ }
+ synchronized (s) {
+ s.sem1.sempost();
+ try {
+ while (!s.notified)
+ s.wait();
+ try {
+ s.wait();
+ } catch (InterruptedException e) {
+ s.notify(); // wake t2
+ }
+ count_not++;
+ } catch (InterruptedException e) {
+ count_int++;
+ }
+ }
+
+ s.sem5.sempost();
+ s.sem8.semwait();
+ } else {
+ s.sem1.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ s.sem2.sempost();
+ try {
+ while (!s.notified)
+ s.wait();
+ s.notified = false;
+ count_not++;
+ } catch (InterruptedException e) {
+ count_int++;
+ }
+ }
+
+ s.sem6.sempost();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class otherthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public otherthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ boolean iAmFirst = Thread.currentThread() == s.t3;
+ try {
+ int i = 0;
+ for (;;) {
+ if (iAmFirst) {
+ s.sem3.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ s.sem4.sempost();
+ }
+ s.t1.interrupt();
+ s.sem5.semwait();
+ } else {
+ s.sem4.semwait();
+ if (++i == 100) {
+ i = 0;
+ System.out.println(Thread.currentThread().getName() + " still running");
+ }
+ synchronized (s) {
+ if (s.notified)
+ System.out.println("shouldn't happen (1)");
+ s.notified = true;
+ s.notify();
+ }
+ s.sem6.semwait();
+ }
+ s.sem7.sempost();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class controlthread implements Runnable {
+ private waitAndInterrupt s;
+
+ public controlthread(waitAndInterrupt s_) {
+ s = s_;
+ }
+ public void run() {
+ try {
+ for (;;) {
+ s.sem2.semwait();
+ synchronized (s) {
+ }
+ s.sem3.sempost();
+ s.sem7.semwait();
+ s.sem7.semwait();
+ s.sem8.sempost(); // wake first
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public Thread t1 = null;
+ public Thread t2 = null;
+ public Thread t3 = null;
+ public Thread t4 = null;
+ public semaphore sem1 = new semaphore(0);
+ public semaphore sem2 = new semaphore(0);
+ public semaphore sem3 = new semaphore(0);
+ public semaphore sem4 = new semaphore(0);
+ public semaphore sem5 = new semaphore(0);
+ public semaphore sem6 = new semaphore(0);
+ public semaphore sem7 = new semaphore(0);
+ public semaphore sem8 = new semaphore(0);
+ public boolean notified = false;
+
+ public static void main(String args[]) {
+ waitAndInterrupt s = new waitAndInterrupt();
+ firstthread r1 = new firstthread(s);
+ firstthread r2 = new firstthread(s);
+ otherthread r3 = new otherthread(s);
+ controlthread r5 = new controlthread(s);
+
+ s.t1 = new Thread(r1, "a");
+ s.t2 = new Thread(r2, "b");
+ s.t3 = new Thread(r3, "c");
+ s.t4 = new Thread(r3, "d");
+ Thread t5 = new Thread(r5, "e");
+ s.t1.start();
+ s.t2.start();
+ s.t3.start();
+ s.t4.start();
+ t5.start();
+ }
+}
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: java
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */