1 // natRuntime.cc - Implementation of native side of Runtime class.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002 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
17 #include <java-props.h>
18 #include <java/lang/Long.h>
19 #include <java/lang/Runtime.h>
20 #include <java/lang/UnknownError.h>
21 #include <java/lang/UnsatisfiedLinkError.h>
22 #include <gnu/gcj/runtime/FileDeleter.h>
23 #include <gnu/gcj/runtime/FinalizerThread.h>
24 #include <java/util/Properties.h>
25 #include <java/util/TimeZone.h>
26 #include <java/lang/StringBuffer.h>
27 #include <java/lang/Process.h>
28 #include <java/lang/ConcreteProcess.h>
40 #include <sys/utsname.h>
47 #ifdef HAVE_LANGINFO_H
51 #if TIME_WITH_SYS_TIME
52 # include <sys/time.h>
56 # include <sys/time.h>
67 /* FIXME: we don't always need this. The next libtool will let us use
68 AC_LTDL_PREOPEN to see if we do. */
69 extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
71 // We keep track of all the libraries loaded by this application. For
72 // now we use them to look up symbols for JNI. `libraries_size' holds
73 // the total size of the buffer. `libraries_count' is the number of
74 // items which are in use.
75 static int libraries_size;
76 static int libraries_count;
77 static lt_dlhandle *libraries;
80 add_library (lt_dlhandle lib)
82 if (libraries_count == libraries_size)
84 int ns = libraries_size * 2;
87 lt_dlhandle *n = (lt_dlhandle *) _Jv_Malloc (ns * sizeof (lt_dlhandle));
90 memcpy (n, libraries, libraries_size * sizeof (lt_dlhandle));
95 for (int i = libraries_count; i < libraries_size; ++i)
99 libraries[libraries_count++] = lib;
103 _Jv_FindSymbolInExecutable (const char *symname)
105 for (int i = 0; i < libraries_count; ++i)
107 void *r = lt_dlsym (libraries[i], symname);
118 _Jv_FindSymbolInExecutable (const char *symname)
123 #endif /* USE_LTDL */
128 java::lang::Runtime::exitInternal (jint status)
130 // Make status right for Unix. This is perhaps strange.
131 if (status < 0 || status > 255)
135 _Jv_RunAllFinalizers ();
137 // Delete all files registered with File.deleteOnExit()
138 gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
144 java::lang::Runtime::freeMemory (void)
146 return _Jv_GCFreeMemory ();
150 java::lang::Runtime::gc (void)
156 java::lang::Runtime::_load (jstring path, jboolean do_search)
158 JvSynchronize sync (this);
159 using namespace java::lang;
161 jint len = _Jv_GetStringUTFLength (path);
162 char buf[len + 1 + 3];
165 // On Unix boxes, prefix library name with `lib', for loadLibrary.
172 jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
173 buf[offset + total] = '\0';
175 // FIXME: make sure path is absolute.
177 // Synchronize on java.lang.Class. This is to protect the class chain from
178 // concurrent modification by class registration calls which may be run
179 // during the dlopen().
180 JvSynchronize sync (&java::lang::Class::class$);
181 h = do_search ? lt_dlopenext (buf) : lt_dlopen (buf);
185 const char *msg = lt_dlerror ();
186 jstring str = path->concat (JvNewStringLatin1 (": "));
187 str = str->concat (JvNewStringLatin1 (msg));
188 throw new UnsatisfiedLinkError (str);
193 void *onload = lt_dlsym (h, "JNI_OnLoad");
196 JavaVM *vm = _Jv_GetJavaVM ();
202 jint vers = ((jint (*) (JavaVM *, void *)) onload) (vm, NULL);
203 if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
204 && vers != JNI_VERSION_1_4)
206 // FIXME: unload the library.
207 throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
211 throw new UnknownError
212 (JvNewStringLatin1 (do_search
213 ? "Runtime.loadLibrary not implemented"
214 : "Runtime.load not implemented"));
215 #endif /* USE_LTDL */
219 java::lang::Runtime::loadLibraryInternal (jstring lib)
221 JvSynchronize sync (this);
222 using namespace java::lang;
224 jint len = _Jv_GetStringUTFLength (lib);
226 jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
228 // FIXME: make sure path is absolute.
229 lt_dlhandle h = lt_dlopenext (buf);
235 #endif /* USE_LTDL */
239 java::lang::Runtime::init (void)
243 lt_dlhandle self = lt_dlopen (NULL);
250 java::lang::Runtime::runFinalization (void)
252 gnu::gcj::runtime::FinalizerThread::finalizerReady ();
256 java::lang::Runtime::totalMemory (void)
258 return _Jv_GCTotalMemory ();
262 java::lang::Runtime::maxMemory (void)
264 // We don't have a maximum. FIXME: we might if we ask the GC for
266 return Long::MAX_VALUE;
270 java::lang::Runtime::traceInstructions (jboolean)
276 java::lang::Runtime::traceMethodCalls (jboolean)
281 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
282 && defined (HAVE_NL_LANGINFO)
287 setlocale (LC_CTYPE, "");
288 char *e = nl_langinfo (CODESET);
289 if (e == NULL || *e == '\0')
294 #define DEFAULT_FILE_ENCODING file_encoding ()
298 #ifndef DEFAULT_FILE_ENCODING
299 #define DEFAULT_FILE_ENCODING "8859_1"
302 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
305 /* Use overload resolution to find out the signature of getpwuid_r. */
307 /* This is Posix getpwuid_r. */
308 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
310 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
311 T_buf *buf_r, T_len len_r,
312 T_passwd **pwd_entry_ptr),
313 uid_t user_id, struct passwd *pwd_r,
314 char *buf_r, size_t len_r, struct passwd **pwd_entry)
316 return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
319 /* This is used on HPUX 10.20 */
320 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
322 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
323 T_buf *buf_r, T_len len_r),
324 uid_t user_id, struct passwd *pwd_r,
325 char *buf_r, size_t len_r, struct passwd **pwd_entry)
327 return getpwuid_r (user_id, pwd_r, buf_r, len_r);
330 /* This is used on IRIX 5.2. */
331 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
333 getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
334 T_buf *buf_r, T_len len_r),
335 uid_t user_id, struct passwd *pwd_r,
336 char *buf_r, size_t len_r, struct passwd **pwd_entry)
338 *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
339 return (*pwd_entry == NULL) ? errno : 0;
344 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
346 // A convenience define.
347 #define SET(Prop,Val) \
348 newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
350 // A mixture of the Java Product Versioning Specification
351 // (introduced in 1.2), and earlier versioning properties.
352 SET ("java.version", GCJVERSION);
353 SET ("java.vendor", "Free Software Foundation, Inc.");
354 SET ("java.vendor.url", "http://gcc.gnu.org/java/");
355 SET ("java.class.version", "46.0");
356 SET ("java.vm.specification.version", "1.0");
357 SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
358 SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
359 SET ("java.vm.version", __VERSION__);
360 SET ("java.vm.vendor", "Free Software Foundation, Inc.");
361 SET ("java.vm.name", "GNU libgcj");
362 SET ("java.specification.version", "1.3");
363 SET ("java.specification.name", "Java(tm) Platform API Specification");
364 SET ("java.specification.vendor", "Sun Microsystems Inc.");
367 #define NAME "GNU libgcj "
368 strcpy (value, NAME);
369 strncpy (value + sizeof (NAME) - 1, __VERSION__,
370 sizeof(value) - sizeof(NAME));
371 value[sizeof (value) - 1] = '\0';
372 jstring version = JvNewStringLatin1 (value);
373 newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
374 newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
376 // This definition is rather arbitrary: we choose $(prefix). In
377 // part we do this because most people specify only --prefix and
378 // nothing else when installing gcj. Plus, people are free to
379 // redefine `java.home' with `-D' if necessary.
380 SET ("java.home", PREFIX);
382 SET ("file.encoding", default_file_encoding);
388 SET ("os.name", u.sysname);
389 SET ("os.arch", u.machine);
390 SET ("os.version", u.release);
394 SET ("os.name", "unknown");
395 SET ("os.arch", "unknown");
396 SET ("os.version", "unknown");
398 #endif /* HAVE_UNAME */
402 uid_t user_id = getuid ();
403 struct passwd *pwd_entry;
405 #ifdef HAVE_GETPWUID_R
408 char *buf_r = (char *) _Jv_AllocBytes (len_r);
410 while (buf_r != NULL)
412 int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
413 buf_r, len_r, &pwd_entry);
416 else if (r != ERANGE)
422 buf_r = (char *) _Jv_AllocBytes (len_r);
425 pwd_entry = getpwuid (user_id);
426 #endif /* HAVE_GETPWUID_R */
428 if (pwd_entry != NULL)
430 SET ("user.name", pwd_entry->pw_name);
431 SET ("user.home", pwd_entry->pw_dir);
433 #endif /* HAVE_PWD_H */
434 #endif /* NO_GETUID */
438 /* Use getcwd to set "user.dir". */
440 char *buffer = (char *) malloc (buflen);
441 while (buffer != NULL)
443 if (getcwd (buffer, buflen) != NULL)
445 SET ("user.dir", buffer);
451 buffer = (char *) realloc (buffer, buflen);
455 #endif /* HAVE_UNISTD_H */
456 #endif /* HAVE_GETCWD */
458 // Set user locale properties based on setlocale()
459 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
460 // We let the user choose the locale. However, since Java differs
461 // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
462 // Java locale. We can't use LC_ALL because it might return a full
463 // list of all the settings. If we don't have LC_MESSAGES then we
464 // just default to `en_US'.
465 setlocale (LC_ALL, "");
466 char *locale = setlocale (LC_MESSAGES, "");
467 if (locale && strlen (locale) >= 2)
471 // copy the first two chars to user.language
472 strncpy (buf, locale, 2);
473 SET ("user.language", buf);
474 // if the next char is a '_', copy the two after that to user.region
476 if (locale[0] == '_')
479 strncpy (buf, locale, 2);
480 SET ("user.region", buf);
484 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
486 SET ("user.language", "en");
487 SET ("user.region", "US");
490 // Set some properties according to whatever was compiled in with
492 for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
496 for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
498 jstring name = JvNewStringLatin1 (p, s - p);
499 jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
500 newprops->put (name, val);
503 // Set the system properties from the user's environment.
504 #ifndef DISABLE_GETENV_PROPERTIES
505 if (_Jv_Environment_Properties)
509 while (_Jv_Environment_Properties[i].key)
511 SET (_Jv_Environment_Properties[i].key,
512 _Jv_Environment_Properties[i].value);
518 if (_Jv_Jar_Class_Path)
519 newprops->put(JvNewStringLatin1 ("java.class.path"),
520 JvNewStringLatin1 (_Jv_Jar_Class_Path));
523 // FIXME: find libgcj.zip and append its path?
524 char *classpath = ::getenv("CLASSPATH");
525 jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
526 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
530 sb->append (JvNewStringLatin1 (classpath));
532 sb->append ((jchar) ';');
534 sb->append ((jchar) ':');
540 sb->append ((jchar) '.');
542 newprops->put(JvNewStringLatin1 ("java.class.path"),
546 // Allow platform specific settings and overrides.
547 _Jv_platform_initProperties (newprops);
550 java::lang::Process *
551 java::lang::Runtime::execInternal (jstringArray cmd,
554 return new java::lang::ConcreteProcess (cmd, env);
558 java::lang::Runtime::availableProcessors (void)
560 // FIXME: find the real value.
565 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
567 java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
568 sb->append(pathname);
569 if (pathname->length() > 0)
571 // FIXME: use platform function here.
573 sb->append ((jchar) '\\');
575 sb->append ((jchar) '/');
579 // FIXME: use platform function here.
581 sb->append (JvNewStringLatin1 ("lib"));
586 // FIXME: use platform function here.
588 sb->append (JvNewStringLatin1 ("dll"));
590 sb->append (JvNewStringLatin1 ("so"));
593 return sb->toString();