natObject.cc (notify): Throw message with IllegalMonitorStateException.

1999-12-22  Bryce McKinlay  <bryce@albatross.co.nz>

        * java/lang/natObject.cc (notify): Throw message with
        IllegalMonitorStateException.
        (notifyAll): Ditto.
        (wait): Ditto.
        * java/lang/Thread.java (isInterrupted): Don't clear interrupt_flag.
        (isInterrupted_): New function, which does clear interrupt_flag.
        (interrupt): Use `isInterrupted_'.
        * java/lang/natThread.cc (interrupt): Add comment.
        (join): Set `Prev' in joiner loop.
        Change various calls to `isInterrupted' to use `isInterrupted_'.
        * posix-threads.cc (_Jv_CondWait): Allways use pthread_cond_timedwait
        on linux. Set result to 0 on an interrupt. Test interrupted status
        of java Thread object directly.
        FLAG_INTERRUPTED: removed.
        (_Jv_ThreadStart): Throw OutOfMemoryError if pthread_create fails.
        (_Jv_ThreadInterrupt): Don't set FLAG_INTERRUPTED.
        (_Jv_InitThreads): Don't block SIGINT.
        (_Jv_ThreadWait): Don't configure SIGINT handler.

From-SVN: r31082
This commit is contained in:
Bryce McKinlay 1999-12-24 01:00:46 +00:00 committed by Bryce McKinlay
parent 07875628ee
commit 43cbc9430d
4 changed files with 108 additions and 64 deletions

View file

@ -1,3 +1,24 @@
1999-12-22 Bryce McKinlay <bryce@albatross.co.nz>
* java/lang/natObject.cc (notify): Throw message with
IllegalMonitorStateException.
(notifyAll): Ditto.
(wait): Ditto.
* java/lang/Thread.java (isInterrupted): Don't clear interrupt_flag.
(isInterrupted_): New function, which does clear interrupt_flag.
(interrupt): Use `isInterrupted_'.
* java/lang/natThread.cc (interrupt): Add comment.
(join): Set `prev' in joiner loop.
Change various calls to `isInterrupted' to use `isInterrupted_'.
* posix-threads.cc (_Jv_CondWait): Allways use pthread_cond_timedwait
on linux. Set result to 0 on an interrupt. Test interrupted status
of java Thread object directly.
FLAG_INTERRUPTED: removed.
(_Jv_ThreadStart): Throw OutOfMemoryError if pthread_create fails.
(_Jv_ThreadInterrupt): Don't set FLAG_INTERRUPTED.
(_Jv_InitThreads): Don't block SIGINT.
(_Jv_ThreadWait): Don't configure SIGINT handler.
1999-12-21 Tom Tromey <tromey@cygnus.com> 1999-12-21 Tom Tromey <tromey@cygnus.com>
* mauve-libgcj: Added java.lang.reflect.Modifier.toString12. * mauve-libgcj: Added java.lang.reflect.Modifier.toString12.

View file

@ -175,7 +175,8 @@ java::lang::Object::notify (void)
sync_init (); sync_init ();
_Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
if (_Jv_CondNotify (&si->condition, &si->mutex)) if (_Jv_CondNotify (&si->condition, &si->mutex))
JvThrow (new IllegalMonitorStateException); JvThrow (new IllegalMonitorStateException(JvNewStringLatin1
("current thread not owner")));
} }
void void
@ -185,7 +186,8 @@ java::lang::Object::notifyAll (void)
sync_init (); sync_init ();
_Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
if (_Jv_CondNotifyAll (&si->condition, &si->mutex)) if (_Jv_CondNotifyAll (&si->condition, &si->mutex))
JvThrow (new IllegalMonitorStateException); JvThrow (new IllegalMonitorStateException(JvNewStringLatin1
("current thread not owner")));
} }
void void
@ -197,7 +199,8 @@ java::lang::Object::wait (jlong timeout, jint nanos)
JvThrow (new IllegalArgumentException); JvThrow (new IllegalArgumentException);
_Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
if (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos)) if (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos))
JvThrow (new IllegalMonitorStateException); JvThrow (new IllegalMonitorStateException(JvNewStringLatin1
("current thread not owner")));
if (Thread::interrupted()) if (Thread::interrupted())
JvThrow (new InterruptedException); JvThrow (new InterruptedException);
} }

View file

