Makefile.am: New friends for java/lang/Thread.h.

* Makefile.am: New friends for java/lang/Thread.h.
	* prims.cc (runFirst): Removed.
	(JvRunMain): Merged into _Jv_RunMain. Now just calls that.
	(_Jv_RunMain): Now takes either a klass or class name parameter.
	Create a gnu.gcj.runtime.FirstThread and attach the native thread
	to that, then run it using _Jv_ThreadRun. Remove special handling of
	jar files, instead pass is_jar parameter through to FirstThread.
	* gcj/javaprims.h: Add prototypes for _Jv_ThreadRun and new variant
	of _Jv_AttachCurrentThread.
	* gnu/gcj/runtime/FirstThread.java (FirstThread): Now extends Thread.
	(run): New method. Take care of looking up main class manifest
	attribute and calling forName if neccessary. Then call call_main.
	(call_main): New native method.
	* gnu/gcj/runtime/natFirstThread.cc (call_main): New function, code
	relocated from prims.cc. Look up and call main method.
	* java/lang/Thread.java (run_): Removed.
	* java/lang/natThread.cc (run_): Renamed to...
	(_Jv_ThreadRun): this. JVMPI notification code moved to ...
	(_Jv_NotifyThreadStart): here. New function.
	(countStackFrames, destroy, resume, suspend, stop): Throw
	UnsupportedOperationExceptions rather than JvFail'ing.
	(_Jv_AttachCurrentThread): New variant takes a Thread argument.
	Existing version wraps new variant.

From-SVN: r45182
This commit is contained in:
Bryce McKinlay 2001-08-26 11:30:09 +00:00 committed by Bryce McKinlay
parent 387edc7625
commit 2dc55bc99f
11 changed files with 264 additions and 1174 deletions

View File

@ -2,6 +2,31 @@
* name-finder.cc (lookup): Ignore a null dli_fname from dladdr.
* Makefile.am: New friends for java/lang/Thread.h.
* prims.cc (runFirst): Removed.
(JvRunMain): Merged into _Jv_RunMain. Now just calls that.
(_Jv_RunMain): Now takes either a klass or class name parameter.
Create a gnu.gcj.runtime.FirstThread and attach the native thread
to that, then run it using _Jv_ThreadRun. Remove special handling of
jar files, instead pass is_jar parameter through to FirstThread.
* gcj/javaprims.h: Add prototypes for _Jv_ThreadRun and new variant
of _Jv_AttachCurrentThread.
* gnu/gcj/runtime/FirstThread.java (FirstThread): Now extends Thread.
(run): New method. Take care of looking up main class manifest
attribute and calling forName if neccessary. Then call call_main.
(call_main): New native method.
* gnu/gcj/runtime/natFirstThread.cc (call_main): New function, code
relocated from prims.cc. Look up and call main method.
* java/lang/Thread.java (run_): Removed.
* java/lang/natThread.cc (run_): Renamed to...
(_Jv_ThreadRun): this. JVMPI notification code moved to ...
(_Jv_NotifyThreadStart): here. New function.
(countStackFrames, destroy, resume, suspend, stop): Throw
UnsupportedOperationExceptions rather than JvFail'ing.
(_Jv_AttachCurrentThread): New variant takes a Thread argument.
Existing version wraps new variant.
2001-08-23 Tom Tromey <tromey@redhat.com>
* java/lang/reflect/Field.java (toString): Use

View File

