This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
preliminary invocation patch
- To: java-patches at gcc dot gnu dot org
- Subject: preliminary invocation patch
- From: Per Bothner <per at bothner dot com>
- Date: 15 May 2001 13:29:52 -0700
Below is a preliminary patch (relative to the libjava directory of the
gcc3.0 branch) that adds support for a CNI invocation interface and
the JNI invocation interface. It no longer uses NativeThread or
FirstThread - the first thread is now the C++ "main" thread.
The follwing C++ program works with this patch:
#include <stdio.h>
#include <gcj/cni.h>
#include <java/lang/Thread.h>
#include <java/lang/System.h>
#include <java/io/PrintStream.h>
int
main (int argc, char ** argv)
{
JvCreateJavaVM (NULL);
JvInitClass(&java::lang::System::class$);
for (int i = 1; i < 5; i++)
{
char buf[100];
java::lang::Thread* thread = _Jv_AttachCurrentThread (NULL, NULL);
java::io::PrintStream* out = java::lang::System::out;
sprintf (buf, "Hello time %d.\n", i);
jstring str = JvNewStringLatin1(buf);
out->println(str);
out->flush();
JvDetachCurrentThread ();
}
}
I have not tested the JNI invocation interface, I have not tested with
--disable-threads, and I have not tested Windows. I would especially
appreciate testing on Windows. I ran the testsuite on an earlier
version, with some regressions, that I have not looked into. I also
want to get rid of the FirstThread class, merging the needed code from
natFirstThread.cc into either natThread.cc or prims.cc.
If we can get these problems taken care of quickly, we then need
to consider whether to include this in the gcc-3.0 branch.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.129.2.8
diff -u -p -r1.129.2.8 Makefile.am
--- Makefile.am 2001/05/13 07:10:23 1.129.2.8
+++ Makefile.am 2001/05/15 20:02:37
@@ -304,12 +304,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
@@ -1006,7 +1006,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 \
@@ -1248,7 +1255,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 \
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.139.2.8
diff -u -p -r1.139.2.8 Makefile.in
--- Makefile.in 2001/05/13 07:10:23 1.139.2.8
+++ Makefile.in 2001/05/15 20:02:38
@@ -733,7 +733,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 \
@@ -974,7 +981,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 \
@@ -1140,7 +1146,7 @@ gnu/gcj/convert/JIS0212_to_Unicode.lo gn
gnu/gcj/convert/natIconv.lo gnu/gcj/convert/natInput_EUCJIS.lo \
gnu/gcj/convert/natInput_SJIS.lo gnu/gcj/convert/natOutput_EUCJIS.lo \
gnu/gcj/convert/natOutput_SJIS.lo gnu/gcj/io/natSimpleSHSStream.lo \
-gnu/gcj/io/shs.lo gnu/gcj/jni/natNativeThread.lo \
+gnu/gcj/io/shs.lo \
gnu/gcj/runtime/natFirstThread.lo java/io/natFile.lo \
java/io/natFileDescriptor.lo java/io/natObjectInputStream.lo \
java/io/natObjectOutputStream.lo java/lang/natCharacter.lo \
@@ -1241,7 +1247,6 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_D
.deps/gnu/gcj/io/DefaultMimeTypes.P .deps/gnu/gcj/io/MimeTypes.P \
.deps/gnu/gcj/io/SimpleSHSStream.P \
.deps/gnu/gcj/io/natSimpleSHSStream.P .deps/gnu/gcj/io/shs.P \
-.deps/gnu/gcj/jni/NativeThread.P .deps/gnu/gcj/jni/natNativeThread.P \
.deps/gnu/gcj/math/MPN.P .deps/gnu/gcj/protocol/file/Connection.P \
.deps/gnu/gcj/protocol/file/Handler.P \
.deps/gnu/gcj/protocol/http/Connection.P \
@@ -2372,12 +2377,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
Index: jni.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni.cc,v
retrieving revision 1.36.4.7
diff -u -p -r1.36.4.7 jni.cc
--- jni.cc 2001/05/03 16:55:34 1.36.4.7
+++ jni.cc 2001/05/15 20:02:39
@@ -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,8 +54,10 @@ 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$
+extern java::lang::Thread*
+_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group);
+
// This enum is used to select different template instantiations in
// the invocation code.
enum invocation_type
@@ -1860,7 +1863,7 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, j
{
try
{
- (void) new gnu::gcj::jni::NativeThread (group, name);
+ _Jv_AttachCurrentThread (name, group);
}
catch (jthrowable t)
{
@@ -1914,28 +1917,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: posix-threads.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/posix-threads.cc,v
retrieving revision 1.22
diff -u -p -r1.22 posix-threads.cc
--- posix-threads.cc 2000/12/30 12:18:39 1.22
+++ posix-threads.cc 2001/05/15 20:02:39
@@ -330,6 +330,26 @@ _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.
@@ -337,14 +357,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.46.4.2
diff -u -p -r1.46.4.2 prims.cc
--- prims.cc 2001/03/23 19:16:40 1.46.4.2
+++ prims.cc 2001/05/15 20:02:40
@@ -62,6 +62,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 +75,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;
@@ -641,9 +644,18 @@ 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"
{
+#pragma weak JNI_OnLoad
+ extern jint JNI_OnLoad (JavaVM *, void *) __attribute__((weak));
+}
+
+
+jint
+_Jv_CreateJavaVM (void* /*vm_args*/)
+{
// Turn stack trace generation off while creating exception objects.
_Jv_InitClass (&java::lang::Throwable::class$);
java::lang::Throwable::trace_enabled = 0;
@@ -684,6 +696,28 @@ main_init ()
#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;
}
#ifndef DISABLE_GETENV_PROPERTIES
@@ -829,6 +863,8 @@ process_gcj_properties ()
}
#endif // DISABLE_GETENV_PROPERTIES
+extern void runFirst(::java::lang::Class *klass, ::java::lang::Object *args);
+
void
JvRunMain (jclass klass, int argc, const char **argv)
{
@@ -837,7 +873,7 @@ JvRunMain (jclass klass, int argc, const
_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 ());
@@ -846,11 +882,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();
- _Jv_ThreadWait ();
+ runFirst (klass, arg_vec);
int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
@@ -863,7 +897,7 @@ _Jv_RunMain (const char *name, int argc,
jstring class_name;
PROCESS_GCJ_PROPERTIES;
- main_init ();
+ _Jv_CreateJavaVM (NULL);
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
@@ -871,23 +905,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
@@ -901,9 +929,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();
- _Jv_ThreadWait ();
+ runFirst(java::lang::Class::forName (class_name), arg_vec);
}
int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
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/15 20:02:40
@@ -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.6.4.1
diff -u -p -r1.6.4.1 cni.h
--- cni.h 2001/05/13 07:10:25 1.6.4.1
+++ cni.h 2001/05/15 20:02:40
@@ -126,4 +126,22 @@ JvFree (void *ptr)
{
return _Jv_Free (ptr);
}
+
+extern inline jint
+JvCreateJavaVM (void* vm_args)
+{
+ return _Jv_CreateJavaVM (vm_args);
+}
+
+extern inline jint
+JvDetachCurrentThread (void)
+{
+ return _Jv_DetachCurrentThread ();
+}
+
+extern inline java::lang::Thread*
+JvAttachCurrentThread (jstring name, java::lang::ThreadGroup* group)
+{
+ return _Jv_AttachCurrentThread (name, group);
+}
#endif /* __GCJ_CNI_H__ */
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.15.4.2
diff -u -p -r1.15.4.2 javaprims.h
--- javaprims.h 2001/05/13 07:10:25 1.15.4.2
+++ javaprims.h 2001/05/15 20:02:40
@@ -375,6 +375,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.6
diff -u -p -r1.6 FirstThread.java
--- FirstThread.java 2000/12/12 00:32:02 1.6
+++ FirstThread.java 2001/05/15 20:02:40
@@ -39,36 +39,32 @@ final class FirstThread extends Thread
args = o;
}
- private static void die (String s)
+ static void die (String s)
{
System.err.println(s);
System.exit(1);
}
- public static void main (String[] args)
+ public static String getMain (String name)
{
+ 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)
- 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: gnu/gcj/runtime/natFirstThread.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/natFirstThread.cc,v
retrieving revision 1.4
diff -u -p -r1.4 natFirstThread.cc
--- natFirstThread.cc 2000/04/24 15:07:16 1.4
+++ natFirstThread.cc 2001/05/15 20:02:40
@@ -26,10 +26,9 @@ details. */
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
#include <java/lang/ThreadGroup.h>
-#include <java/lang/UnsatisfiedLinkError.h>
#endif
-#define DIE(Message) die (JvNewStringLatin1 (Message))
+#define DIE(Message) gnu::gcj::runtime::FirstThread::die (JvNewStringLatin1 (Message))
typedef void main_func (jobject);
@@ -37,46 +36,24 @@ typedef void main_func (jobject);
extern void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event);
#endif
-/* This will be non-NULL if the user has preloaded a JNI library, or
- linked one into the executable. */
-extern "C"
-{
-#pragma weak JNI_OnLoad
- extern jint JNI_OnLoad (JavaVM *, void *) __attribute__((weak));
-}
+extern void runFirst(::java::lang::Class *klass, ::java::lang::Object *args);
void
gnu::gcj::runtime::FirstThread::run (void)
{
- Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22);
- Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4);
-
- /* 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;
- }
- 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")));
- }
- }
-
if (klass == NULL)
klass = java::lang::Class::forName (klass_name);
if (klass != NULL)
_Jv_InitClass (klass);
+ runFirst (klass, args);
+}
+
+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);
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/15 20:02:40
@@ -130,6 +130,16 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *, j
{
}
+inline void
+void _Jv_ThreadRegister (_Jv_Thread_t *data)
+{
+}
+
+inline void
+void _Jv_ThreadUnRegister (void)
+{
+}
+
void _Jv_ThreadStart (java::lang::Thread *, _Jv_Thread_t *,
_Jv_ThreadStartFunc *meth);
Index: include/posix-threads.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/posix-threads.h,v
retrieving revision 1.16
diff -u -p -r1.16 posix-threads.h
--- posix-threads.h 2000/12/30 12:18:39 1.16
+++ posix-threads.h 2001/05/15 20:02:41
@@ -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/15 20:02:41
@@ -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/15 20:02:41
@@ -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.20
diff -u -p -r1.20 natThread.cc
--- natThread.cc 2000/12/30 12:18:39 1.20
+++ natThread.cc 2001/05/15 20:02:41
@@ -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.
@@ -11,6 +11,7 @@ details. */
#include <config.h>
#include <stdlib.h>
+#include <stdio.h>
#include <gcj/cni.h>
#include <jvm.h>
@@ -59,7 +60,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 +323,18 @@ java::lang::Thread::suspend (void)
(JvNewStringLatin1 ("java::lang::Thread::suspend unimplemented")));
}
+static int nextThreadNumber = 0;
+
+jstring
+java::lang::Thread::gen_name (void)
+{
+ JvSynchronize dummy(&java::lang::Thread::class$);
+ char buf[20];
+ sprintf (buf, "Thread-%d", nextThreadNumber);
+ nextThreadNumber++;
+ return JvNewStringLatin1 (buf);
+}
+
void
java::lang::Thread::yield (void)
{
@@ -343,4 +356,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/