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/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>
43 #include <sys/utsname.h>
50 #ifdef HAVE_LANGINFO_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 } };
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
;
78 _Jv_FindSymbolInExecutable (const char *symname
)
81 data
.symname
= symname
;
83 lt_dlforeach (find_symbol
, (lt_ptr
) &data
);
88 _Jv_SetDLLSearchPath (const char *path
)
90 lt_dlsetsearchpath (path
);
96 _Jv_FindSymbolInExecutable (const char *)
102 _Jv_SetDLLSearchPath (const char *)
107 #endif /* USE_LTDL */
112 java::lang::Runtime::exitInternal (jint status
)
114 // Make status right for Unix. This is perhaps strange.
115 if (status
< 0 || status
> 255)
119 _Jv_RunAllFinalizers ();
121 // Delete all files registered with File.deleteOnExit()
122 gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
128 java::lang::Runtime::freeMemory (void)
130 return _Jv_GCFreeMemory ();
134 java::lang::Runtime::gc (void)
140 // List of names for JNI_OnLoad.
141 static const char *onload_names
[] = _Jv_platform_onload_names
;
145 java::lang::Runtime::_load (jstring path
, jboolean do_search
)
147 JvSynchronize
sync (this);
148 using namespace java::lang
;
150 jint len
= _Jv_GetStringUTFLength (path
);
151 char buf
[len
+ 1 + strlen (_Jv_platform_solib_prefix
)
152 + strlen (_Jv_platform_solib_suffix
)];
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
;
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
);
176 ClassLoader
*loader
= klass
->getClassLoaderInternal();
177 if (loader
!= NULL
&& loader
!= sys
)
185 catch (::java::lang::ArrayIndexOutOfBoundsException
*e
)
191 // Don't include solib prefix in string passed to
193 jstring name
= look
->findLibrary(JvNewStringUTF(&buf
[offset
]));
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
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
);
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.
228 const char **name
= onload_names
;
229 while (*name
!= NULL
)
231 onload
= lt_dlsym (h
, *name
);
239 JavaVM
*vm
= _Jv_GetJavaVM ();
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"));
254 throw new UnknownError
255 (JvNewStringLatin1 (do_search
256 ? "Runtime.loadLibrary not implemented"
257 : "Runtime.load not implemented"));
258 #endif /* USE_LTDL */
262 java::lang::Runtime::loadLibraryInternal (jstring lib
)
264 JvSynchronize
sync (this);
265 using namespace java::lang
;
267 jint len
= _Jv_GetStringUTFLength (lib
);
269 jsize total
= JvGetStringUTFRegion (lib
, 0, lib
->length(), buf
);
271 // FIXME: make sure path is absolute.
272 lt_dlhandle h
= lt_dlopenext (buf
);
276 #endif /* USE_LTDL */
280 java::lang::Runtime::init (void)
284 // Make sure self is opened.
290 java::lang::Runtime::runFinalization (void)
292 gnu::gcj::runtime::FinalizerThread::finalizerReady ();
296 java::lang::Runtime::totalMemory (void)
298 return _Jv_GCTotalMemory ();
302 java::lang::Runtime::maxMemory (void)
304 // We don't have a maximum. FIXME: we might if we ask the GC for
306 return Long::MAX_VALUE
;
310 java::lang::Runtime::traceInstructions (jboolean
)
316 java::lang::Runtime::traceMethodCalls (jboolean
)
321 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
322 && defined (HAVE_NL_LANGINFO)
327 setlocale (LC_CTYPE
, "");
328 char *e
= nl_langinfo (CODESET
);
329 if (e
== NULL
|| *e
== '\0')
334 #define DEFAULT_FILE_ENCODING file_encoding ()
338 #ifndef DEFAULT_FILE_ENCODING
339 #define DEFAULT_FILE_ENCODING "8859_1"
342 static char *default_file_encoding
= DEFAULT_FILE_ENCODING
;
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
>
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
>
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
>
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;
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.");
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
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
);
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'
445 && u
.machine
[2] == '8'
446 && u
.machine
[3] == '6'
447 && u
.machine
[4] == 0)
448 SET ("os.arch", "i386");
450 SET ("os.arch", u
.machine
);
454 SET ("os.name", "unknown");
455 SET ("os.arch", "unknown");
456 SET ("os.version", "unknown");
458 #endif /* HAVE_UNAME */
462 uid_t user_id
= getuid ();
463 struct passwd
*pwd_entry
;
465 #ifdef HAVE_GETPWUID_R
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
);
476 else if (r
!= ERANGE
)
482 buf_r
= (char *) _Jv_AllocBytes (len_r
);
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 */
498 /* Use getcwd to set "user.dir". */
500 char *buffer
= (char *) malloc (buflen
);
501 while (buffer
!= NULL
)
503 if (getcwd (buffer
, buflen
) != NULL
)
505 SET ("user.dir", buffer
);
511 buffer
= (char *) realloc (buffer
, buflen
);
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)
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
536 if (locale
[0] == '_')
539 strncpy (buf
, locale
, 2);
540 SET ("user.region", buf
);
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
)
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
)
577 while (_Jv_Environment_Properties
[i
].key
)
579 SET (_Jv_Environment_Properties
[i
].key
,
580 _Jv_Environment_Properties
[i
].value
);
586 if (_Jv_Jar_Class_Path
)
587 newprops
->put(JvNewStringLatin1 ("java.class.path"),
588 JvNewStringLatin1 (_Jv_Jar_Class_Path
));
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 ();
598 sb
->append (JvNewStringLatin1 (classpath
));
599 sb
->append (_Jv_platform_path_separator
);
604 sb
->append ((jchar
) '.');
606 newprops
->put(JvNewStringLatin1 ("java.class.path"),
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"));
621 char *val
= (char *) _Jv_Malloc (JvGetStringUTFLength (path
) + 1);
622 jsize total
= JvGetStringUTFRegion (path
, 0, path
->length(), val
);
624 _Jv_SetDLLSearchPath (val
);
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
,
641 return new java::lang::ConcreteProcess (cmd
, env
, dir
);
645 java::lang::Runtime::availableProcessors (void)
647 // FIXME: find the real value.
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
));
661 sb
->append (JvNewStringLatin1 (_Jv_platform_solib_suffix
));
663 return sb
->toString();