This is the mail archive of the java-patches@gcc.gnu.org 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]

java invocation api checked in


I checked in the initial implementation of the invocation api,
for both cni and jni.  (Into the trunk only.)  The cni version
has not been tested - someone please do!  Also, someone please
verify that I didn't break the win32 version.

2001-05-21  Per Bothner  <per@bothner.com>

	Implement invocation interface; don't create new thread for main.
	* java/lang/Thread.java (gen_name):  Make native.
	(<init>(Thread,THreadGroup,Runnable,String)):  New private
	constructor, used by other constructors, and _Jv_AttachCurrentThread.
	* java/lang/natThread.cc (gen_name):  New implementation.
	(_Jv_AttachCurrentThread, _Jv_DetachCurrentThread):  New.
	* prims.cc (main_init):  Removed, replaced by _Jv_CreateJavaVM.
	(_Jv_CreateJavaVM):  New runtime initialization procedure.
	(runFirst):  New proecdure - mostly code from old FirstThread::run.
	(JvRunMain, _Jv_RunMain):  Re-write to use new invocation code.
	* gcj/cni.h (JvCreateJavaVM, JvAttachCurrentThread,
	JvDetachCurrentThread):  New inline wrappers.
	* gcj/javaprims.h (_Jv_CreateJavaVM, _Jv_AttachCurrentThread,
	_Jv_DetachCurrentThread):  New declarations.
	* gnu/gcj/runtime/FirstThread.java:  Gutted.  Now contains only ...
	(getMain): new static method.
	* gnu/gcj/runtime/natFirstThread.cc:  Removed;  run method replaced
	by runFirst in prims.cc.
	(java/lang/Thread.h):  Update for new invocation interface.
	* include/posix-threads.h (_Jv_ThreadRegister,
	_Jv_ThreadUnRegister):  New declarations.
	* posix-threads.cc (_Jv_ThreadRegister, _Jv_ThreadUnRegister):  New.
	(really_start):  Use new _Jv_ThreadRegister.
	* include/no-threads.h (_Jv_ThreadInitData):  No longer inline.
	(_Jv_ThreadRegister, _Jv_ThreadUnRegister):  New empty inlines.
	* no-threads.cc (_Jv_ThreadInitData):  Set _Jv_OnlyThread here.
	Complain of called when _Jv_OnlyThread already set.
	(_Jv_ThreadStart):  Always JvFail.
	* include/win32-threads.h  (_Jv_Thread_t):  New thread_obj field.
	(_Jv_ThreadRegister, _Jv_ThreadUnRegister):  New declarations.
	* win32-threads.cc (struct starter):  Remove objet field -
	we use _Jv_Thread_t's new thread_obj field instead.
	(_Jv_ThreadInitData):  Set _Jv_Thread_t's thread_obj field.
	(_Jv_ThreadRegister, _Jv_ThreadUnRegister):  New.
	(really_start):  Use new _Jv_ThreadRegister.
	* jni.cc (_Jv_JNI_AttachCurrentThread):  Use _Jv_AttachCurrentThread.
	(_Jv_JNI_DetachCurrentThread):  Use _Jv_DetachCurrentThread.
	* gnu/gcj/jni/NativeThread.java, gnu/gcj/jni/natNativeThread.cc:
	Removed - no longer needed with new invocation interface.
	* Makefile.am:  Update for removed/added files.

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.146
diff -u -p -r1.146 Makefile.am
--- Makefile.am	2001/05/22 06:40:06	1.146
+++ Makefile.am	2001/05/22 06:43:26
@@ -303,12 +303,12 @@ gnu/gcj/runtime/FirstThread.h: gnu/gcj/r
 java/lang/Thread.h: java/lang/Thread.class libgcj.jar
 	$(GCJH) -classpath $(top_builddir) \
 		-prepend 'class _Jv_JNIEnv;' \
-		-prepend 'extern "Java" { namespace gnu { namespace gcj { namespace jni { class NativeThread; } } } };' \
 		-prepend '#define _JV_NOT_OWNER 1' \
 		-prepend '#define _JV_INTERRUPTED 2' \
 		-friend '_Jv_JNIEnv * _Jv_GetCurrentJNIEnv ();' \
 		-friend 'void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env);' \
-		-friend 'class gnu::gcj::jni::NativeThread;' \
+		-friend 'java::lang::Thread* _Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group);' \
+		-friend 'jint _Jv_DetachCurrentThread ();' \
 		$(basename $<)
 
 java/lang/String.h: java/lang/String.class libgcj.jar
