This is the mail archive of the java-patches@sources.redhat.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Multiple threads fixes, nogc fix


These patches fix several long-standing and nasty threads problems:

1. We never detached dead threads. This meant that native thread
resources were leaked, which under linux meant that only ~1020 threads
could ever be created during the lifetime of a java process. Oops ;-)

2. The native thread data for posix threads was allocated using C++
"new" but never released (there were FIXMEs about this problem). My
solution registers a finalizer against the natThread struct rather than
the java Thread object itself, ensuring that the thread data will only
be released after the Thread object is definitely unreachable, after any
user Thread finalizers have run (the natThread struct is stored in an
Object field, so is marked in the regular way via the thread object). I
also removed the LINUX_THREADS conditional code from around the mutex
and condvar destroy calls (thread cleanup isn't time critical and nobody
likes unnecessary #ifdefs).

3. Previously mentioned linuxthreads symbol version/link problems, fixed
by linking the boehm-gc library with -lpthread.

4. In the case of a catastrophic runtime failure, zombie threads would
sometimes get left behind because the GC blocked delivery of
SIGABRT during collections.

Also, nogc.cc didn't build.

regards

  [ bryce ]


Index: configure.in
===================================================================
RCS file: /cvs/gcc/egcs/boehm-gc/configure.in,v
retrieving revision 1.20
diff -u -r1.20 configure.in
--- configure.in	2000/12/12 20:52:54	1.20
+++ configure.in	2000/12/30 10:32:32
@@ -66,7 +66,7 @@
 fi
 
 INCLUDES=
-THREADLIB=
+THREADLIBS=
 case "$THREADS" in
  no | none | single)
     THREADS=none
@@ -86,7 +86,7 @@
 	AC_DEFINE(IRIX_THREADS)
 	;;
     esac
-    THREADLIB=-lpthread
+    THREADLIBS=-lpthread
     ;;
  decosf1 | irix | mach | os2 | solaris | win32 | dce | vxworks)
     AC_MSG_ERROR(thread package $THREADS not yet supported)
@@ -96,7 +96,7 @@
     ;;
 esac
 AC_MSG_RESULT($THREADS)
-AC_SUBST(THREADLIB)
+AC_SUBST(THREADLIBS)
 
 AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
 AC_SUBST(EXTRA_TEST_LIBS)
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/egcs/boehm-gc/Makefile.am,v
retrieving revision 1.17
diff -u -r1.17 Makefile.am
--- Makefile.am	2000/12/12 20:52:54	1.17
+++ Makefile.am	2000/12/30 10:32:32
@@ -32,7 +32,7 @@
 misc.c new_hblk.c obj_map.c os_dep.c pcr_interface.c ptr_chck.c	\
 real_malloc.c reclaim.c solaris_pthreads.c solaris_threads.c \
 solaris_threads.h stubborn.c typd_mlc.c version.h weakpointer.h
-libgcjgc_la_LIBADD = @addobjs@
+libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
 libgcjgc_la_DEPENDENCIES = @addobjs@
 libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir)
 
@@ -45,7 +45,7 @@
 
 check_PROGRAMS = gctest
 gctest_SOURCES = test.c
-gctest_LDADD = ./libgcjgc.la $(THREADLIB) $(EXTRA_TEST_LIBS)
+gctest_LDADD = ./libgcjgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
 
 TESTS = gctest
 
Index: linux_threads.c
===================================================================
RCS file: /cvs/gcc/egcs/boehm-gc/linux_threads.c,v
retrieving revision 1.7
diff -u -r1.7 linux_threads.c
--- linux_threads.c	2000/04/27 00:43:33	1.7
+++ linux_threads.c	2000/12/30 10:32:32
@@ -201,6 +201,7 @@
       if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
       if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
       if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
