Implement invocation interface; don't create new thread for main.

From-SVN: r42428
This commit is contained in:
Per Bothner 2001-05-21 23:47:48 -07:00 committed by Per Bothner
parent b4fbaca7cb
commit c93d7fae7b
22 changed files with 461 additions and 1945 deletions

View file

@ -1,3 +1,46 @@
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.
2001-05-21 Per Bothner <per@bothner.com>
* Makefile.am (libgcj_la_DEPENDENCIES): Add $(nat_files).

View file

@ -303,12 +303,12 @@ gnu/gcj/runtime/FirstThread.h: gnu/gcj/runtime/FirstThread.class libgcj.jar
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 \

File diff suppressed because one or more lines are too long

View file

@ -73,6 +73,7 @@ CXXCPP = @CXXCPP@
DIRLTDL = @DIRLTDL@
DIVIDESPEC = @DIVIDESPEC@
DLLTOOL = @DLLTOOL@
EXCEPTIONSPEC = @EXCEPTIONSPEC@
EXEEXT = @EXEEXT@
GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
GCDEPS = @GCDEPS@
@ -202,7 +203,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$d/$$file $(distdir)/$$file; \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View file

@ -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__ */

View file

@ -380,6 +380,11 @@ extern "C" jstring _Jv_NewStringLatin1(const char*, jsize)
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);

View file

@ -1,29 +0,0 @@
// NativeThread.java - Wrapper for attached user threads.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
package gnu.gcj.jni;
/**
* @author Tom Tromey <tromey@cygnus.com>
* @date February 9, 2000
*/
public class NativeThread extends Thread
{
public NativeThread (ThreadGroup g, String name)
{
super (g, null, name);
init ();
}
// Call this to mark the thread as finished.
public native void finish ();
public native void init ();
}

View file

@ -1,30 +0,0 @@
// natNativeThread.cc - Native side of attached threads.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
// Written by Tom Tromey <tromey@cygnus.com>
#include <config.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <gnu/gcj/jni/NativeThread.h>
#include <java/lang/Thread.h>
void
gnu::gcj::jni::NativeThread::finish ()
{
finish_ ();
}
void
gnu::gcj::jni::NativeThread::init ()
{
alive_flag = true; // alive_flag is private in java.lang.Thread
}

View file

@ -19,59 +19,29 @@ 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)
{
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)
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)
{
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;
private String klass_name;

View file

@ -1,147 +0,0 @@
// natFirstThread.cc - Implementation of FirstThread native methods.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
#include <config.h>
#include <stdlib.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <jni.h>
#include <gnu/gcj/runtime/FirstThread.h>
#include <java/lang/Class.h>
#include <java/lang/String.h>
#include <java/lang/System.h>
#include <java/lang/reflect/Modifier.h>
#include <java/io/PrintStream.h>
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
#include <java/lang/ThreadGroup.h>
#include <java/lang/UnsatisfiedLinkError.h>
#endif
#define DIE(Message) die (JvNewStringLatin1 (Message))
typedef void main_func (jobject);
#ifdef WITH_JVMPI
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));
}
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.
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);
_Jv_Method *meth = _Jv_GetMethodLocal (klass, main_name, main_signature);
// Some checks from Java Spec section 12.1.4.
if (meth == NULL)
DIE ("no suitable method `main' in class");
if (! java::lang::reflect::Modifier::isStatic(meth->accflags))
DIE ("`main' must be static");
if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
DIE ("`main' must be public");
#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);
}

View file

@ -73,6 +73,7 @@ CXXCPP = @CXXCPP@
DIRLTDL = @DIRLTDL@
DIVIDESPEC = @DIVIDESPEC@
DLLTOOL = @DLLTOOL@
EXCEPTIONSPEC = @EXCEPTIONSPEC@
EXEEXT = @EXEEXT@
GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
GCDEPS = @GCDEPS@

View file

@ -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)
@ -130,6 +127,16 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *, jint)
{
}
inline void
_Jv_ThreadRegister (_Jv_Thread_t *data)
{
}
inline void
_Jv_ThreadUnRegister (void)
{
}
void _Jv_ThreadStart (java::lang::Thread *, _Jv_Thread_t *,
_Jv_ThreadStartFunc *meth);

View file

@ -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,

View file

@ -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 *);
@ -120,6 +121,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,
_Jv_ThreadStartFunc *meth);

View file

@ -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 ()
{
String n;
n = "Thread-" + nextThreadNumber;
++nextThreadNumber;
return n;
}
private final native static String gen_name ();
public Thread (ThreadGroup g, Runnable r, String n)
{
Thread current = currentThread ();
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 ();
}
private Thread (Thread current, ThreadGroup g, Runnable r, String n)
{
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;
}

View file

@ -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 (void)
{
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)
{
@ -344,3 +372,33 @@ _Jv_SetCurrentJNIEnv (JNIEnv *env)
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;
}

View file

@ -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 *, jstring name, void **penv, void *args)
{
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

View file

@ -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");
}

View file

@ -326,6 +326,25 @@ _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
}
}
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.
@ -334,13 +353,7 @@ 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);

View file

@ -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_memory;
// 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_POINTERS e)
#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 char **argv)
_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, const char **argv, bool is_jar)
_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, const char **argv, bool is_jar)
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 ();
}

View file

@ -73,6 +73,7 @@ CXXCPP = @CXXCPP@
DIRLTDL = @DIRLTDL@
DIVIDESPEC = @DIVIDESPEC@
DLLTOOL = @DLLTOOL@
EXCEPTIONSPEC = @EXCEPTIONSPEC@
EXEEXT = @EXEEXT@
GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
GCDEPS = @GCDEPS@
@ -122,14 +123,10 @@ libgcj_basedir = @libgcj_basedir@
AUTOMAKE_OPTIONS = foreign dejagnu
# Setup the testing framework, if you have one
EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \
echo $(top_builddir)/../expect/expect ; \
else echo expect ; fi`
EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then echo $(top_builddir)/../expect/expect ; else echo expect ; fi`
RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \
echo $(top_srcdir)/../dejagnu/runtest ; \
else echo runtest; fi`
RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then echo $(top_srcdir)/../dejagnu/runtest ; else echo runtest; fi`
RUNTESTFLAGS = @AM_RUNTESTFLAGS@

View file

@ -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 *data, jint prio)
}
}
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.
@ -184,9 +198,9 @@ really_start (void* x)
{
struct starter *info = (struct starter *) x;
TlsSetValue (_Jv_ThreadKey, info->object);
TlsSetValue (_Jv_ThreadDataKey, info->data);
info->method (info->object);
_Jv_ThreadRegister (info->data);
info->method (info->data->thread_obj);
if (! (info->data->flags & FLAG_DAEMON))
{
@ -214,7 +228,6 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStart
// 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 ())