@ -267,7 +267,7 @@ $(nat_headers) $(x_nat_headers): libgcj.jar
java/lang/ClassLoader.h: java/lang/ClassLoader.class libgcj.jar
$(GCJH) -classpath $(top_builddir) \
-friend 'jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader);' \
-friend 'void _Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar);' \
-friend 'void _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv, bool is_jar);' \
$(basename $<)
## Our internal main program needs to be able to create a FirstThread.
@ -284,6 +284,8 @@ java/lang/Thread.h: java/lang/Thread.class libgcj.jar
-prepend '#define _JV_INTERRUPTED 2' \
-friend '_Jv_JNIEnv * _Jv_GetCurrentJNIEnv ();' \
-friend 'void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env);' \
-friend 'void _Jv_ThreadRun (java::lang::Thread* thread);' \
-friend 'jint _Jv_AttachCurrentThread(java::lang::Thread* thread);' \
-friend 'java::lang::Thread* _Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group);' \
-friend 'jint _Jv_DetachCurrentThread ();' \
$(basename $<)
@ -1343,6 +1345,7 @@ gnu/gcj/convert/natOutput_EUCJIS.cc \
gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.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

@ -398,6 +398,11 @@ extern "C" jsize _Jv_GetStringUTFLength (jstring);
extern "C" jsize _Jv_GetStringUTFRegion (jstring, jsize, jsize, char *);
extern jint _Jv_CreateJavaVM (void* /*vm_args*/);
void
_Jv_ThreadRun (java::lang::Thread* thread);
jint
_Jv_AttachCurrentThread(java::lang::Thread* thread);
extern "C" java::lang::Thread*
_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group);
extern "C" jint _Jv_DetachCurrentThread (void);

View File

@ -136,5 +136,5 @@ main (int argc, const char **argv)
exit (1);
}
_Jv_RunMain (argv[i], argc - i, argv + i, jar_mode);
_Jv_RunMain (NULL, argv[i], argc - i, argv + i, jar_mode);
}

View File