+      if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed");
 #   endif
     do {
 	    me->signal = 0;
@@ -487,7 +488,8 @@
 #   ifdef NO_SIGNALS
       if (sigdelset(&act.sa_mask, SIGINT) != 0
 	  || sigdelset(&act.sa_mask, SIGQUIT != 0)
-	  || sigdelset(&act.sa_mask, SIGTERM != 0)) {
+	  || sigdelset(&act.sa_mask, SIGTERM != 0)
+	  || sigdelset(&act.sa_mask, SIGABRT != 0)) {
         ABORT("sigdelset() failed");
       }
 #   endif
2000-12-30  Bryce McKinlay  <bryce@albatross.co.nz>

	* Makefile.am (libgcj_la_LIBADD): Add $(THREADLIBS). This ensures that
	the correct versions of various linuxthreads functions get linked.
	* Makefile.in: Rebuilt.
	* java/lang/natThread.cc (finalize_native): New static function. Call
	_Jv_ThreadDestroyData.
	(initialize_native): Register finalizer for "data".
	* include/posix-threads.h (_Jv_ThreadInitData): New simpler prototype.
	(_Jv_ThreadDestroyData): New prototype.
	* include/win32-threads.h: Ditto.
	* include/no-threads.h: Ditto.
	* posix-threads.cc (_Jv_ThreadInitData): Implement new prototype.
	(_Jv_ThreadDestroyData): New function. Free native thread "data" and 
	move mutex and condition variable destroy code from:
	(really_start): ...here.
	(_Jv_ThreadStart): Set PTHREAD_CREATE_DETACHED.
	* win32-threads.cc (_Jv_ThreadInitData): Implement new prototype.
	(_Jv_ThreadDestroyData): Implemented.
	* nogc.cc (_Jv_AllocObject): Use "void *" not "ptr_t".
	(_Jv_AllocArray): Ditto.

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/egcs/libjava/Makefile.am,v
retrieving revision 1.121
diff -u -r1.121 Makefile.am
--- Makefile.am	2000/12/26 00:25:10	1.121
+++ Makefile.am	2000/12/30 11:49:23
@@ -135,8 +135,11 @@
 	$(c_source_files) $(java_source_files) $(built_java_source_files)
 libgcj_la_DEPENDENCIES = libgcj.jar $(javao_files) \
 	$(c_files) $(GCOBJS) $(THREADOBJS) $(LIBLTDL)
+	
+# Include THREADLIBS here to ensure that the correct version of
+# certain linuxthread functions get linked:
 libgcj_la_LIBADD = $(javao_files) $(c_files) $(GCOBJS) \
-	$(THREADOBJS) $(libffi_files) $(LIBLTDL)
+	$(THREADOBJS) $(THREADLIBS) $(libffi_files) $(LIBLTDL)
 libgcj_la_LDFLAGS = -L$(here)/../libstdc++-v3/libsupc++ -lsupc++ \
 	-rpath $(toolexeclibdir) \
 ## The mysterious backslash is consumed by make.
Index: posix-threads.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/posix-threads.cc,v
retrieving revision 1.21
diff -u -r1.21 posix-threads.cc
--- posix-threads.cc	2000/09/30 10:01:04	1.21
+++ posix-threads.cc	2000/12/30 11:49:23
@@ -147,7 +147,7 @@
       else
 	r = pthread_cond_timedwait (&current->wait_cond, &current->wait_mutex, 
 				    &ts);
-				    
+
       // In older glibc's (prior to 2.1.3), the cond_wait functions may 
       // spuriously wake up on a signal. Catch that here.
       if (r != EINTR)
@@ -297,20 +297,25 @@
   sigaction (INTR, &act, NULL);
 }
 
-void
-_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *obj)
+_Jv_Thread_t *
+_Jv_ThreadInitData (java::lang::Thread *obj)
 {
-  _Jv_Thread_t *info = new _Jv_Thread_t;
-  info->flags = 0;
-  info->thread_obj = obj;
+  _Jv_Thread_t *data = new _Jv_Thread_t;
+  data->flags = 0;
+  data->thread_obj = obj;
 
-  pthread_mutex_init (&info->wait_mutex, NULL);
-  pthread_cond_init (&info->wait_cond, NULL);
+  pthread_mutex_init (&data->wait_mutex, NULL);
+  pthread_cond_init (&data->wait_cond, NULL);
 
-  // FIXME register a finalizer for INFO here.
-  // FIXME also must mark INFO somehow.
+  return data;
+}
 
-  *data = info;
+void
+_Jv_ThreadDestroyData (_Jv_Thread_t *data)
+{
+  pthread_mutex_destroy (&data->wait_mutex);
+  pthread_cond_destroy (&data->wait_cond);
+  delete data;
 }
 
 void
@@ -352,12 +357,6 @@
       pthread_mutex_unlock (&daemon_mutex);
     }
   
-#ifndef LINUX_THREADS
-  // Clean up. These calls do nothing on Linux.
-  pthread_mutex_destroy (&info->data->wait_mutex);
-  pthread_cond_destroy (&info->data->wait_cond);
-#endif /* ! LINUX_THREADS */
-
   return NULL;
 }
 
@@ -377,6 +376,7 @@
 
   pthread_attr_init (&attr);
   pthread_attr_setschedparam (&attr, &param);
+  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
 
   // FIXME: handle marking the info object for GC.
   info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
Index: win32-threads.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/win32-threads.cc,v
retrieving revision 1.2
diff -u -r1.2 win32-threads.cc
--- win32-threads.cc	2000/03/28 02:22:23	1.2
+++ win32-threads.cc	2000/12/30 11:49:23
@@ -123,16 +123,19 @@
   non_daemon_count = 0;
 }
 
-void
-_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *)
+_Jv_Thread_t *
+_Jv_ThreadInitData (java::lang::Thread *)
 {
-  _Jv_Thread_t *info = new _Jv_Thread_t;
-  info->flags = 0;
+  _Jv_Thread_t *data = new _Jv_Thread_t;
+  data->flags = 0;
 
-  // FIXME register a finalizer for INFO here.
-  // FIXME also must mark INFO somehow.
+  return data;
+}
 
-  *data = info;
+void
+_Jv_ThreadDestroyData (_Jv_Thread_t *data)
+{
+  delete data;
 }
 
 void
