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
18 #include <java-props.h>
19 #include <java-stack.h>
20 #include <java/lang/Long.h>
21 #include <java/lang/Runtime.h>
22 #include <java/lang/UnknownError.h>
23 #include <java/lang/UnsatisfiedLinkError.h>
24 #include <gnu/gcj/runtime/FileDeleter.h>
25 #include <gnu/gcj/runtime/FinalizerThread.h>
26 #include <java/io/File.h>
27 #include <java/util/Properties.h>
28 #include <java/util/TimeZone.h>
29 #include <java/lang/StringBuffer.h>
30 #include <java/lang/Process.h>
31 #include <java/lang/ConcreteProcess.h>
32 #include <java/lang/ClassLoader.h>
42 #include <sys/utsname.h>
49 #ifdef HAVE_LANGINFO_H
58 /* FIXME: we don't always need this. The next libtool will let us use
59 AC_LTDL_PREOPEN to see if we do. */
60 extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
69 find_symbol (lt_dlhandle handle, lt_ptr data)
71 lookup_data *ld = (lookup_data *) data;
72 ld->result = lt_dlsym (handle, ld->symname);
73 return ld->result != NULL;
77 _Jv_FindSymbolInExecutable (const char *symname)
80 data.symname = symname;
82 lt_dlforeach (find_symbol, (lt_ptr) &data);
87 _Jv_SetDLLSearchPath (const char *path)
89 lt_dlsetsearchpath (path);
95 _Jv_FindSymbolInExecutable (const char *)
101 _Jv_SetDLLSearchPath (const char *)
106 #endif /* USE_LTDL */
111 java::lang::Runtime::exitInternal (jint status)
113 // Make status right for Unix. This is perhaps strange.
114 if (status < 0 || status > 255)
118 _Jv_RunAllFinalizers ();
120 // Delete all files registered with File.deleteOnExit()
121 gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
127 java::lang::Runtime::freeMemory (void)
129 return _Jv_GCFreeMemory ();
133 java::lang::Runtime::gc (void)
139 // List of names for JNI_OnLoad.
140 static const char *onload_names[] = _Jv_platform_onload_names;
144 java::lang::Runtime::_load (jstring path, jboolean do_search)
146 JvSynchronize sync (this);
147 using namespace java::lang;
149 jint len = _Jv_GetStringUTFLength (path);
150 char buf[len + 1 + strlen (_Jv_platform_solib_prefix)
151 + strlen (_Jv_platform_solib_suffix)];
155 strcpy (buf, _Jv_platform_solib_prefix);
156 offset = strlen (_Jv_platform_solib_prefix);
158 jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
159 buf[offset + total] = '\0';
161 char *lib_name = buf;
165 ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader ();
169 // Don't include solib prefix in string passed to
171 jstring name = look->findLibrary(JvNewStringUTF(&buf[offset]));
174 len = _Jv_GetStringUTFLength (name);
175 lib_name = (char *) _Jv_AllocBytes(len + 1);
176 total = JvGetStringUTFRegion (name, 0,
177 name->length(), lib_name);
178 lib_name[total] = '\0';
179 // Don't append suffixes any more; we have the full file
187 // FIXME: make sure path is absolute.
189 // Synchronize on java.lang.Class. This is to protect the class chain from
190 // concurrent modification by class registration calls which may be run
191 // during the dlopen().
192 JvSynchronize sync (&java::lang::Class::class$);
193 h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name);
197 const char *msg = lt_dlerror ();
198 jstring str = JvNewStringLatin1 (lib_name);
199 str = str->concat (JvNewStringLatin1 (": "));
200 str = str->concat (JvNewStringLatin1 (msg));
201 throw new UnsatisfiedLinkError (str);
204 // Search for JNI_OnLoad function.
206 const char **name = onload_names;
207 while (*name != NULL)
209 onload = lt_dlsym (h, *name);
217 JavaVM *vm = _Jv_GetJavaVM ();
223 jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
224 if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
225 && vers != JNI_VERSION_1_4)
227 // FIXME: unload the library.
228 throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
232 throw new UnknownError
233 (JvNewStringLatin1 (do_search
234 ? "Runtime.loadLibrary not implemented"
235 : "Runtime.load not implemented"));
236 #endif /* USE_LTDL */
240 java::lang::Runtime::loadLibraryInternal (jstring lib)
242 JvSynchronize sync (this);
243 using namespace java::lang;
245 jint len = _Jv_GetStringUTFLength (lib);
247 jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
249 // FIXME: make sure path is absolute.
250 lt_dlhandle h = lt_dlopenext (buf);
254 #endif /* USE_LTDL */
258 java::lang::Runtime::init (void)
262 // Make sure self is opened.
268 java::lang::Runtime::runFinalization (void)
270 gnu::gcj::runtime::FinalizerThread::finalizerReady ();
274 java::lang::Runtime::totalMemory (void)
276 return _Jv_GCTotalMemory ();
280 java::lang::Runtime::maxMemory (void)
282 // We don't have a maximum. FIXME: we might if we ask the GC for
284 return Long::MAX_VALUE;
288 java::lang::Runtime::traceInstructions (jboolean)
294 java::lang::Runtime::traceMethodCalls (jboolean)
299 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
300 && defined (HAVE_NL_LANGINFO)
305 setlocale (LC_CTYPE, "");
306 char *e = nl_langinfo (CODESET);
307 if (e == NULL || *e == '\0')
312 #define DEFAULT_FILE_ENCODING file_encoding ()
316 #ifndef DEFAULT_FILE_ENCODING
317 #define DEFAULT_FILE_ENCODING "8859_1"
320 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
323 /* Use overload resolution to find out the signature of getpwuid_r. */
325 /* This is Posix getpwuid_r. */
326 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
328 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
329 T_buf *buf_r, T_len len_r,
330 T_passwd **pwd_entry_ptr),
331 uid_t user_id, struct passwd *pwd_r,
332 char *buf_r, size_t len_r, struct passwd **pwd_entry)
334 return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
337 /* This is used on HPUX 10.20 */
338 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
340 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
341 T_buf *buf_r, T_len len_r),
342 uid_t user_id, struct passwd *pwd_r,
343 char *buf_r, size_t len_r, struct passwd **pwd_entry)
345 return getpwuid_r (user_id, pwd_r, buf_r, len_r);
348 /* This is used on IRIX 5.2. */
349 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
351 getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
352 T_buf *buf_r, T_len len_r),
353 uid_t user_id, struct passwd *pwd_r,
354 char *buf_r, size_t len_r, struct passwd **pwd_entry)
356 *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
357 return (*pwd_entry == NULL) ? errno : 0;
362 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
364 // A convenience define.
365 #define SET(Prop,Val) \
366 newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
368 // A mixture of the Java Product Versioning Specification
369 // (introduced in 1.2), and earlier versioning properties. Some
370 // programs rely on seeing values that they expect, so we claim to
371 // be a 1.4-ish VM for their sake.
372 SET ("java.version", "1.4.2");
373 SET ("java.runtime.version", "1.4.2");
374 SET ("java.vendor", "Free Software Foundation, Inc.");
375 SET ("java.vendor.url", "http://gcc.gnu.org/java/");
376 SET ("java.class.version", "46.0");
377 SET ("java.vm.specification.version", "1.0");
378 SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
379 SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
380 SET ("java.vm.version", __VERSION__);
381 SET ("java.vm.vendor", "Free Software Foundation, Inc.");
382 SET ("java.vm.name", "GNU libgcj");
383 SET ("java.specification.version", "1.4");
384 SET ("java.specification.name", "Java(tm) Platform API Specification");
385 SET ("java.specification.vendor", "Sun Microsystems Inc.");
388 #define NAME "GNU libgcj "
389 strcpy (value, NAME);
390 strncpy (value + sizeof (NAME) - 1, __VERSION__,
391 sizeof(value) - sizeof(NAME));
392 value[sizeof (value) - 1] = '\0';
393 jstring version = JvNewStringLatin1 (value);
394 newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
395 newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
397 // This definition is rather arbitrary: we choose $(prefix). In
398 // part we do this because most people specify only --prefix and
399 // nothing else when installing gcj. Plus, people are free to
400 // redefine `java.home' with `-D' if necessary.
401 SET ("java.home", PREFIX);
402 SET ("gnu.classpath.home", PREFIX);
403 // This is set to $(libdir) because we use this to find .security
405 char val2[sizeof ("file://") + sizeof (LIBDIR) + 1];
406 strcpy (val2, "file://");
407 strcat (val2, LIBDIR);
408 SET ("gnu.classpath.home.url", val2);
410 SET ("file.encoding", default_file_encoding);
416 SET ("os.name", u.sysname);
417 SET ("os.version", u.release);
419 // Normalize x86 architecture names to "i386" (except on Windows, which
420 // is handled in win32.cc).
421 if (u.machine[0] == 'i'
423 && u.machine[2] == '8'
424 && u.machine[3] == '6'
425 && u.machine[4] == 0)
426 SET ("os.arch", "i386");
428 SET ("os.arch", u.machine);
432 SET ("os.name", "unknown");
433 SET ("os.arch", "unknown");
434 SET ("os.version", "unknown");
436 #endif /* HAVE_UNAME */
440 uid_t user_id = getuid ();
441 struct passwd *pwd_entry;
443 #ifdef HAVE_GETPWUID_R
446 char *buf_r = (char *) _Jv_AllocBytes (len_r);
448 while (buf_r != NULL)
450 int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
451 buf_r, len_r, &pwd_entry);
454 else if (r != ERANGE)
460 buf_r = (char *) _Jv_AllocBytes (len_r);
463 pwd_entry = getpwuid (user_id);
464 #endif /* HAVE_GETPWUID_R */
466 if (pwd_entry != NULL)
468 SET ("user.name", pwd_entry->pw_name);
469 SET ("user.home", pwd_entry->pw_dir);
471 #endif /* HAVE_PWD_H */
472 #endif /* NO_GETUID */
476 /* Use getcwd to set "user.dir". */
478 char *buffer = (char *) malloc (buflen);
479 while (buffer != NULL)
481 if (getcwd (buffer, buflen) != NULL)
483 SET ("user.dir", buffer);
489 buffer = (char *) realloc (buffer, buflen);
493 #endif /* HAVE_UNISTD_H */
494 #endif /* HAVE_GETCWD */
496 // Set user locale properties based on setlocale()
497 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
498 // We let the user choose the locale. However, since Java differs
499 // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
500 // Java locale. We can't use LC_ALL because it might return a full
501 // list of all the settings. If we don't have LC_MESSAGES then we
502 // just default to `en_US'.
503 setlocale (LC_ALL, "");
504 char *locale = setlocale (LC_MESSAGES, "");
505 if (locale && strlen (locale) >= 2)
509 // copy the first two chars to user.language
510 strncpy (buf, locale, 2);
511 SET ("user.language", buf);
512 // if the next char is a '_', copy the two after that to user.region
514 if (locale[0] == '_')
517 strncpy (buf, locale, 2);
518 SET ("user.region", buf);
522 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
524 SET ("user.language", "en");
525 SET ("user.region", "US");
528 // The java extensions directory.
529 SET ("java.ext.dirs", JAVA_EXT_DIRS);
531 // The path to libgcj's boot classes
532 SET ("sun.boot.class.path", BOOT_CLASS_PATH);
534 // If there is a default system database, set it.
535 SET ("gnu.gcj.precompiled.db.path", LIBGCJ_DEFAULT_DATABASE);
537 // Set some properties according to whatever was compiled in with
538 // `-D'. Important: after this point, the only properties that
539 // should be set are those which either the user cannot meaningfully
540 // override, or which augment whatever value the user has provided.
541 for (int i = 0; i < _Jv_Properties_Count; ++i)
545 for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
547 jstring name = JvNewStringLatin1 (p, s - p);
548 jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
549 newprops->put (name, val);
552 // Set the system properties from the user's environment.
553 #ifndef DISABLE_GETENV_PROPERTIES
554 if (_Jv_Environment_Properties)
558 while (_Jv_Environment_Properties[i].key)
560 SET (_Jv_Environment_Properties[i].key,
561 _Jv_Environment_Properties[i].value);
567 if (_Jv_Jar_Class_Path)
568 newprops->put(JvNewStringLatin1 ("java.class.path"),
569 JvNewStringLatin1 (_Jv_Jar_Class_Path));
572 // FIXME: find libgcj.zip and append its path?
573 char *classpath = ::getenv("CLASSPATH");
574 jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
575 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
579 sb->append (JvNewStringLatin1 (classpath));
580 sb->append (_Jv_platform_path_separator);
585 sb->append ((jchar) '.');
587 newprops->put(JvNewStringLatin1 ("java.class.path"),
591 // The name used to invoke this process (argv[0] in C).
592 SET ("gnu.gcj.progname", _Jv_GetSafeArg (0));
594 // Allow platform specific settings and overrides.
595 _Jv_platform_initProperties (newprops);
597 // If java.library.path is set, tell libltdl so we search the new
598 // directories as well. FIXME: does this work properly on Windows?
599 String *path = newprops->getProperty(JvNewStringLatin1("java.library.path"));
602 char *val = (char *) _Jv_Malloc (JvGetStringUTFLength (path) + 1);
603 jsize total = JvGetStringUTFRegion (path, 0, path->length(), val);
605 _Jv_SetDLLSearchPath (val);
610 // Set a value for user code to see.
611 // FIXME: JDK sets this to the actual path used, including
612 // LD_LIBRARY_PATH, etc.
613 SET ("java.library.path", "");
617 java::lang::Process *
618 java::lang::Runtime::execInternal (jstringArray cmd,
622 return new java::lang::ConcreteProcess (cmd, env, dir);
626 java::lang::Runtime::availableProcessors (void)
628 // FIXME: find the real value.
633 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
635 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
636 sb->append(pathname);
637 if (pathname->length() > 0)
638 sb->append (_Jv_platform_file_separator);
640 sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix));
642 sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix));
644 return sb->toString();