@ -17,11 +17,44 @@ import java.util.jar.*;
* @date August 24, 1998
*/
// This is entirely internal to our implementation.
final class FirstThread
final class FirstThread extends Thread
{
public static String getMain (String name)
public FirstThread (Class k, String[] args)
{
super (null, null, "main");
klass = k;
this.args = args;
}
public FirstThread (String class_name, String[] args, boolean is_jar)
{
super (null, null, "main");
klass_name = class_name;
this.args = args;
this.is_jar = is_jar;
}
public void run()
{
if (is_jar)
klass_name = getMain(klass_name);
if (klass == null)
{
try
{
klass = Class.forName(klass_name);
}
catch (ClassNotFoundException x)
{
throw new NoClassDefFoundError(klass_name);
}
}
call_main();
}
private String getMain (String name)
{
String mainName = null;
try {
@ -37,15 +70,21 @@ final class FirstThread
}
if (mainName == null)
System.err.println ("Failed to load Main-Class manifest attribute from\n"
+ name);
{
System.err.println ("Failed to load Main-Class manifest attribute from\n"
+ name);
System.exit(1);
}
return mainName;
}
private native void call_main ();
// Private data.
private Class klass;
private String klass_name;
private Object args;
private boolean is_jar;
// If the user links statically then we need to ensure that these
// classes are linked in. Otherwise bootstrapping fails. These

View File

@ -0,0 +1,47 @@
// natFirstThread.cc - Implementation of FirstThread native methods.
/* Copyright (C) 1998, 1999, 2000, 2001 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 <stdio.h>
#include <stdlib.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <gnu/gcj/runtime/FirstThread.h>
typedef void main_func (jobject);
void
gnu::gcj::runtime::FirstThread::call_main (void)
{
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);
}
main_func *real_main = (main_func *) meth->ncode;
(*real_main) (args);
}

View File

@ -166,7 +166,8 @@ void _Jv_SetInitialHeapSize (const char *arg);
void _Jv_SetMaximumHeapSize (const char *arg);
extern "C" void JvRunMain (jclass klass, int argc, const char **argv);
void _Jv_RunMain (const char* name, int argc, const char **argv, bool is_jar);
void _Jv_RunMain (jclass klass, const char *name, int argc, const char **argv,
bool is_jar);
// This function is used to determine the hash code of an object.
inline jint
@ -276,7 +277,7 @@ _Jv_JNIEnv *_Jv_GetCurrentJNIEnv ();
void _Jv_SetCurrentJNIEnv (_Jv_JNIEnv *);
struct _Jv_JavaVM;
_Jv_JavaVM *_Jv_GetJavaVM ();
_Jv_JavaVM *_Jv_GetJavaVM ();
#ifdef ENABLE_JVMPI
#include "jvmpi.h"

View File

@ -109,8 +109,6 @@ public class Thread implements Runnable
public final native void resume ();
// This method exists only to avoid a warning from the C++ compiler.
private static final native void run_ (Object obj);
private final native void finish_ ();
// Check the thread's interrupted status. If clear_flag is true, the

View File

@ -87,7 +87,8 @@ jint
java::lang::Thread::countStackFrames (void)
{
// NOTE: This is deprecated in JDK 1.2.
JvFail ("java::lang::Thread::countStackFrames unimplemented");
throw new UnsupportedOperationException
(JvNewStringLatin1 ("Thread.countStackFrames unimplemented"));
return 0;
}
@ -102,7 +103,8 @@ java::lang::Thread::destroy (void)
{
// NOTE: This is marked as unimplemented in the JDK 1.2
// documentation.
JvFail ("java::lang::Thread::destroy unimplemented");
throw new UnsupportedOperationException
(JvNewStringLatin1 ("Thread.destroy unimplemented"));
}
void
@ -142,7 +144,8 @@ void
java::lang::Thread::resume (void)
{
checkAccess ();
JvFail ("java::lang::Thread::resume unimplemented");
throw new UnsupportedOperationException
(JvNewStringLatin1 ("Thread.resume unimplemented"));
}
void
@ -213,12 +216,11 @@ java::lang::Thread::finish_ ()
_Jv_MutexUnlock (&nt->join_mutex);
}
void
java::lang::Thread::run_ (jobject obj)
// Run once at thread startup, either when thread is attached or when
// _Jv_ThreadRun is called.
static void
_Jv_NotifyThreadStart (java::lang::Thread* thread)
{
java::lang::Thread *thread = (java::lang::Thread *) obj;
try
{
#ifdef ENABLE_JVMPI
if (_Jv_JVMPI_Notify_THREAD_START)
{
@ -272,7 +274,14 @@ java::lang::Thread::run_ (jobject obj)
_Jv_EnableGC ();
}
#endif
}
void
_Jv_ThreadRun (java::lang::Thread* thread)
{
try
{
_Jv_NotifyThreadStart (thread);
thread->run ();
}
catch (java::lang::Throwable *t)
@ -304,14 +313,14 @@ java::lang::Thread::start (void)
alive_flag = true;
startable_flag = false;
natThread *nt = (natThread *) data;
_Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &run_);
_Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun);
}
void
java::lang::Thread::stop (java::lang::Throwable *)
{
throw new UnsupportedOperationException
(JvNewStringLatin1 ("java::lang::Thread::stop unimplemented"));
(JvNewStringLatin1 ("Thread.stop unimplemented"));
}
void
@ -319,7 +328,7 @@ java::lang::Thread::suspend (void)
{
checkAccess ();
throw new UnsupportedOperationException
(JvNewStringLatin1 ("java::lang::Thread::suspend unimplemented"));
(JvNewStringLatin1 ("Thread.suspend unimplemented"));
}
static int nextThreadNumber = 0;
@ -373,6 +382,20 @@ _Jv_SetCurrentJNIEnv (JNIEnv *env)
((natThread *) t->data)->jni_env = env;
}
// Attach the current native thread to an existing (but unstarted) Thread
// object. Returns -1 on failure, 0 upon success.
jint
_Jv_AttachCurrentThread(java::lang::Thread* thread)
{
if (thread == NULL || thread->startable_flag == false)
return -1;
thread->startable_flag = false;
thread->alive_flag = true;
natThread *nt = (natThread *) thread->data;
_Jv_ThreadRegister (nt->thread);
return 0;
}
java::lang::Thread*
_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
{
@ -382,10 +405,8 @@ _Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
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);
_Jv_AttachCurrentThread (thread);
_Jv_NotifyThreadStart (thread);
return thread;
}

View File

@ -90,14 +90,12 @@ property_pair *_Jv_Environment_Properties;
#endif
// The name of this executable.
static char * _Jv_execName;
static char *_Jv_execName;
// Stash the argv pointer to benefit native libraries that need it.
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);
@ -643,7 +641,7 @@ JvConvertArgv (int argc, const char **argv)
// it will only scan the qthreads stacks.
// Command line arguments.
static jobject arg_vec;
static JArray<jstring> *arg_vec;
// The primary thread.
static java::lang::Thread *main_thread;
@ -690,7 +688,6 @@ win32_exception_handler (LPEXCEPTION_POINTERS e)
#endif
#ifndef DISABLE_GETENV_PROPERTIES
static char *
@ -885,93 +882,15 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
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_RunMain (jclass klass, const char *name, int argc, const char **argv,
bool is_jar)
{
_Jv_argv = argv;
_Jv_argc = argc;
_Jv_CreateJavaVM (NULL);
java::lang::Runtime *runtime = NULL;
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
sprintf (exec_name, "/proc/%d/exe", getpid ());
@ -980,68 +899,51 @@ JvRunMain (jclass klass, int argc, const char **argv)
_Jv_ThisExecutable (argv[0]);
#endif
// Get the Runtime here. We want to initialize it before searching
// for `main'; that way it will be set up if `main' is a JNI method.
java::lang::Runtime *rtime = java::lang::Runtime::getRuntime ();
try
{
_Jv_CreateJavaVM (NULL);
main_thread = _Jv_AttachCurrentThread (JvNewStringLatin1 ("main"), NULL);
arg_vec = JvConvertArgv (argc - 1, argv + 1);
runFirst (klass, arg_vec);
// Get the Runtime here. We want to initialize it before searching
// for `main'; that way it will be set up if `main' is a JNI method.
runtime = java::lang::Runtime::getRuntime ();
arg_vec = JvConvertArgv (argc - 1, argv + 1);
if (klass)
main_thread = new gnu::gcj::runtime::FirstThread (klass, arg_vec);
else
main_thread = new gnu::gcj::runtime::FirstThread
(JvNewStringLatin1 (name), arg_vec, is_jar);
if (is_jar)
{
// We need a new ClassLoader because the classpath must be the
// jar file only. The easiest way to do this is to lose our
// reference to the previous classloader.
_Jv_Jar_Class_Path = strdup (name);
java::lang::ClassLoader::system = NULL;
}
}
catch (java::lang::Throwable *t)
{
java::lang::System::err->println (JvNewStringLatin1
("Exception during runtime initialization"));
t->printStackTrace();
runtime->exit (1);
}
_Jv_AttachCurrentThread (main_thread);
_Jv_ThreadRun (main_thread);
_Jv_ThreadWait ();
int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
rtime->_exit (status);
runtime->exit (status);
}
void
_Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar)
JvRunMain (jclass klass, int argc, const char **argv)
{
jstring class_name;
_Jv_CreateJavaVM (NULL);
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
sprintf (exec_name, "/proc/%d/exe", getpid ());
_Jv_ThisExecutable (exec_name);
#endif
// Get the Runtime here. We want to initialize it before searching
// for `main'; that way it will be set up if `main' is a JNI method.
java::lang::Runtime *rtime = java::lang::Runtime::getRuntime ();
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.getMain.
_Jv_Jar_Class_Path = strdup (name);
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
// reference to the previous classloader.
java::lang::ClassLoader::system = NULL;
}
else
class_name = JvNewStringLatin1 (name);
arg_vec = JvConvertArgv (argc - 1, argv + 1);
if (class_name)
{
runFirst(java::lang::Class::forName (class_name), arg_vec);
_Jv_ThreadWait ();
}
int status = (int) java::lang::ThreadGroup::had_uncaught_exception;
rtime->exit (status);
_Jv_RunMain (klass, NULL, argc, argv, false);
}