source: trunk/gcc/libjava/java/lang/natRuntime.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.6 KB
Line 
1// natRuntime.cc - Implementation of native side of Runtime class.
2
3/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11#include <config.h>
12#include <platform.h>
13
14#include <stdlib.h>
15
16#include <gcj/cni.h>
17#include <jvm.h>
18#include <java-props.h>
19#include <java/lang/Long.h>
20#include <java/lang/Runtime.h>
21#include <java/lang/UnknownError.h>
22#include <java/lang/UnsatisfiedLinkError.h>
23#include <gnu/gcj/runtime/FileDeleter.h>
24#include <gnu/gcj/runtime/FinalizerThread.h>
25#include <java/io/File.h>
26#include <java/util/Properties.h>
27#include <java/util/TimeZone.h>
28#include <java/lang/StringBuffer.h>
29#include <java/lang/Process.h>
30#include <java/lang/ConcreteProcess.h>
31#include <java/lang/ClassLoader.h>
32#include <gnu/gcj/runtime/StackTrace.h>
33#include <java/lang/ArrayIndexOutOfBoundsException.h>
34
35#include <jni.h>
36
37#ifdef HAVE_PWD_H
38#include <pwd.h>
39#endif
40#include <errno.h>
41
42#ifdef HAVE_UNAME
43#include <sys/utsname.h>
44#endif
45
46#ifdef HAVE_LOCALE_H
47#include <locale.h>
48#endif
49
50#ifdef HAVE_LANGINFO_H
51#include <langinfo.h>
52#endif
53
54
55
56
57#ifdef USE_LTDL
58#include <ltdl.h>
59
60/* FIXME: we don't always need this. The next libtool will let us use
61 AC_LTDL_PREOPEN to see if we do. */
62extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
63
64// We keep track of all the libraries loaded by this application. For
65// now we use them to look up symbols for JNI. `libraries_size' holds
66// the total size of the buffer. `libraries_count' is the number of
67// items which are in use.
68static int libraries_size;
69static int libraries_count;
70static lt_dlhandle *libraries;
71
72static void
73add_library (lt_dlhandle lib)
74{
75 if (libraries_count == libraries_size)
76 {
77 int ns = libraries_size * 2;
78 if (ns == 0)
79 ns = 10;
80 lt_dlhandle *n = (lt_dlhandle *) _Jv_Malloc (ns * sizeof (lt_dlhandle));
81 if (libraries)
82 {
83 memcpy (n, libraries, libraries_size * sizeof (lt_dlhandle));
84 _Jv_Free (libraries);
85 }
86 libraries = n;
87 libraries_size = ns;
88 for (int i = libraries_count; i < libraries_size; ++i)
89 libraries[i] = NULL;
90 }
91
92 libraries[libraries_count++] = lib;
93}
94
95void *
96_Jv_FindSymbolInExecutable (const char *symname)
97{
98 for (int i = 0; i < libraries_count; ++i)
99 {
100 void *r = lt_dlsym (libraries[i], symname);
101 if (r)
102 return r;
103 }
104
105 return NULL;
106}
107
108void
109_Jv_SetDLLSearchPath (const char *path)
110{
111 lt_dlsetsearchpath (path);
112}
113
114#else
115
116void *
117_Jv_FindSymbolInExecutable (const char *)
118{
119 return NULL;
120}
121
122void
123_Jv_SetDLLSearchPath (const char *)
124{
125 // Nothing.
126}
127
128#endif /* USE_LTDL */
129
130
131
132
133void
134java::lang::Runtime::exitInternal (jint status)
135{
136 // Make status right for Unix. This is perhaps strange.
137 if (status < 0 || status > 255)
138 status = 255;
139
140 if (finalizeOnExit)
141 _Jv_RunAllFinalizers ();
142
143 // Delete all files registered with File.deleteOnExit()
144 gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
145
146 ::exit (status);
147}
148
149jlong
150java::lang::Runtime::freeMemory (void)
151{
152 return _Jv_GCFreeMemory ();
153}
154
155void
156java::lang::Runtime::gc (void)
157{
158 _Jv_RunGC ();
159}
160
161void
162java::lang::Runtime::_load (jstring path, jboolean do_search)
163{
164 JvSynchronize sync (this);
165 using namespace java::lang;
166#ifdef USE_LTDL
167 jint len = _Jv_GetStringUTFLength (path);
168 char buf[len + 1 + strlen (_Jv_platform_solib_prefix)
169 + strlen (_Jv_platform_solib_suffix)];
170 int offset = 0;
171 if (do_search)
172 {
173 strcpy (buf, _Jv_platform_solib_prefix);
174 offset = strlen (_Jv_platform_solib_prefix);
175 }
176 jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
177 buf[offset + total] = '\0';
178
179 char *lib_name = buf;
180
181 if (do_search)
182 {
183 ClassLoader *sys = ClassLoader::getSystemClassLoader();
184 ClassLoader *look = NULL;
185 gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(10);
186 try
187 {
188 for (int i = 0; i < 10; ++i)
189 {
190 jclass klass = t->classAt(i);
191 if (klass != NULL)
192 {
193 ClassLoader *loader = klass->getClassLoaderInternal();
194 if (loader != NULL && loader != sys)
195 {
196 look = loader;
197 break;
198 }
199 }
200 }
201 }
202 catch (::java::lang::ArrayIndexOutOfBoundsException *e)
203 {
204 }
205
206 if (look != NULL)
207 {
208 // Don't include solib prefix in string passed to
209 // findLibrary.
210 jstring name = look->findLibrary(JvNewStringUTF(&buf[offset]));
211 if (name != NULL)
212 {
213 len = _Jv_GetStringUTFLength (name);
214 lib_name = (char *) _Jv_AllocBytes(len + 1);
215 total = JvGetStringUTFRegion (name, 0,
216 name->length(), lib_name);
217 lib_name[total] = '\0';
218 // Don't append suffixes any more; we have the full file
219 // name.
220 do_search = false;
221 }
222 }
223 }
224
225 lt_dlhandle h;
226 // FIXME: make sure path is absolute.
227 {
228 // Synchronize on java.lang.Class. This is to protect the class chain from
229 // concurrent modification by class registration calls which may be run
230 // during the dlopen().
231 JvSynchronize sync (&java::lang::Class::class$);
232 h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name);
233 }
234 if (h == NULL)
235 {
236 const char *msg = lt_dlerror ();
237 jstring str = path->concat (JvNewStringLatin1 (": "));
238 str = str->concat (JvNewStringLatin1 (msg));
239 throw new UnsatisfiedLinkError (str);
240 }
241
242 add_library (h);
243
244 void *onload = lt_dlsym (h, "JNI_OnLoad");
245
246#ifdef WIN32
247 // On Win32, JNI_OnLoad is an "stdcall" function taking two pointers
248 // (8 bytes) as arguments. It could also have been exported as
249 // "JNI_OnLoad@8" (MinGW) or "_JNI_OnLoad@8" (MSVC).
250 if (onload == NULL)
251 {
252 onload = lt_dlsym (h, "JNI_OnLoad@8");
253 if (onload == NULL)
254 onload = lt_dlsym (h, "_JNI_OnLoad@8");
255 }
256#endif /* WIN32 */
257
258 if (onload != NULL)
259 {
260 JavaVM *vm = _Jv_GetJavaVM ();
261 if (vm == NULL)
262 {
263 // FIXME: what?
264 return;
265 }
266 jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
267 if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
268 && vers != JNI_VERSION_1_4)
269 {
270 // FIXME: unload the library.
271 throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
272 }
273 }
274#else
275 throw new UnknownError
276 (JvNewStringLatin1 (do_search
277 ? "Runtime.loadLibrary not implemented"
278 : "Runtime.load not implemented"));
279#endif /* USE_LTDL */
280}
281
282jboolean
283java::lang::Runtime::loadLibraryInternal (jstring lib)
284{
285 JvSynchronize sync (this);
286 using namespace java::lang;
287#ifdef USE_LTDL
288 jint len = _Jv_GetStringUTFLength (lib);
289 char buf[len + 1];
290 jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
291 buf[total] = '\0';
292 // FIXME: make sure path is absolute.
293 lt_dlhandle h = lt_dlopenext (buf);
294 if (h != NULL)
295 add_library (h);
296 return h != NULL;
297#else
298 return false;
299#endif /* USE_LTDL */
300}
301
302void
303java::lang::Runtime::init (void)
304{
305#ifdef USE_LTDL
306 lt_dlinit ();
307 lt_dlhandle self = lt_dlopen (NULL);
308 if (self != NULL)
309 add_library (self);
310#endif
311}
312
313void
314java::lang::Runtime::runFinalization (void)
315{
316 gnu::gcj::runtime::FinalizerThread::finalizerReady ();
317}
318
319jlong
320java::lang::Runtime::totalMemory (void)
321{
322 return _Jv_GCTotalMemory ();
323}
324
325jlong
326java::lang::Runtime::maxMemory (void)
327{
328 // We don't have a maximum. FIXME: we might if we ask the GC for
329 // one.
330 return Long::MAX_VALUE;
331}
332
333void
334java::lang::Runtime::traceInstructions (jboolean)
335{
336 // Do nothing.
337}
338
339void
340java::lang::Runtime::traceMethodCalls (jboolean)
341{
342 // Do nothing.
343}
344
345#if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
346 && defined (HAVE_NL_LANGINFO)
347
348static char *
349file_encoding ()
350{
351 setlocale (LC_CTYPE, "");
352 char *e = nl_langinfo (CODESET);
353 if (e == NULL || *e == '\0')
354 e = "8859_1";
355 return e;
356}
357
358#define DEFAULT_FILE_ENCODING file_encoding ()
359
360#endif
361
362#ifndef DEFAULT_FILE_ENCODING
363#define DEFAULT_FILE_ENCODING "8859_1"
364#endif
365
366static char *default_file_encoding = DEFAULT_FILE_ENCODING;
367
368#if HAVE_GETPWUID_R
369/* Use overload resolution to find out the signature of getpwuid_r. */
370
371 /* This is Posix getpwuid_r. */
372template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
373static inline int
374getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
375 T_buf *buf_r, T_len len_r,
376 T_passwd **pwd_entry_ptr),
377 uid_t user_id, struct passwd *pwd_r,
378 char *buf_r, size_t len_r, struct passwd **pwd_entry)
379{
380 return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
381}
382
383/* This is used on HPUX 10.20 */
384template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
385static inline int
386getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
387 T_buf *buf_r, T_len len_r),
388 uid_t user_id, struct passwd *pwd_r,
389 char *buf_r, size_t len_r, struct passwd **pwd_entry)
390{
391 return getpwuid_r (user_id, pwd_r, buf_r, len_r);
392}
393
394/* This is used on IRIX 5.2. */
395template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
396static inline int
397getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
398 T_buf *buf_r, T_len len_r),
399 uid_t user_id, struct passwd *pwd_r,
400 char *buf_r, size_t len_r, struct passwd **pwd_entry)
401{
402 *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
403 return (*pwd_entry == NULL) ? errno : 0;
404}
405#endif
406
407void
408java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
409{
410 // A convenience define.
411#define SET(Prop,Val) \
412 newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
413
414 // A mixture of the Java Product Versioning Specification
415 // (introduced in 1.2), and earlier versioning properties.
416 SET ("java.version", GCJVERSION);
417 SET ("java.vendor", "Free Software Foundation, Inc.");
418 SET ("java.vendor.url", "http://gcc.gnu.org/java/");
419 SET ("java.class.version", "46.0");
420 SET ("java.vm.specification.version", "1.0");
421 SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
422 SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
423 SET ("java.vm.version", __VERSION__);
424 SET ("java.vm.vendor", "Free Software Foundation, Inc.");
425 SET ("java.vm.name", "GNU libgcj");
426 SET ("java.specification.version", "1.3");
427 SET ("java.specification.name", "Java(tm) Platform API Specification");
428 SET ("java.specification.vendor", "Sun Microsystems Inc.");
429
430 char value[100];
431#define NAME "GNU libgcj "
432 strcpy (value, NAME);
433 strncpy (value + sizeof (NAME) - 1, __VERSION__,
434 sizeof(value) - sizeof(NAME));
435 value[sizeof (value) - 1] = '\0';
436 jstring version = JvNewStringLatin1 (value);
437 newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
438 newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
439
440 // This definition is rather arbitrary: we choose $(prefix). In
441 // part we do this because most people specify only --prefix and
442 // nothing else when installing gcj. Plus, people are free to
443 // redefine `java.home' with `-D' if necessary.
444 SET ("java.home", PREFIX);
445 SET ("gnu.classpath.home", PREFIX);
446
447 SET ("file.encoding", default_file_encoding);
448
449#ifdef HAVE_UNAME
450 struct utsname u;
451 if (! uname (&u))
452 {
453 SET ("os.name", u.sysname);
454 SET ("os.arch", u.machine);
455 SET ("os.version", u.release);
456 }
457 else
458 {
459 SET ("os.name", "unknown");
460 SET ("os.arch", "unknown");
461 SET ("os.version", "unknown");
462 }
463#endif /* HAVE_UNAME */
464
465#ifndef NO_GETUID
466#ifdef HAVE_PWD_H
467 uid_t user_id = getuid ();
468 struct passwd *pwd_entry;
469
470#ifdef HAVE_GETPWUID_R
471 struct passwd pwd_r;
472 size_t len_r = 200;
473 char *buf_r = (char *) _Jv_AllocBytes (len_r);
474
475 while (buf_r != NULL)
476 {
477 int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
478 buf_r, len_r, &pwd_entry);
479 if (r == 0)
480 break;
481 else if (r != ERANGE)
482 {
483 pwd_entry = NULL;
484 break;
485 }
486 len_r *= 2;
487 buf_r = (char *) _Jv_AllocBytes (len_r);
488 }
489#else
490 pwd_entry = getpwuid (user_id);
491#endif /* HAVE_GETPWUID_R */
492
493 if (pwd_entry != NULL)
494 {
495 SET ("user.name", pwd_entry->pw_name);
496 SET ("user.home", pwd_entry->pw_dir);
497 }
498#endif /* HAVE_PWD_H */
499#endif /* NO_GETUID */
500
501#ifdef HAVE_GETCWD
502#ifdef HAVE_UNISTD_H
503 /* Use getcwd to set "user.dir". */
504 int buflen = 250;
505 char *buffer = (char *) malloc (buflen);
506 while (buffer != NULL)
507 {
508 if (getcwd (buffer, buflen) != NULL)
509 {
510 SET ("user.dir", buffer);
511 break;
512 }
513 if (errno != ERANGE)
514 break;
515 buflen = 2 * buflen;
516 buffer = (char *) realloc (buffer, buflen);
517 }
518 if (buffer != NULL)
519 free (buffer);
520#endif /* HAVE_UNISTD_H */
521#endif /* HAVE_GETCWD */
522
523 // Set user locale properties based on setlocale()
524#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
525 // We let the user choose the locale. However, since Java differs
526 // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
527 // Java locale. We can't use LC_ALL because it might return a full
528 // list of all the settings. If we don't have LC_MESSAGES then we
529 // just default to `en_US'.
530 setlocale (LC_ALL, "");
531 char *locale = setlocale (LC_MESSAGES, "");
532 if (locale && strlen (locale) >= 2)
533 {
534 char buf[3];
535 buf[2] = '\0';
536 // copy the first two chars to user.language
537 strncpy (buf, locale, 2);
538 SET ("user.language", buf);
539 // if the next char is a '_', copy the two after that to user.region
540 locale += 2;
541 if (locale[0] == '_')
542 {
543 locale++;
544 strncpy (buf, locale, 2);
545 SET ("user.region", buf);
546 }
547 }
548 else
549#endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
550 {
551 SET ("user.language", "en");
552 SET ("user.region", "US");
553 }
554
555 // Set some properties according to whatever was compiled in with
556 // `-D'.
557 for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
558 {
559 const char *s, *p;
560 // Find the `='.
561 for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
562 ;
563 jstring name = JvNewStringLatin1 (p, s - p);
564 jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
565 newprops->put (name, val);
566 }
567
568 // Set the system properties from the user's environment.
569#ifndef DISABLE_GETENV_PROPERTIES
570 if (_Jv_Environment_Properties)
571 {
572 size_t i = 0;
573
574 while (_Jv_Environment_Properties[i].key)
575 {
576 SET (_Jv_Environment_Properties[i].key,
577 _Jv_Environment_Properties[i].value);
578 i++;
579 }
580 }
581#endif
582
583 if (_Jv_Jar_Class_Path)
584 newprops->put(JvNewStringLatin1 ("java.class.path"),
585 JvNewStringLatin1 (_Jv_Jar_Class_Path));
586 else
587 {
588 // FIXME: find libgcj.zip and append its path?
589 char *classpath = ::getenv("CLASSPATH");
590 jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
591 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
592
593 if (classpath)
594 {
595 sb->append (JvNewStringLatin1 (classpath));
596#ifdef WIN32
597 sb->append ((jchar) ';');
598#else
599 sb->append ((jchar) ':');
600#endif
601 }
602 if (cp != NULL)
603 sb->append (cp);
604 else
605 sb->append ((jchar) '.');
606
607 newprops->put(JvNewStringLatin1 ("java.class.path"),
608 sb->toString ());
609 }
610
611 // The name used to invoke this process (argv[0] in C).
612 SET ("gnu.gcj.progname", _Jv_GetSafeArg (0));
613
614 // Allow platform specific settings and overrides.
615 _Jv_platform_initProperties (newprops);
616
617 // If java.library.path is set, tell libltdl so we search the new
618 // directories as well. FIXME: does this work properly on Windows?
619 String *path = newprops->getProperty(JvNewStringLatin1("java.library.path"));
620 if (path)
621 {
622 char *val = (char *) _Jv_Malloc (JvGetStringUTFLength (path) + 1);
623 jsize total = JvGetStringUTFRegion (path, 0, path->length(), val);
624 val[total] = '\0';
625 _Jv_SetDLLSearchPath (val);
626 _Jv_Free (val);
627 }
628 else
629 {
630 // Set a value for user code to see.
631 // FIXME: JDK sets this to the actual path used, including
632 // LD_LIBRARY_PATH, etc.
633 SET ("java.library.path", "");
634 }
635}
636
637java::lang::Process *
638java::lang::Runtime::execInternal (jstringArray cmd,
639 jstringArray env,
640 java::io::File *dir)
641{
642 return new java::lang::ConcreteProcess (cmd, env, dir);
643}
644
645jint
646java::lang::Runtime::availableProcessors (void)
647{
648 // FIXME: find the real value.
649 return 1;
650}
651
652jstring
653java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
654{
655 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
656 sb->append(pathname);
657 if (pathname->length() > 0)
658 {
659 // FIXME: use platform function here.
660#ifdef WIN32
661 sb->append ((jchar) '\\');
662#else
663 sb->append ((jchar) '/');
664#endif
665 }
666
667 sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix));
668 sb->append(libname);
669 sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix));
670
671 return sb->toString();
672}
Note: See TracBrowser for help on using the repository browser.