@@ -1008,7 +1008,6 @@ gnu/gcj/RawData.java \
 gnu/gcj/io/DefaultMimeTypes.java \
 gnu/gcj/io/MimeTypes.java \
 gnu/gcj/io/SimpleSHSStream.java	\
-gnu/gcj/jni/NativeThread.java \
 gnu/gcj/math/MPN.java \
 gnu/gcj/protocol/file/Connection.java \
 gnu/gcj/protocol/file/Handler.java \
@@ -1308,8 +1307,6 @@ gnu/gcj/convert/natOutput_EUCJIS.cc \
 gnu/gcj/convert/natOutput_SJIS.cc \
 gnu/gcj/io/natSimpleSHSStream.cc \
 gnu/gcj/io/shs.cc \
-gnu/gcj/jni/natNativeThread.cc \
-gnu/gcj/runtime/natFirstThread.cc \
 java/io/natFile.cc \
 java/io/natFileDescriptor.cc \
 java/io/natObjectInputStream.cc \
Index: jni.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni.cc,v
retrieving revision 1.44
diff -u -p -r1.44 jni.cc
--- jni.cc	2001/05/03 16:56:38	1.44
+++ jni.cc	2001/05/22 06:43:28
@@ -40,12 +40,13 @@ details.  */
 #include <java/util/Hashtable.h>
 #include <java/lang/Integer.h>
 #include <java/lang/ThreadGroup.h>
-#include <gnu/gcj/jni/NativeThread.h>
+#include <java/lang/Thread.h>
 
 #include <gcj/method.h>
 #include <gcj/field.h>
 
 #include <java-interp.h>
+#include <java-threads.h>
 
 // FIXME: remove these defines.
 #define ClassClass java::lang::Class::class$
@@ -53,7 +54,6 @@ details.  */
 #define ThrowableClass java::lang::Throwable::class$
 #define MethodClass java::lang::reflect::Method::class$
 #define ThreadGroupClass java::lang::ThreadGroup::class$
-#define NativeThreadClass gnu::gcj::jni::NativeThread::class$
 
 // This enum is used to select different template instantiations in
 // the invocation code.
@@ -1862,7 +1862,7 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, j
     {
       try
 	{
-	  (void) new gnu::gcj::jni::NativeThread (group, name);
+	  _Jv_AttachCurrentThread (name, group);
 	}
       catch (jthrowable t)
 	{
@@ -1916,28 +1916,11 @@ _Jv_JNI_DestroyJavaVM (JavaVM *vm)
   return JNI_ERR;
 }
 
-static jint
+jint
 _Jv_JNI_DetachCurrentThread (JavaVM *)
 {
-  java::lang::Thread *t = _Jv_ThreadCurrent ();
-  if (t == NULL)
-    return JNI_EDETACHED;
-
-  // FIXME: we only allow threads attached via AttachCurrentThread to
-  // be detached.  I have no idea how we could implement detaching
-  // other threads, given the requirement that we must release all the
-  // monitors.  That just seems evil.
-  JvAssert ((&NativeThreadClass)->isInstance (t));
-
-  // FIXME: release the monitors.  We'll take this to mean all
-  // monitors acquired via the JNI interface.  This means we have to
-  // keep track of them.
-
-  gnu::gcj::jni::NativeThread *nt
-    = reinterpret_cast<gnu::gcj::jni::NativeThread *> (t);
-  nt->finish ();
-
-  return 0;
+  jint code = _Jv_DetachCurrentThread ();
+  return code  ? JNI_EDETACHED : 0;
 }
 
 static jint
Index: no-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/no-threads.cc,v
retrieving revision 1.5
diff -u -p -r1.5 no-threads.cc
--- no-threads.cc	2000/03/07 19:55:24	1.5
+++ no-threads.cc	2001/05/22 06:43:28
@@ -16,14 +16,20 @@ details.  */
 
 java::lang::Thread *_Jv_OnlyThread = NULL;
 
-void
-_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *,
-		 _Jv_ThreadStartFunc *meth)
+_Jv_Thread_t *
+_Jv_ThreadInitData (java::lang::Thread * thread)
 {
   // Don't use JvAssert, since we want this to fail even when compiled
   // without assertions.
   if (_Jv_OnlyThread)
     JvFail ("only thread already running");
   _Jv_OnlyThread = thread;
-  (*meth) (thread);
+  return NULL;
+}
+
+void
+_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *,
+		 _Jv_ThreadStartFunc *meth)
+{
+  JvFail ("Thread.start called but threads not available");
 }