@ -130,10 +130,13 @@ java::lang::Thread::interrupt (void)
// another thread to exit. // another thread to exit.
natThread *nt = (natThread *) data; natThread *nt = (natThread *) data;
_Jv_MutexLock (&nt->interrupt_mutex); _Jv_MutexLock (&nt->interrupt_mutex);
// Notify the interrupt condition to interrupt sleep() and join() calls.
_Jv_CondNotify (&nt->interrupt_cond, &nt->interrupt_mutex); _Jv_CondNotify (&nt->interrupt_cond, &nt->interrupt_mutex);
_Jv_MutexUnlock (&nt->interrupt_mutex); // Send a signal to the target thread to interrupt system calls. On Linux,
// this will also interrupt the target thread from *any* _Jv_CondWait call,
// ie wait(). This behaviour is not portable, however.
_Jv_ThreadInterrupt (nt->thread); _Jv_ThreadInterrupt (nt->thread);
_Jv_MutexUnlock (&nt->interrupt_mutex);
} }
void void
@ -145,7 +148,7 @@ java::lang::Thread::join (jlong millis, jint nanos)
_Jv_Throw (new IllegalArgumentException); _Jv_Throw (new IllegalArgumentException);
Thread *current = currentThread (); Thread *current = currentThread ();
if (current->isInterrupted ()) if (current->isInterrupted_ ())
_Jv_Throw (new InterruptedException); _Jv_Throw (new InterruptedException);
// Update the list of all threads waiting for this thread to exit. // Update the list of all threads waiting for this thread to exit.
@ -199,11 +202,12 @@ java::lang::Thread::join (jlong millis, jint nanos)
t->next = 0; t->next = 0;
break; break;
} }
prev = t;
} }
JvAssert (t != NULL); JvAssert (t != NULL);
_Jv_MonitorExit (this); _Jv_MonitorExit (this);
if (current->isInterrupted ()) if (current->isInterrupted_ ())
_Jv_Throw (new InterruptedException); _Jv_Throw (new InterruptedException);
} }
@ -240,7 +244,7 @@ java::lang::Thread::sleep (jlong millis, jint nanos)
++nanos; ++nanos;
Thread *current = currentThread (); Thread *current = currentThread ();
if (current->isInterrupted ()) if (current->isInterrupted_ ())
_Jv_Throw (new InterruptedException); _Jv_Throw (new InterruptedException);
// We use a condition variable to implement sleeping so that an // We use a condition variable to implement sleeping so that an
@ -253,7 +257,7 @@ java::lang::Thread::sleep (jlong millis, jint nanos)
millis, nanos); millis, nanos);
} }
if (current->isInterrupted ()) if (current->isInterrupted_ ())
_Jv_Throw (new InterruptedException); _Jv_Throw (new InterruptedException);
} }

View file

