This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
java invocation api checked in
- To: java-patches at gcc dot gnu dot org
- Subject: java invocation api checked in
- From: Per Bothner <per at bothner dot com>
- Date: 21 May 2001 23:55:55 -0700
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/