Index: nogc.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/nogc.cc,v
retrieving revision 1.7
diff -u -r1.7 nogc.cc
--- nogc.cc	2000/09/30 09:56:57	1.7
+++ nogc.cc	2000/12/30 11:49:23
@@ -1,4 +1,4 @@
-// nogc.cc - Code to implement no GC.
+// nogc.cc - Implement null garbage collector.
 
 /* Copyright (C) 1998, 1999, 2000  Free Software Foundation
 
@@ -31,7 +31,7 @@
 _Jv_AllocObj (jsize size, jclass klass)
 {
   total += size;
-  ptr_t obj = calloc (size, 1);
+  void *obj = calloc (size, 1);
   *((_Jv_VTable **) obj) = klass->vtable;
   return obj;
 }
@@ -40,7 +40,7 @@
 _Jv_AllocArray (jsize size, jclass klass)
 {
   total += size;
-  ptr_t obj = calloc (size, 1);
+  void *obj = calloc (size, 1);
   *((_Jv_VTable **) obj) = klass->vtable;
   return obj;
 }
Index: java/lang/natThread.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/natThread.cc,v
retrieving revision 1.19
diff -u -r1.19 natThread.cc
--- natThread.cc	2000/06/21 03:55:35	1.19
+++ natThread.cc	2000/12/30 11:49:23
@@ -50,24 +50,37 @@
   JNIEnv *jni_env;
 };
 
+static void finalize_native (jobject ptr);
+
 // This is called from the constructor to initialize the native side
 // of the Thread.
 void
 java::lang::Thread::initialize_native (void)
 {
-  // FIXME: this must interact with the GC in some logical way.  At
-  // the very least we must register a finalizer to clean up.  This
-  // isn't easy to do.  If the Thread object resurrects itself in its
-  // own finalizer then we will need to reinitialize this structure at
-  // any "interesting" point.
   natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
+  
+  // The native thread data is kept in a Object field, not a rawdata, so that
+  // the GC allocator can be used and a finalizer run after the thread becomes
+  // unreachable. Note that this relies on the GC's ability to finalize 
+  // non-Java objects. FIXME?
   data = reinterpret_cast<jobject> (nt);
+  
+  // Register a finalizer to clean up the native thread resources.
+  _Jv_RegisterFinalizer (data, finalize_native);
+
   _Jv_MutexInit (&nt->join_mutex);
   _Jv_CondInit (&nt->join_cond);
-  _Jv_ThreadInitData (&nt->thread, this);
+  nt->thread = _Jv_ThreadInitData (this);
   // FIXME: if JNI_ENV is set we will want to free it.  It is
   // malloc()d.
   nt->jni_env = NULL;
+}
+
+static void
+finalize_native (jobject ptr)
+{
+  natThread *nt = (natThread *) ptr;
+  _Jv_ThreadDestroyData (nt->thread);
 }
 
 jint
Index: include/posix-threads.h
===================================================================
RCS file: /cvs/gcc/egcs/libjava/include/posix-threads.h,v
retrieving revision 1.15
diff -u -r1.15 posix-threads.h
--- posix-threads.h	2000/04/09 06:53:00	1.15
+++ posix-threads.h	2000/12/30 11:49:23
@@ -169,7 +169,8 @@
 
 void _Jv_InitThreads (void);
 
-void _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *thread);
+_Jv_Thread_t *_Jv_ThreadInitData (java::lang::Thread *thread);
+void _Jv_ThreadDestroyData (_Jv_Thread_t *data);
 
 inline java::lang::Thread *
 _Jv_ThreadCurrent (void)
Index: include/win32-threads.h
===================================================================
RCS file: /cvs/gcc/egcs/libjava/include/win32-threads.h,v
retrieving revision 1.2
diff -u -r1.2 win32-threads.h
--- win32-threads.h	2000/03/28 02:22:24	1.2
+++ win32-threads.h	2000/12/30 11:49:23
@@ -97,7 +97,8 @@
 //
 
 void _Jv_InitThreads (void);
-void _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *thread);
+_Jv_Thread_t *_Jv_ThreadInitData (java::lang::Thread *thread);
+void _Jv_ThreadDestroyData (_Jv_Thread_t *data);
 
 inline java::lang::Thread *
 _Jv_ThreadCurrent (void)
Index: include/no-threads.h
===================================================================
RCS file: /cvs/gcc/egcs/libjava/include/no-threads.h,v
retrieving revision 1.4
diff -u -r1.4 no-threads.h
--- no-threads.h	2000/03/07 19:55:25	1.4
+++ no-threads.h	2000/12/30 11:49:23
@@ -102,10 +102,15 @@
 {
 }
 
+inline _Jv_Thread_t *
+_Jv_ThreadInitData (java::lang::Thread *)
+{
+  return NULL;
+}
+
 inline void
-_Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *)
+_Jv_ThreadDestroyData (_Jv_Thread_t *data)
 {
-  *data = NULL;
 }
 
 inline java::lang::Thread *

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]