@ -27,11 +27,14 @@ extern "C"
#include <time.h> #include <time.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <gcj/cni.h> #include <gcj/cni.h>
#include <jvm.h> #include <jvm.h>
#include <java/lang/Thread.h> #include <java/lang/Thread.h>
#include <java/lang/System.h> #include <java/lang/System.h>
#include <java/lang/Long.h>
#include <java/lang/OutOfMemoryError.h>
// This is used to implement thread startup. // This is used to implement thread startup.
struct starter struct starter
@ -58,7 +61,7 @@ static int non_daemon_count;
// The signal to use when interrupting a thread. // The signal to use when interrupting a thread.
#ifdef LINUX_THREADS #ifdef LINUX_THREADS
// LinuxThreads usurps both SIGUSR1 and SIGUSR2. // LinuxThreads (prior to glibc 2.1) usurps both SIGUSR1 and SIGUSR2.
# define INTR SIGHUP # define INTR SIGHUP
#else /* LINUX_THREADS */ #else /* LINUX_THREADS */
# define INTR SIGUSR2 # define INTR SIGUSR2
@ -72,8 +75,6 @@ static int non_daemon_count;
#define FLAG_START 0x01 #define FLAG_START 0x01
// Thread is daemon. // Thread is daemon.
#define FLAG_DAEMON 0x02 #define FLAG_DAEMON 0x02
// Thread was interrupted by _Jv_ThreadInterrupt.
#define FLAG_INTERRUPTED 0x04
@ -91,18 +92,44 @@ _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
bool done_sleeping = false; bool done_sleeping = false;
if (millis == 0 && nanos == 0) if (millis == 0 && nanos == 0)
r = pthread_cond_wait (cv, pmu); {
#ifdef LINUX_THREADS
// pthread_cond_timedwait can be interrupted by a signal on linux, while
// pthread_cond_wait can not. So pthread_cond_timedwait() forever.
m = java::lang::Long::MAX_VALUE;
ts.tv_sec = LONG_MAX;
ts.tv_nsec = 0;
#endif
}
else else
{ {
startTime = java::lang::System::currentTimeMillis(); startTime = java::lang::System::currentTimeMillis();
m = millis + startTime; m = millis + startTime;
ts.tv_sec = m / 1000;
ts.tv_nsec = ((m % 1000) * 1000000) + nanos;
}
java::lang::Thread *current = _Jv_ThreadCurrent();
do do
{ {
ts.tv_sec = m / 1000; r = EINTR;
ts.tv_nsec = ((m % 1000) * 1000000) + nanos; // Check to ensure the thread hasn't already been interrupted.
if (!(current->isInterrupted ()))
{
#ifdef LINUX_THREADS
// FIXME: in theory, interrupt() could be called on this thread
// between the test above and the wait below, resulting in the
// interupt() call failing. I don't see a way to fix this
// without significant changes to the implementation.
r = pthread_cond_timedwait (cv, pmu, &ts); r = pthread_cond_timedwait (cv, pmu, &ts);
#else
if (millis == 0 && nanos == 0)
r = pthread_cond_wait (cv, pmu);
else
r = pthread_cond_timedwait (cv, pmu, &ts);
#endif
}
if (r == EINTR) if (r == EINTR)
{ {
@ -110,10 +137,9 @@ _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
because we were interrupted intentionally (i.e. by because we were interrupted intentionally (i.e. by
Thread.interrupt()) or by the GC if it is Thread.interrupt()) or by the GC if it is
signal-based. */ signal-based. */
_Jv_Thread_t *current = _Jv_ThreadCurrentData(); if (current->isInterrupted ())
if (current->flags & FLAG_INTERRUPTED)
{ {
current->flags &= ~(FLAG_INTERRUPTED); r = 0;
done_sleeping = true; done_sleeping = true;
} }
else else
@ -137,7 +163,6 @@ _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
done_sleeping = true; done_sleeping = true;
} }
while (! done_sleeping); while (! done_sleeping);
}
return r != 0; return r != 0;
} }
@ -272,20 +297,12 @@ _Jv_InitThreads (void)
sigemptyset (&act.sa_mask); sigemptyset (&act.sa_mask);
act.sa_flags = 0; act.sa_flags = 0;
sigaction (INTR, &act, NULL); sigaction (INTR, &act, NULL);
// Arrange for SIGINT to be blocked to all threads. It is only
// deliverable to the master thread.
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGINT);
pthread_sigmask (SIG_BLOCK, &mask, NULL);
} }
void void
_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *) _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *)
{ {
_Jv_Thread_t *info = new _Jv_Thread_t; _Jv_Thread_t *info = new _Jv_Thread_t;
info->flags = 0; info->flags = 0;
// FIXME register a finalizer for INFO here. // FIXME register a finalizer for INFO here.
@ -361,20 +378,20 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
} }
else else
data->flags |= FLAG_DAEMON; data->flags |= FLAG_DAEMON;
pthread_create (&data->thread, &attr, really_start, (void *) info); int r = pthread_create (&data->thread, &attr, really_start, (void *) info);
pthread_attr_destroy (&attr); pthread_attr_destroy (&attr);
if (r)
{
const char* msg = "Cannot create additional threads";
JvThrow (new java::lang::OutOfMemoryError (JvNewStringUTF (msg)));
}
} }
void void
_Jv_ThreadWait (void) _Jv_ThreadWait (void)
{ {
// Arrange for SIGINT to be delivered to the master thread.
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGINT);
pthread_sigmask (SIG_UNBLOCK, &mask, NULL);
pthread_mutex_lock (&daemon_mutex); pthread_mutex_lock (&daemon_mutex);
if (non_daemon_count) if (non_daemon_count)
pthread_cond_wait (&daemon_cond, &daemon_mutex); pthread_cond_wait (&daemon_cond, &daemon_mutex);
@ -384,6 +401,5 @@ _Jv_ThreadWait (void)
void void
_Jv_ThreadInterrupt (_Jv_Thread_t *data) _Jv_ThreadInterrupt (_Jv_Thread_t *data)
{ {
data->flags |= FLAG_INTERRUPTED;
pthread_kill (data->thread, INTR); pthread_kill (data->thread, INTR);
} }