Index: posix-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/posix-threads.cc,v
retrieving revision 1.25
diff -u -p -r1.25 posix-threads.cc
--- posix-threads.cc	2001/05/21 08:37:04	1.25
+++ posix-threads.cc	2001/05/22 06:43:28
@@ -326,6 +326,25 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *dat
     }
 }
 
+void
+_Jv_ThreadRegister (_Jv_Thread_t *data)
+{
+  pthread_setspecific (_Jv_ThreadKey, data->thread_obj);
+  pthread_setspecific (_Jv_ThreadDataKey, data);
+
+  // glibc 2.1.3 doesn't set the value of `thread' until after start_routine
+  // is called. Since it may need to be accessed from the new thread, work 
+  // around the potential race here by explicitly setting it again.
+  data->thread = pthread_self ();
+}
+
+void
+_Jv_ThreadUnRegister ()
+{
+  pthread_setspecific (_Jv_ThreadKey, NULL);
+  pthread_setspecific (_Jv_ThreadDataKey, NULL);
+}
+
 // This function is called when a thread is started.  We don't arrange
 // to call the `run' method directly, because this function must
 // return a value.
@@ -333,14 +352,8 @@ static void *
 really_start (void *x)
 {
   struct starter *info = (struct starter *) x;
-
-  pthread_setspecific (_Jv_ThreadKey, info->data->thread_obj);
-  pthread_setspecific (_Jv_ThreadDataKey, info->data);
 
-  // glibc 2.1.3 doesn't set the value of `thread' until after start_routine
-  // is called. Since it may need to be accessed from the new thread, work 
-  // around the potential race here by explicitly setting it again.
-  info->data->thread = pthread_self ();
+  _Jv_ThreadRegister (info->data);
 
   info->method (info->data->thread_obj);
   
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.50
diff -u -p -r1.50 prims.cc
--- prims.cc	2001/04/28 00:04:55	1.50
+++ prims.cc	2001/05/22 06:43:29
@@ -36,6 +36,7 @@ details.  */
 
 #ifdef ENABLE_JVMPI
 #include <jvmpi.h>
+#include <java/lang/ThreadGroup.h>
 #endif
 
 #ifndef DISABLE_GETENV_PROPERTIES
@@ -62,6 +63,7 @@ details.  */
 #include <java/lang/System.h>
 #include <java/lang/reflect/Modifier.h>
 #include <java/io/PrintStream.h>
+#include <java/lang/UnsatisfiedLinkError.h>
 
 #ifdef USE_LTDL
 #include <ltdl.h>
@@ -74,8 +76,10 @@ static java::lang::OutOfMemoryError *no_
 // Largest representable size_t.
 #define SIZE_T_MAX ((size_t) (~ (size_t) 0))
 
+static const char *no_properties[] = { NULL };
+
 // Properties set at compile time.
-const char **_Jv_Compiler_Properties;
+const char **_Jv_Compiler_Properties = no_properties;
 
 // The JAR file to add to the beginning of java.class.path.
 const char *_Jv_Jar_Class_Path;
@@ -92,6 +96,8 @@ static char * _Jv_execName;
 const char **_Jv_argv;
 int _Jv_argc;
 
+typedef void main_func (jobject);
+
 #ifdef ENABLE_JVMPI
 // Pointer to JVMPI notification functions.
 void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
@@ -640,51 +646,15 @@ win32_exception_handler (LPEXCEPTION_POI
 
 #endif
 
-static void
-main_init ()
+/* This will be non-NULL if the user has preloaded a JNI library, or
+   linked one into the executable.  */
+extern "C" 
 {
-  // Turn stack trace generation off while creating exception objects.
-  _Jv_InitClass (&java::lang::Throwable::class$);
-  java::lang::Throwable::trace_enabled = 0;
-  
-  INIT_SEGV;
-#ifdef HANDLE_FPE
-  INIT_FPE;
-#else
-  arithexception = new java::lang::ArithmeticException
-    (JvNewStringLatin1 ("/ by zero"));
-#endif
-
-  no_memory = new java::lang::OutOfMemoryError;
-
-  java::lang::Throwable::trace_enabled = 1;
-
-#ifdef USE_LTDL
-  LTDL_SET_PRELOADED_SYMBOLS ();
-#endif
-
-#ifdef USE_WINSOCK
-  // Initialise winsock for networking
-  WSADATA data;
-  if (WSAStartup (MAKEWORD (1, 1), &data))
-      MessageBox (NULL, "Error initialising winsock library.", "Error", MB_OK | MB_ICONEXCLAMATION);
-#endif /* USE_WINSOCK */
-
-#ifdef USE_WIN32_SIGNALLING
-  // Install exception handler
-  SetUnhandledExceptionFilter (win32_exception_handler);
-#else
-  // We only want this on POSIX systems.
-  struct sigaction act;
-  act.sa_handler = SIG_IGN;
-  sigemptyset (&act.sa_mask);
-  act.sa_flags = 0;
-  sigaction (SIGPIPE, &act, NULL);
-#endif /* USE_WIN32_SIGNALLING */
-
-  _Jv_JNI_Init ();
+#pragma weak JNI_OnLoad
+  extern jint JNI_OnLoad (JavaVM *, void *) __attribute__((weak));
 }
 
+
 #ifndef DISABLE_GETENV_PROPERTIES
 
 static char *
@@ -828,15 +798,162 @@ process_gcj_properties ()
 }
 #endif // DISABLE_GETENV_PROPERTIES
 
-void
-JvRunMain (jclass klass, int argc, const char **argv)
+jint
+_Jv_CreateJavaVM (void* /*vm_args*/)
 {
   PROCESS_GCJ_PROPERTIES;
 
+  // Turn stack trace generation off while creating exception objects.
+  _Jv_InitClass (&java::lang::Throwable::class$);
+  java::lang::Throwable::trace_enabled = 0;
+  
+  INIT_SEGV;
+#ifdef HANDLE_FPE
+  INIT_FPE;
+#else
+  arithexception = new java::lang::ArithmeticException
+    (JvNewStringLatin1 ("/ by zero"));
+#endif
+
+  no_memory = new java::lang::OutOfMemoryError;
+
+  java::lang::Throwable::trace_enabled = 1;
+
+#ifdef USE_LTDL
+  LTDL_SET_PRELOADED_SYMBOLS ();
+#endif
+
+#ifdef USE_WINSOCK
+  // Initialise winsock for networking
+  WSADATA data;
+  if (WSAStartup (MAKEWORD (1, 1), &data))
+      MessageBox (NULL, "Error initialising winsock library.", "Error", MB_OK | MB_ICONEXCLAMATION);
+#endif /* USE_WINSOCK */
+
+#ifdef USE_WIN32_SIGNALLING
+  // Install exception handler
+  SetUnhandledExceptionFilter (win32_exception_handler);
+#else
+  // We only want this on POSIX systems.
+  struct sigaction act;
+  act.sa_handler = SIG_IGN;
+  sigemptyset (&act.sa_mask);
+  act.sa_flags = 0;
+  sigaction (SIGPIPE, &act, NULL);
+#endif /* USE_WIN32_SIGNALLING */
+
+  _Jv_JNI_Init ();
+
+  /* Some systems let you preload shared libraries before running a
+     program.  Under Linux, this is done by setting the LD_PRELOAD
+     environment variable.  We take advatage of this here to allow for
+     dynamically loading a JNI library into a fully linked executable.  */
+
+  if (JNI_OnLoad != NULL)
+    {
+      JavaVM *vm = _Jv_GetJavaVM ();
+      if (vm == NULL)
+	{
+	  // FIXME: what?
+	  return -1;
+	}
+      jint vers = JNI_OnLoad (vm, NULL);
+      if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2)
+	{
+	  // FIXME: unload the library.
+	  _Jv_Throw (new java::lang::UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from preloaded JNI_OnLoad")));
+	}
+    }
+  return 0;
+}
+
+static void
+runFirst (::java::lang::Class *klass, ::java::lang::Object *args)
+{
+  Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22);
+  Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4);
+
+  _Jv_Method *meth = _Jv_GetMethodLocal (klass, main_name, main_signature);
+
+  // Some checks from Java Spec section 12.1.4.
+  const char *msg = NULL;
+  if (meth == NULL)
+    msg = "no suitable method `main' in class";
+  else if (! java::lang::reflect::Modifier::isStatic(meth->accflags))
+    msg = "`main' must be static";
+  else if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
+    msg =  "`main' must be public";
+  if (msg != NULL)
+    {
+      fprintf (stderr, "%s\n", msg);
+      ::exit(1);
+    }
+
+#ifdef WITH_JVMPI
+  if (_Jv_JVMPI_Notify_THREAD_START)
+    {
+      JVMPI_Event event;
+
+      jstring thread_name = getName ();
+      jstring group_name = NULL, parent_name = NULL;
+      java::lang::ThreadGroup *group = getThreadGroup ();
+
+      if (group)
+	{
+	  group_name = group->getName ();
+	  group = group->getParent ();
+
+	  if (group)
+	    parent_name = group->getName ();
+	}
+
+      int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
+      int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
+      int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
+
+      char thread_chars[thread_len + 1];
+      char group_chars[group_len + 1];
+      char parent_chars[parent_len + 1];
+
+      if (thread_name)
+	JvGetStringUTFRegion (thread_name, 0, 
+			      thread_name->length(), thread_chars);
+      if (group_name)
+	JvGetStringUTFRegion (group_name, 0, 
+			      group_name->length(), group_chars);
+      if (parent_name)
+	JvGetStringUTFRegion (parent_name, 0, 
+			      parent_name->length(), parent_chars);
+
+      thread_chars[thread_len] = '\0';
+      group_chars[group_len] = '\0';
+      parent_chars[parent_len] = '\0';
+
+      event.event_type = JVMPI_EVENT_THREAD_START;
+      event.env_id = NULL;
+      event.u.thread_start.thread_name = thread_chars;
+      event.u.thread_start.group_name = group_chars;
+      event.u.thread_start.parent_name = parent_chars;
+      event.u.thread_start.thread_id = (jobjectID) this;
+      event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
+
+      _Jv_DisableGC ();
+      (*_Jv_JVMPI_Notify_THREAD_START) (&event);
+      _Jv_EnableGC ();
+    }
+#endif
+
+  main_func *real_main = (main_func *) meth->ncode;
+  (*real_main) (args);
+}
+
+void
+JvRunMain (jclass klass, int argc, const char **argv)
+{
   _Jv_argv = argv;
   _Jv_argc = argc;
 
-  main_init ();
+  _Jv_CreateJavaVM (NULL);
 #ifdef HAVE_PROC_SELF_EXE
   char exec_name[20];
   sprintf (exec_name, "/proc/%d/exe", getpid ());
@@ -845,10 +962,9 @@ JvRunMain (jclass klass, int argc, const
   _Jv_ThisExecutable (argv[0]);
 #endif
 
+  main_thread = _Jv_AttachCurrentThread (JvNewStringLatin1 ("main"), NULL);
   arg_vec = JvConvertArgv (argc - 1, argv + 1);
-  main_thread = new gnu::gcj::runtime::FirstThread (klass, arg_vec);
-
-  main_thread->start();
+  runFirst (klass, arg_vec);
   _Jv_ThreadWait ();
 
   int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
@@ -860,9 +976,8 @@ void
 _Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar)
 {
   jstring class_name;
-  PROCESS_GCJ_PROPERTIES;
 
-  main_init ();
+  _Jv_CreateJavaVM (NULL);
 
 #ifdef HAVE_PROC_SELF_EXE
   char exec_name[20];
@@ -870,23 +985,17 @@ _Jv_RunMain (const char *name, int argc,
   _Jv_ThisExecutable (exec_name);
 #endif
 
+  main_thread = _Jv_AttachCurrentThread (JvNewStringLatin1 ("main"), NULL);
+
   if (is_jar)
     {
       // name specifies a jar file.  We must now extract the
-      // Main-Class attribute from the jar's manifest file.  This is
-      // done by gnu.gcj.runtime.FirstThread.main.
+      // Main-Class attribute from the jar's manifest file.
+      // This is done by gnu.gcj.runtime.FirstThread.getMain.
       _Jv_Jar_Class_Path = strdup (name);
-      arg_vec = JvConvertArgv (1, &_Jv_Jar_Class_Path);
-
-      main_thread = 
-	new gnu::gcj::runtime::FirstThread (&gnu::gcj::runtime::FirstThread::class$,
-					    arg_vec);
-      main_thread->start();
-      _Jv_ThreadWait ();
-      
-      // FirstThread.main extracts the main class name and stores it
-      // here.
-      class_name = gnu::gcj::runtime::FirstThread::jarMainClassName;
+      jstring jar_name = JvNewStringLatin1 (name);
+      // FirstThread.getMain extracts the main class name.
+      class_name = gnu::gcj::runtime::FirstThread::getMain (jar_name);
 
       // We need a new ClassLoader because the classpath must be the
       // jar file only.  The easiest way to do this is to lose our
@@ -900,8 +1009,7 @@ _Jv_RunMain (const char *name, int argc,
 
   if (class_name)
     {
-      main_thread = new gnu::gcj::runtime::FirstThread (class_name, arg_vec);
-      main_thread->start();
+      runFirst(java::lang::Class::forName (class_name), arg_vec);
       _Jv_ThreadWait ();
     }
 
Index: win32-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/win32-threads.cc,v
retrieving revision 1.3
diff -u -p -r1.3 win32-threads.cc
--- win32-threads.cc	2000/12/30 12:18:39	1.3
+++ win32-threads.cc	2001/05/22 06:43:29
@@ -35,7 +35,6 @@ extern "C"
 struct starter
 {
   _Jv_ThreadStartFunc *method;
-  java::lang::Thread *object;
   _Jv_Thread_t *data;
 };
 
@@ -124,10 +123,11 @@ _Jv_InitThreads (void)
 }
 
 _Jv_Thread_t *
-_Jv_ThreadInitData (java::lang::Thread *)
+_Jv_ThreadInitData (java::lang::Thread* obj)
 {
   _Jv_Thread_t *data = new _Jv_Thread_t;
   data->flags = 0;
+  data->thread_obj = obj;
 
   return data;
 }
@@ -176,6 +176,20 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *dat
     }
 }
 
+void
+_Jv_ThreadRegister (_Jv_Thread_t *data)
+{
+  TlsSetValue (_Jv_ThreadKey, data->thread_obj);
+  TlsSetValue (_Jv_ThreadDataKey, data);
+}
+
+void
+_Jv_ThreadUnRegister ()
+{
+  TlsSetValue (_Jv_ThreadKey, NULL);
+  TlsSetValue (_Jv_ThreadDataKey, NULL);
+}
+
 // This function is called when a thread is started.  We don't arrange
 // to call the `run' method directly, because this function must
 // return a value.
@@ -183,10 +197,10 @@ static DWORD __stdcall
 really_start (void* x)
 {
   struct starter *info = (struct starter *) x;
+
+  _Jv_ThreadRegister (info->data);
 
-  TlsSetValue (_Jv_ThreadKey, info->object);
-  TlsSetValue (_Jv_ThreadDataKey, info->data);
-  info->method (info->object);
+  info->method (info->data->thread_obj);
 
   if (! (info->data->flags & FLAG_DAEMON))
     {
@@ -214,7 +228,6 @@ _Jv_ThreadStart (java::lang::Thread *thr
   // FIXME: handle marking the info object for GC.
   info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
   info->method = meth;
-  info->object = thread;
   info->data = data;
 
   if (! thread->isDaemon ())
Index: gcj/cni.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/cni.h,v
retrieving revision 1.7
diff -u -p -r1.7 cni.h
--- cni.h	2001/03/26 07:05:31	1.7
+++ cni.h	2001/05/22 06:43:29
@@ -118,4 +118,22 @@ JvFree (void *ptr)
 {
   return _Jv_Free (ptr);
 }
+
+extern inline jint
+JvCreateJavaVM (void* vm_args)
+{
+  return _Jv_CreateJavaVM (vm_args);
+}
+
+extern inline java::lang::Thread*
+JvAttachCurrentThread (jstring name, java::lang::ThreadGroup* group)
+{
+  return _Jv_AttachCurrentThread (name, group);
+}
+
+extern inline jint
+JvDetachCurrentThread (void)
+{
+  return _Jv_DetachCurrentThread ();
+}
 #endif /* __GCJ_CNI_H__ */
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.20
diff -u -p -r1.20 javaprims.h
--- javaprims.h	2001/05/22 04:38:33	1.20
+++ javaprims.h	2001/05/22 06:43:29
@@ -380,6 +380,11 @@ extern "C" jstring _Jv_NewStringLatin1(c
 extern "C" jsize _Jv_GetStringUTFLength (jstring);
 extern "C" jsize _Jv_GetStringUTFRegion (jstring, jsize, jsize, char *);
 
+extern jint _Jv_CreateJavaVM (void* /*vm_args*/);
+extern "C" java::lang::Thread*
+_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group);
+extern "C" jint _Jv_DetachCurrentThread (void);
+
 extern "C" void _Jv_Throw (jthrowable) __attribute__ ((__noreturn__));
 extern "C" void* _Jv_Malloc (jsize) __attribute__((__malloc__));
 extern "C" void* _Jv_Realloc (void *, jsize);
Index: gnu/gcj/runtime/FirstThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/FirstThread.java,v
retrieving revision 1.7
diff -u -p -r1.7 FirstThread.java
--- FirstThread.java	2001/03/18 23:07:57	1.7
+++ FirstThread.java	2001/05/22 06:43:29
@@ -19,58 +19,28 @@ import java.util.jar.*;
 
 // This is entirely internal to our implementation.
 
-final class FirstThread extends Thread
+final class FirstThread
 {
-  public native void run ();
-
-  public FirstThread (Class k, Object o)
-  {
-    super (null, null, "main");
-    klass = k;
-    klass_name = null;
-    args = o;
-  }
-
-  public FirstThread (String class_name, Object o)
+  public static String getMain (String name)
   {
-    super (null, null, "main");
-    klass = null;
-    klass_name = class_name;
-    args = o;
-  }
-
-  private static void die (String s)
-  {
-    System.err.println(s);
-    System.exit(1);
-  }
-
-  public static void main (String[] args)
-  {
+    String mainName = null;
     try {
 
-      JarFile j = new JarFile (args[0]);
+      JarFile j = new JarFile (name);
 
       Attributes a = j.getManifest().getMainAttributes();
 
-      jarMainClassName = a.getValue(Attributes.Name.MAIN_CLASS);
+      mainName = a.getValue(Attributes.Name.MAIN_CLASS);
 
-      if (jarMainClassName != null)
-      {
-	jarMainClassName = jarMainClassName.replace('/','.');
-	return;
-      }
     } catch (Exception e) {
       // empty
     }
 
-    System.err.println ("Failed to load Main-Class manifest attribute from\n"
-			+ args[0]);
+    if (mainName == null)
+      System.err.println ("Failed to load Main-Class manifest attribute from\n"
+			  + name);
+    return mainName;
   }
-
-  // If interpreter is invoked with -jar, the main class name is recorded
-  // here.
-  public static String jarMainClassName;
 
   // Private data.
   private Class klass;
Index: include/no-threads.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/no-threads.h,v
retrieving revision 1.5
diff -u -p -r1.5 no-threads.h
--- no-threads.h	2000/12/30 12:18:39	1.5
+++ no-threads.h	2001/05/22 06:43:30
@@ -102,11 +102,8 @@ _Jv_InitThreads (void)
 {
 }
 
-inline _Jv_Thread_t *
-_Jv_ThreadInitData (java::lang::Thread *)
-{
-  return NULL;
-}
+_Jv_Thread_t *
+_Jv_ThreadInitData (java::lang::Thread *);
 
 inline void
 _Jv_ThreadDestroyData (_Jv_Thread_t *data)
@@ -127,6 +124,16 @@ _Jv_ThreadYield (void)
 
 inline void
 _Jv_ThreadSetPriority (_Jv_Thread_t *, jint)
+{
+}
+
+inline void
+_Jv_ThreadRegister (_Jv_Thread_t *data)
+{
+}
+
+inline void
+_Jv_ThreadUnRegister (void)
 {
 }
 
Index: include/posix-threads.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/posix-threads.h,v
retrieving revision 1.17
diff -u -p -r1.17 posix-threads.h
--- posix-threads.h	2001/05/19 05:43:00	1.17
+++ posix-threads.h	2001/05/22 06:43:30
@@ -194,6 +194,9 @@ _Jv_ThreadYield (void)
 #endif /* HAVE_SCHED_YIELD */
 }
 
+void _Jv_ThreadRegister (_Jv_Thread_t *data);
+void _Jv_ThreadUnRegister ();
+
 void _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio);
 
 void _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
Index: include/win32-threads.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/win32-threads.h,v
retrieving revision 1.3
diff -u -p -r1.3 win32-threads.h
--- win32-threads.h	2000/12/30 12:18:39	1.3
+++ win32-threads.h	2001/05/22 06:43:30
@@ -25,6 +25,7 @@ typedef struct
 {
   int flags;            // Flags are defined in implementation.
   HANDLE handle;        // Actual handle to the thread
+  java::lang::Thread *thread_obj;
 } _Jv_Thread_t;
 
 typedef void _Jv_ThreadStartFunc (java::lang::Thread *);
@@ -119,6 +120,9 @@ _Jv_ThreadYield (void)
 {
   Sleep (0);
 }
+
+void _Jv_ThreadRegister (_Jv_Thread_t *data);
+void _Jv_ThreadUnRegister ();
 
 void _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio);
 void _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
Index: java/lang/Thread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Thread.java,v
retrieving revision 1.17
diff -u -p -r1.17 Thread.java
--- Thread.java	2001/01/05 00:31:45	1.17
+++ Thread.java	2001/05/22 06:43:30
@@ -1,6 +1,6 @@
 // Thread.java - Thread class.
 
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -209,18 +209,20 @@ public class Thread implements Runnable
 
   private final native void initialize_native ();
 
-  private final synchronized static String gen_name ()
+  private final native static String gen_name ();
+
+  public Thread (ThreadGroup g, Runnable r, String n)
   {
-    String n;
-    n = "Thread-" + nextThreadNumber;
-    ++nextThreadNumber;
-    return n;
+    this (currentThread (), g, r, n);
+
+    // The Class Libraries book says ``threadName cannot be null''.  I
+    // take this to mean NullPointerException.
+    if (n == null)
+      throw new NullPointerException ();
   }
 
-  public Thread (ThreadGroup g, Runnable r, String n)
+  private Thread (Thread current, ThreadGroup g, Runnable r, String n)
   {
-    Thread current = currentThread ();
-          
     if (g == null)
       {
 	// If CURRENT is null, then we are bootstrapping the first thread. 
@@ -233,17 +235,6 @@ public class Thread implements Runnable
     else
       group = g;
       
-    group.checkAccess();
-
-    // The Class Libraries book says ``threadName cannot be null''.  I
-    // take this to mean NullPointerException.
-    if (n == null)
-      throw new NullPointerException ();
-
-    name = n;
-    group.addThread(this);
-    runnable = r;
-
     data = null;
     interrupt_flag = false;
     alive_flag = false;
@@ -251,6 +242,8 @@ public class Thread implements Runnable
 
     if (current != null)
       {
+	group.checkAccess();
+
 	daemon_flag = current.isDaemon();
         int gmax = group.getMaxPriority();
 	int pri = current.getPriority();
@@ -263,6 +256,10 @@ public class Thread implements Runnable
 	priority = NORM_PRIORITY;
       }
 
+    name = n;
+    group.addThread(this);
+    runnable = r;
+
     initialize_native ();
   }
 
@@ -315,9 +312,6 @@ public class Thread implements Runnable
   private boolean startable_flag;
   private ClassLoader context_class_loader;
 
-  // Our native data.
+  // Our native data - points to an instance of struct natThread.
   private Object data;
-
-  // Next thread number to assign.
-  private static int nextThreadNumber = 0;
 }
Index: java/lang/natThread.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natThread.cc,v
retrieving revision 1.21
diff -u -p -r1.21 natThread.cc
--- natThread.cc	2001/03/26 07:05:32	1.21
+++ natThread.cc	2001/05/22 06:43:30
@@ -1,6 +1,6 @@
 // natThread.cc - Native part of Thread class.
 
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -59,7 +59,7 @@ java::lang::Thread::initialize_native (v
 {
   natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
   
-  // The native thread data is kept in a Object field, not a rawdata, so that
+  // 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?
@@ -322,6 +322,34 @@ java::lang::Thread::suspend (void)
     (JvNewStringLatin1 ("java::lang::Thread::suspend unimplemented"));
 }
 
+static int nextThreadNumber = 0;
+
+jstring
+java::lang::Thread::gen_name (void)
+{
+  jint i;
+  jclass sync = &java::lang::Thread::class$;
+  {
+    JvSynchronize dummy(sync); 
+    i = ++nextThreadNumber;
+  }
+
+  // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-".
+  jchar buffer[7+11];
+  jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer));
+  i = _Jv_FormatInt (bufend, i);
+  jchar *ptr = bufend - i;
+  // Prepend "Thread-".
+  *--ptr = '-';
+  *--ptr = 'd';
+  *--ptr = 'a';
+  *--ptr = 'e';
+  *--ptr = 'r';
+  *--ptr = 'h';
+  *--ptr = 'T';
+  return JvNewString (ptr, bufend - ptr);
+}
+
 void
 java::lang::Thread::yield (void)
 {
@@ -343,4 +371,34 @@ _Jv_SetCurrentJNIEnv (JNIEnv *env)
   java::lang::Thread *t = _Jv_ThreadCurrent ();
   JvAssert (t != NULL);
   ((natThread *) t->data)->jni_env = env;
+}
+
+java::lang::Thread*
+_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
+{
+  java::lang::Thread *thread = _Jv_ThreadCurrent ();
+  if (thread != NULL)
+    return thread;
+  if (name == NULL)
+    name = java::lang::Thread::gen_name ();
+  thread = new java::lang::Thread (NULL, group, NULL, name);
+  thread->startable_flag = false;
+  thread->alive_flag = true;
+  natThread *nt = (natThread *) thread->data;
+  _Jv_ThreadRegister (nt->thread);
+  return thread;
+}
+
+jint
+_Jv_DetachCurrentThread (void)
+{
+  java::lang::Thread *t = _Jv_ThreadCurrent ();
+  if (t == NULL)
+    return -1;
+
+  _Jv_ThreadUnRegister ();
+  // Release the monitors.
+  t->finish_ ();
+
+  return 0;
 }

-- 
	--Per Bothner
per@bothner.com   http://www.bothner.com/per/


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