PATCH: Various threads fixes

Bryce McKinlay bryce@albatross.co.nz
Mon Nov 29 04:06:00 GMT 1999


I ran some of the threads regression tests out of kaffe on libgcj, and -
lets say - things were broken pretty badly.

Firstly, Thread.interrupt() is implemented by sending a signal to the
thread we want to interrupt. This works fine when the target thread is
blocked on a pthread_cond_timedwait. However, the glibc/linux-threads
documentation states that while signals will interrupt
pthread_cond_timedwait, they do not necessarily interrupt
pthread_cond_wait. This seems to be enforced in glibc 2.1.2 (and
presumably is true on other platforms). As such, interrupt() has no
effect on, say, a thread in wait(). So, instead of calling
pthread_cond_wait, I have changed it to always call
pthread_cond_timedwait, with the end of the world as the timeout
argument.

Secondly, there was a small bug in the join() implementation - 'prev'
wasn't being set in the joiners loop. This meant that if a thread had
multiple threads waiting to join() it, and one of those join operations
was interrupted, the list of joiners (used to signal waiting threads
that the target has finished) would get truncated and some threads
wouldn't be notified.

Thirdly, the semantics of the Thread.isInterrupted() and
Thread.interrupted() methods were a little wrong. The docs state that
interrupted() should clear the thread's interrupted status flag, but
isInterrupted() should not. I fixed this and changed code in
natThread.cc that relied on the old behaviour.

Fourthly, the result code from _Jv_CondWait was not getting zeroed in
the event of the thread being interrupted. This meant that wait() would
throw an IllegialMonitorStateException when it should be throwing an
InterruptedException.

Fifthly, we're using SIGHUP as the interrupt signal on linux. I think
this is a bad idea, as SIGHUP is actually used commonly and expected to
kill the process. I've changed it to use SIGXFSZ instead as this one
seems relatively harmless and is not already used by linuxthreads or
boehm-gc.

I also added some useful error messages to java.lang.Object in order to
match the JDK.

Some other issues:

 - natThread.cc defines a "locker" object to wrap around calls to
_Jv_CondWait to ensure that the mutex lock gets released in the event of
an exception. This is a clever C++ hack, but I don't think it is
necessary, because _Jv_CondWait does NOT throw any exceptions, as far as
I can tell. Callers to that method are required to interpret the result
code from it and throw appropriate exceptions themselves. So can we get
rid of "locker" ?

- Thread.interrupt() may still not be entirely correct - there seems to
be a problem with a thread calling interrupt() on itself and then
entering a synchronized block - the interrupt status gets cleared. See
ThreadInterrupt.java (attached). Also, libgcj allows threads to be
re-start()-ed after they have died. This is incorrect according to
ThreadState.java, but I noticed that the IBM JDK 1.1.8 fails in exactly
the same way. I don't have any actual documentation which says exactly
what should be happening with these (JLS and JDK1.2 online docs dont say
anything useful) - can anyone point me to something?

This patch also includes my earlier patch to get rid of the explicit
SIGINT handling.

regards

  [ bryce ]

1999-11-29  Bryce McKinlay  <bryce@albatross.co.nz>

        * java/lang/natObject.cc (notify): Throw a useful error message
with
        IllegalMonitorStateException, like the JDK does.
        (notifyAll): Ditto.
        (wait): Ditto.
        * posix-threads.cc (_Jv_CondWait): Being interrupted is not an
error
        condition, so set result to 0. Allways use
pthread_cond_timedwait,
        even if we want to wait forever: pthread_cond_wait does not
return
        on signals. Use SIGXFSZ, not SIGHUP, as the interrupt signal for

        Linux-threads.
        * libjava/java/lang/Thread.java (interrupted): Clear
interrupt_flag.
        (isInterrupted): Don't clear interrupt_flag.
        (finish_): Clear interrupt_flag after calling isInterrupted().
        * java/lang/natThread.cc (join): Set `Prev' in joiner loop so
that
        other joiners in the list don't get forgotten. Clear
interrupt_flag
        after calling isInterrupted().

1999-11-25  Bryce McKinlay  <bryce@albatross.co.nz>

        * posix-threads.cc (_Jv_InitThreads): Don't block SIGINT.
        (_Jv_ThreadWait): Don't arrange SIGINT delivery to master
thread.



More information about the Java-patches mailing list