Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / lang / natRuntime.cc
blob31f9b90b6fa4d3a6b4e1b104ae2e5f05370aec9d
1 // natRuntime.cc - Implementation of native side of Runtime class.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
12 #include <platform.h>
14 #include <stdlib.h>
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>
35 #include <jni.h>
37 #ifdef HAVE_PWD_H
38 #include <pwd.h>
39 #endif
40 #include <errno.h>
42 #ifdef HAVE_UNAME
43 #include <sys/utsname.h>
44 #endif
46 #ifdef HAVE_LOCALE_H
47 #include <locale.h>
48 #endif
50 #ifdef HAVE_LANGINFO_H
51 #include <langinfo.h>
52 #endif
56 #ifdef USE_LTDL
57 #include <ltdl.h>
59 /* FIXME: we don't always need this. The next libtool will let us use
60 AC_LTDL_PREOPEN to see if we do. */
61 extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
63 struct lookup_data
65 const char *symname;
66 void *result;
69 static int
70 find_symbol (lt_dlhandle handle, lt_ptr data)
72 lookup_data *ld = (lookup_data *) data;
73 ld->result = lt_dlsym (handle, ld->symname);
74 return ld->result != NULL;
77 void *
78 _Jv_FindSymbolInExecutable (const char *symname)
80 lookup_data data;
81 data.symname = symname;
82 data.result = NULL;
83 lt_dlforeach (find_symbol, (lt_ptr) &data);
84 return data.result;
87 void
88 _Jv_SetDLLSearchPath (const char *path)
90 lt_dlsetsearchpath (path);
93 #else
95 void *
96 _Jv_FindSymbolInExecutable (const char *)
98 return NULL;
101 void
102 _Jv_SetDLLSearchPath (const char *)
104 // Nothing.
107 #endif /* USE_LTDL */
111 void
112 java::lang::Runtime::exitInternal (jint status)
114 // Make status right for Unix. This is perhaps strange.
115 if (status < 0 || status > 255)
116 status = 255;
118 if (finalizeOnExit)
119 _Jv_RunAllFinalizers ();
121 // Delete all files registered with File.deleteOnExit()
122 gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
124 ::exit (status);
127 jlong
128 java::lang::Runtime::freeMemory (void)
130 return _Jv_GCFreeMemory ();
133 void
134 java::lang::Runtime::gc (void)
136 _Jv_RunGC ();
139 #ifdef USE_LTDL
140 // List of names for JNI_OnLoad.
141 static const char *onload_names[] = _Jv_platform_onload_names;
142 #endif
144 void
145 java::lang::Runtime::_load (jstring path, jboolean do_search)
147 JvSynchronize sync (this);
148 using namespace java::lang;
149 #ifdef USE_LTDL
150 jint len = _Jv_GetStringUTFLength (path);
151 char buf[len + 1 + strlen (_Jv_platform_solib_prefix)
152 + strlen (_Jv_platform_solib_suffix)];
153 int offset = 0;
154 if (do_search)
156 strcpy (buf, _Jv_platform_solib_prefix);
157 offset = strlen (_Jv_platform_solib_prefix);
159 jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
160 buf[offset + total] = '\0';
162 char *lib_name = buf;
164 if (do_search)
166 ClassLoader *sys = ClassLoader::getSystemClassLoader();
167 ClassLoader *look = NULL;
168 gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(10);
171 for (int i = 0; i < 10; ++i)
173 jclass klass = t->classAt(i);
174 if (klass != NULL)
176 ClassLoader *loader = klass->getClassLoaderInternal();
177 if (loader != NULL && loader != sys)
179 look = loader;
180 break;
185 catch (::java::lang::ArrayIndexOutOfBoundsException *e)
189 if (look != NULL)
191 // Don't include solib prefix in string passed to
192 // findLibrary.
193 jstring name = look->findLibrary(JvNewStringUTF(&buf[offset]));
194 if (name != NULL)
196 len = _Jv_GetStringUTFLength (name);
197 lib_name = (char *) _Jv_AllocBytes(len + 1);
198 total = JvGetStringUTFRegion (name, 0,
199 name->length(), lib_name);
200 lib_name[total] = '\0';
201 // Don't append suffixes any more; we have the full file
202 // name.
203 do_search = false;
208 lt_dlhandle h;
209 // FIXME: make sure path is absolute.
211 // Synchronize on java.lang.Class. This is to protect the class chain from
212 // concurrent modification by class registration calls which may be run
213 // during the dlopen().
214 JvSynchronize sync (&java::lang::Class::class$);
215 h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name);
217 if (h == NULL)
219 const char *msg = lt_dlerror ();
220 jstring str = JvNewStringLatin1 (lib_name);
221 str = str->concat (JvNewStringLatin1 (": "));
222 str = str->concat (JvNewStringLatin1 (msg));
223 throw new UnsatisfiedLinkError (str);
226 // Search for JNI_OnLoad function.
227 void *onload = NULL;
228 const char **name = onload_names;
229 while (*name != NULL)
231 onload = lt_dlsym (h, *name);
232 if (onload != NULL)
233 break;
234 ++name;
237 if (onload != NULL)
239 JavaVM *vm = _Jv_GetJavaVM ();
240 if (vm == NULL)
242 // FIXME: what?
243 return;
245 jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
246 if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
247 && vers != JNI_VERSION_1_4)
249 // FIXME: unload the library.
250 throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
253 #else
254 throw new UnknownError
255 (JvNewStringLatin1 (do_search
256 ? "Runtime.loadLibrary not implemented"
257 : "Runtime.load not implemented"));
258 #endif /* USE_LTDL */
261 jboolean
262 java::lang::Runtime::loadLibraryInternal (jstring lib)
264 JvSynchronize sync (this);
265 using namespace java::lang;
266 #ifdef USE_LTDL
267 jint len = _Jv_GetStringUTFLength (lib);
268 char buf[len + 1];
269 jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
270 buf[total] = '\0';
271 // FIXME: make sure path is absolute.
272 lt_dlhandle h = lt_dlopenext (buf);
273 return h != NULL;
274 #else
275 return false;
276 #endif /* USE_LTDL */
279 void
280 java::lang::Runtime::init (void)
282 #ifdef USE_LTDL
283 lt_dlinit ();
284 // Make sure self is opened.
285 lt_dlopen (NULL);
286 #endif
289 void
290 java::lang::Runtime::runFinalization (void)
292 gnu::gcj::runtime::FinalizerThread::finalizerReady ();
295 jlong
296 java::lang::Runtime::totalMemory (void)
298 return _Jv_GCTotalMemory ();
301 jlong
302 java::lang::Runtime::maxMemory (void)
304 // We don't have a maximum. FIXME: we might if we ask the GC for
305 // one.
306 return Long::MAX_VALUE;
309 void
310 java::lang::Runtime::traceInstructions (jboolean)
312 // Do nothing.
315 void
316 java::lang::Runtime::traceMethodCalls (jboolean)
318 // Do nothing.
321 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
322 && defined (HAVE_NL_LANGINFO)
324 static char *
325 file_encoding ()
327 setlocale (LC_CTYPE, "");
328 char *e = nl_langinfo (CODESET);
329 if (e == NULL || *e == '\0')
330 e = "8859_1";
331 return e;
334 #define DEFAULT_FILE_ENCODING file_encoding ()
336 #endif
338 #ifndef DEFAULT_FILE_ENCODING
339 #define DEFAULT_FILE_ENCODING "8859_1"
340 #endif
342 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
344 #if HAVE_GETPWUID_R
345 /* Use overload resolution to find out the signature of getpwuid_r. */
347 /* This is Posix getpwuid_r. */
348 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
349 static inline int
350 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
351 T_buf *buf_r, T_len len_r,
352 T_passwd **pwd_entry_ptr),
353 uid_t user_id, struct passwd *pwd_r,
354 char *buf_r, size_t len_r, struct passwd **pwd_entry)
356 return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
359 /* This is used on HPUX 10.20 */
360 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
361 static inline int
362 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
363 T_buf *buf_r, T_len len_r),
364 uid_t user_id, struct passwd *pwd_r,
365 char *buf_r, size_t len_r, struct passwd **pwd_entry)
367 return getpwuid_r (user_id, pwd_r, buf_r, len_r);
370 /* This is used on IRIX 5.2. */
371 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
372 static inline int
373 getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
374 T_buf *buf_r, T_len len_r),
375 uid_t user_id, struct passwd *pwd_r,
376 char *buf_r, size_t len_r, struct passwd **pwd_entry)
378 *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
379 return (*pwd_entry == NULL) ? errno : 0;
381 #endif
383 void
384 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
386 // A convenience define.
387 #define SET(Prop,Val) \
388 newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
390 // A mixture of the Java Product Versioning Specification
391 // (introduced in 1.2), and earlier versioning properties. Some
392 // programs rely on seeing values that they expect, so we claim to
393 // be a 1.4-ish VM for their sake.
394 SET ("java.version", "1.4.2");
395 SET ("java.runtime.version", "1.4.2");
396 SET ("java.vendor", "Free Software Foundation, Inc.");
397 SET ("java.vendor.url", "http://gcc.gnu.org/java/");
398 SET ("java.class.version", "46.0");
399 SET ("java.vm.specification.version", "1.0");
400 SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
401 SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
402 SET ("java.vm.version", __VERSION__);
403 SET ("java.vm.vendor", "Free Software Foundation, Inc.");
404 SET ("java.vm.name", "GNU libgcj");
405 SET ("java.specification.version", "1.4");
406 SET ("java.specification.name", "Java(tm) Platform API Specification");
407 SET ("java.specification.vendor", "Sun Microsystems Inc.");
409 char value[100];
410 #define NAME "GNU libgcj "
411 strcpy (value, NAME);
412 strncpy (value + sizeof (NAME) - 1, __VERSION__,
413 sizeof(value) - sizeof(NAME));
414 value[sizeof (value) - 1] = '\0';
415 jstring version = JvNewStringLatin1 (value);
416 newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
417 newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
419 // This definition is rather arbitrary: we choose $(prefix). In
420 // part we do this because most people specify only --prefix and
421 // nothing else when installing gcj. Plus, people are free to
422 // redefine `java.home' with `-D' if necessary.
423 SET ("java.home", PREFIX);
424 SET ("gnu.classpath.home", PREFIX);
425 // This is set to $(libdir) because we use this to find .security
426 // files at runtime.
427 char val2[sizeof ("file://") + sizeof (LIBDIR) + 1];
428 strcpy (val2, "file://");
429 strcat (val2, LIBDIR);
430 SET ("gnu.classpath.home.url", val2);
432 SET ("file.encoding", default_file_encoding);
434 #ifdef HAVE_UNAME
435 struct utsname u;
436 if (! uname (&u))
438 SET ("os.name", u.sysname);
439 SET ("os.version", u.release);
441 // Normalize x86 architecture names to "i386" (except on Windows, which
442 // is handled in win32.cc).
443 if (u.machine[0] == 'i'
444 && u.machine[1] != 0
445 && u.machine[2] == '8'
446 && u.machine[3] == '6'
447 && u.machine[4] == 0)
448 SET ("os.arch", "i386");
449 else
450 SET ("os.arch", u.machine);
452 else
454 SET ("os.name", "unknown");
455 SET ("os.arch", "unknown");
456 SET ("os.version", "unknown");
458 #endif /* HAVE_UNAME */
460 #ifndef NO_GETUID
461 #ifdef HAVE_PWD_H
462 uid_t user_id = getuid ();
463 struct passwd *pwd_entry;
465 #ifdef HAVE_GETPWUID_R
466 struct passwd pwd_r;
467 size_t len_r = 200;
468 char *buf_r = (char *) _Jv_AllocBytes (len_r);
470 while (buf_r != NULL)
472 int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
473 buf_r, len_r, &pwd_entry);
474 if (r == 0)
475 break;
476 else if (r != ERANGE)
478 pwd_entry = NULL;
479 break;
481 len_r *= 2;
482 buf_r = (char *) _Jv_AllocBytes (len_r);
484 #else
485 pwd_entry = getpwuid (user_id);
486 #endif /* HAVE_GETPWUID_R */
488 if (pwd_entry != NULL)
490 SET ("user.name", pwd_entry->pw_name);
491 SET ("user.home", pwd_entry->pw_dir);
493 #endif /* HAVE_PWD_H */
494 #endif /* NO_GETUID */
496 #ifdef HAVE_GETCWD
497 #ifdef HAVE_UNISTD_H
498 /* Use getcwd to set "user.dir". */
499 int buflen = 250;
500 char *buffer = (char *) malloc (buflen);
501 while (buffer != NULL)
503 if (getcwd (buffer, buflen) != NULL)
505 SET ("user.dir", buffer);
506 break;
508 if (errno != ERANGE)
509 break;
510 buflen = 2 * buflen;
511 buffer = (char *) realloc (buffer, buflen);
513 if (buffer != NULL)
514 free (buffer);
515 #endif /* HAVE_UNISTD_H */
516 #endif /* HAVE_GETCWD */
518 // Set user locale properties based on setlocale()
519 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
520 // We let the user choose the locale. However, since Java differs
521 // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
522 // Java locale. We can't use LC_ALL because it might return a full
523 // list of all the settings. If we don't have LC_MESSAGES then we
524 // just default to `en_US'.
525 setlocale (LC_ALL, "");
526 char *locale = setlocale (LC_MESSAGES, "");
527 if (locale && strlen (locale) >= 2)
529 char buf[3];
530 buf[2] = '\0';
531 // copy the first two chars to user.language
532 strncpy (buf, locale, 2);
533 SET ("user.language", buf);
534 // if the next char is a '_', copy the two after that to user.region
535 locale += 2;
536 if (locale[0] == '_')
538 locale++;
539 strncpy (buf, locale, 2);
540 SET ("user.region", buf);
543 else
544 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
546 SET ("user.language", "en");
547 SET ("user.region", "US");
550 // The java extensions directory.
551 SET ("java.ext.dirs", JAVA_EXT_DIRS);
553 // The path to libgcj's boot classes
554 SET ("sun.boot.class.path", BOOT_CLASS_PATH);
556 // Set some properties according to whatever was compiled in with
557 // `-D'. Important: after this point, the only properties that
558 // should be set are those which either the user cannot meaningfully
559 // override, or which augment whatever value the user has provided.
560 for (int i = 0; i < _Jv_Properties_Count; ++i)
562 const char *s, *p;
563 // Find the `='.
564 for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
566 jstring name = JvNewStringLatin1 (p, s - p);
567 jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
568 newprops->put (name, val);
571 // Set the system properties from the user's environment.
572 #ifndef DISABLE_GETENV_PROPERTIES
573 if (_Jv_Environment_Properties)
575 size_t i = 0;
577 while (_Jv_Environment_Properties[i].key)
579 SET (_Jv_Environment_Properties[i].key,
580 _Jv_Environment_Properties[i].value);
581 i++;
584 #endif
586 if (_Jv_Jar_Class_Path)
587 newprops->put(JvNewStringLatin1 ("java.class.path"),
588 JvNewStringLatin1 (_Jv_Jar_Class_Path));
589 else
591 // FIXME: find libgcj.zip and append its path?
592 char *classpath = ::getenv("CLASSPATH");
593 jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
594 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
596 if (classpath)
598 sb->append (JvNewStringLatin1 (classpath));
599 sb->append (_Jv_platform_path_separator);
601 if (cp != NULL)
602 sb->append (cp);
603 else
604 sb->append ((jchar) '.');
606 newprops->put(JvNewStringLatin1 ("java.class.path"),
607 sb->toString ());
610 // The name used to invoke this process (argv[0] in C).
611 SET ("gnu.gcj.progname", _Jv_GetSafeArg (0));
613 // Allow platform specific settings and overrides.
614 _Jv_platform_initProperties (newprops);
616 // If java.library.path is set, tell libltdl so we search the new
617 // directories as well. FIXME: does this work properly on Windows?
618 String *path = newprops->getProperty(JvNewStringLatin1("java.library.path"));
619 if (path)
621 char *val = (char *) _Jv_Malloc (JvGetStringUTFLength (path) + 1);
622 jsize total = JvGetStringUTFRegion (path, 0, path->length(), val);
623 val[total] = '\0';
624 _Jv_SetDLLSearchPath (val);
625 _Jv_Free (val);
627 else
629 // Set a value for user code to see.
630 // FIXME: JDK sets this to the actual path used, including
631 // LD_LIBRARY_PATH, etc.
632 SET ("java.library.path", "");
636 java::lang::Process *
637 java::lang::Runtime::execInternal (jstringArray cmd,
638 jstringArray env,
639 java::io::File *dir)
641 return new java::lang::ConcreteProcess (cmd, env, dir);
644 jint
645 java::lang::Runtime::availableProcessors (void)
647 // FIXME: find the real value.
648 return 1;
651 jstring
652 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
654 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
655 sb->append(pathname);
656 if (pathname->length() > 0)
657 sb->append (_Jv_platform_file_separator);
659 sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix));
660 sb->append(libname);
661 sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix));
663 return sb->toString();