OSDN Git Service

Fixes PR libgcj/6389:
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natRuntime.cc
1 // natRuntime.cc - Implementation of native side of Runtime class.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include <stdlib.h>
14
15 #include <gcj/cni.h>
16 #include <jvm.h>
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>
29
30 #include <jni.h>
31
32 #include "platform.h"
33
34 #ifdef HAVE_PWD_H
35 #include <pwd.h>
36 #endif
37 #include <errno.h>
38
39 #ifdef HAVE_UNAME
40 #include <sys/utsname.h>
41 #endif
42
43 #ifdef HAVE_LOCALE_H
44 #include <locale.h>
45 #endif
46
47 #ifdef HAVE_LANGINFO_H
48 #include <langinfo.h>
49 #endif
50
51 #if TIME_WITH_SYS_TIME
52 # include <sys/time.h>
53 # include <time.h>
54 #else
55 # if HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 # else
58 #  include <time.h>
59 # endif
60 #endif
61
62 \f
63
64 #ifdef USE_LTDL
65 #include <ltdl.h>
66
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 } };
70
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;
78
79 static void
80 add_library (lt_dlhandle lib)
81 {
82   if (libraries_count == libraries_size)
83     {
84       int ns = libraries_size * 2;
85       if (ns == 0)
86         ns = 10;
87       lt_dlhandle *n = (lt_dlhandle *) _Jv_Malloc (ns * sizeof (lt_dlhandle));
88       if (libraries)
89         {
90           memcpy (n, libraries, libraries_size * sizeof (lt_dlhandle));
91           _Jv_Free (libraries);
92         }
93       libraries = n;
94       libraries_size = ns;
95       for (int i = libraries_count; i < libraries_size; ++i)
96         libraries[i] = NULL;
97     }
98
99   libraries[libraries_count++] = lib;
100 }
101
102 void *
103 _Jv_FindSymbolInExecutable (const char *symname)
104 {
105   for (int i = 0; i < libraries_count; ++i)
106     {
107       void *r = lt_dlsym (libraries[i], symname);
108       if (r)
109         return r;
110     }
111
112   return NULL;
113 }
114
115 #else
116
117 void *
118 _Jv_FindSymbolInExecutable (const char *symname)
119 {
120   return NULL;
121 }
122
123 #endif /* USE_LTDL */
124
125 \f
126
127 void
128 java::lang::Runtime::exitInternal (jint status)
129 {
130   // Make status right for Unix.  This is perhaps strange.
131   if (status < 0 || status > 255)
132     status = 255;
133
134   if (finalizeOnExit)
135     _Jv_RunAllFinalizers ();
136
137   // Delete all files registered with File.deleteOnExit()
138   gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
139
140   ::exit (status);
141 }
142
143 jlong
144 java::lang::Runtime::freeMemory (void)
145 {
146   return _Jv_GCFreeMemory ();
147 }
148
149 void
150 java::lang::Runtime::gc (void)
151 {
152   _Jv_RunGC ();
153 }
154
155 void
156 java::lang::Runtime::_load (jstring path, jboolean do_search)
157 {
158   JvSynchronize sync (this);
159   using namespace java::lang;
160 #ifdef USE_LTDL
161   jint len = _Jv_GetStringUTFLength (path);
162   char buf[len + 1 + 3];
163   int offset = 0;
164 #ifndef WIN32
165   // On Unix boxes, prefix library name with `lib', for loadLibrary.
166   if (do_search)
167     {
168       strcpy (buf, "lib");
169       offset = 3;
170     }
171 #endif
172   jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
173   buf[offset + total] = '\0';
174   lt_dlhandle h;
175   // FIXME: make sure path is absolute.
176   {
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);
182   }
183   if (h == NULL)
184     {
185       const char *msg = lt_dlerror ();
186       jstring str = path->concat (JvNewStringLatin1 (": "));
187       str = str->concat (JvNewStringLatin1 (msg));
188       throw new UnsatisfiedLinkError (str);
189     }
190
191   add_library (h);
192
193   void *onload = lt_dlsym (h, "JNI_OnLoad");
194   if (onload != NULL)
195     {
196       JavaVM *vm = _Jv_GetJavaVM ();
197       if (vm == NULL)
198         {
199           // FIXME: what?
200           return;
201         }
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)
205         {
206           // FIXME: unload the library.
207           throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
208         }
209     }
210 #else
211   throw new UnknownError
212     (JvNewStringLatin1 (do_search
213                         ? "Runtime.loadLibrary not implemented"
214                         : "Runtime.load not implemented"));
215 #endif /* USE_LTDL */
216 }
217
218 jboolean
219 java::lang::Runtime::loadLibraryInternal (jstring lib)
220 {
221   JvSynchronize sync (this);
222   using namespace java::lang;
223 #ifdef USE_LTDL
224   jint len = _Jv_GetStringUTFLength (lib);
225   char buf[len + 1];
226   jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
227   buf[total] = '\0';
228   // FIXME: make sure path is absolute.
229   lt_dlhandle h = lt_dlopenext (buf);
230   if (h != NULL)
231     add_library (h);
232   return h != NULL;
233 #else
234   return false;
235 #endif /* USE_LTDL */
236 }
237
238 void
239 java::lang::Runtime::init (void)
240 {
241 #ifdef USE_LTDL
242   lt_dlinit ();
243   lt_dlhandle self = lt_dlopen (NULL);
244   if (self != NULL)
245     add_library (self);
246 #endif
247 }
248
249 void
250 java::lang::Runtime::runFinalization (void)
251 {
252   gnu::gcj::runtime::FinalizerThread::finalizerReady ();
253 }
254
255 jlong
256 java::lang::Runtime::totalMemory (void)
257 {
258   return _Jv_GCTotalMemory ();
259 }
260
261 jlong
262 java::lang::Runtime::maxMemory (void)
263 {
264   // We don't have a maximum.  FIXME: we might if we ask the GC for
265   // one.
266   return Long::MAX_VALUE;
267 }
268
269 void
270 java::lang::Runtime::traceInstructions (jboolean)
271 {
272   // Do nothing.
273 }
274
275 void
276 java::lang::Runtime::traceMethodCalls (jboolean)
277 {
278   // Do nothing.
279 }
280
281 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
282     && defined (HAVE_NL_LANGINFO)
283
284 static char *
285 file_encoding ()
286 {
287   setlocale (LC_CTYPE, "");
288   char *e = nl_langinfo (CODESET);
289   if (e == NULL || *e == '\0')
290     e = "8859_1";
291   return e;
292 }
293
294 #define DEFAULT_FILE_ENCODING file_encoding ()
295
296 #endif
297
298 #ifndef DEFAULT_FILE_ENCODING
299 #define DEFAULT_FILE_ENCODING "8859_1"
300 #endif
301
302 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
303
304 #if HAVE_GETPWUID_R
305 /* Use overload resolution to find out the signature of getpwuid_r.  */
306
307   /* This is Posix getpwuid_r.  */
308 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
309 static inline int
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)
315 {
316   return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
317 }
318
319 /* This is used on HPUX 10.20 */
320 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
321 static inline int
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)
326 {
327   return getpwuid_r (user_id, pwd_r, buf_r, len_r);
328 }
329
330 /* This is used on IRIX 5.2.  */
331 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
332 static inline int
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)
337 {
338   *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
339   return (*pwd_entry == NULL) ? errno : 0;
340 }
341 #endif
342
343 void
344 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
345 {
346   // A convenience define.
347 #define SET(Prop,Val) \
348         newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
349
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.");
365
366   char value[100];
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);
375
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);
381   
382   SET ("file.encoding", default_file_encoding);
383
384 #ifdef HAVE_UNAME
385   struct utsname u;
386   if (! uname (&u))
387     {
388       SET ("os.name", u.sysname);
389       SET ("os.arch", u.machine);
390       SET ("os.version", u.release);
391     }
392   else
393     {
394       SET ("os.name", "unknown");
395       SET ("os.arch", "unknown");
396       SET ("os.version", "unknown");
397     }
398 #endif /* HAVE_UNAME */
399
400 #ifndef NO_GETUID
401 #ifdef HAVE_PWD_H
402   uid_t user_id = getuid ();
403   struct passwd *pwd_entry;
404
405 #ifdef HAVE_GETPWUID_R
406   struct passwd pwd_r;
407   size_t len_r = 200;
408   char *buf_r = (char *) _Jv_AllocBytes (len_r);
409
410   while (buf_r != NULL)
411     {
412       int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
413                                 buf_r, len_r, &pwd_entry);
414       if (r == 0)
415         break;
416       else if (r != ERANGE)
417         {
418           pwd_entry = NULL;
419           break;
420         }
421       len_r *= 2;
422       buf_r = (char *) _Jv_AllocBytes (len_r);
423     }
424 #else
425   pwd_entry = getpwuid (user_id);
426 #endif /* HAVE_GETPWUID_R */
427
428   if (pwd_entry != NULL)
429     {
430       SET ("user.name", pwd_entry->pw_name);
431       SET ("user.home", pwd_entry->pw_dir);
432     }
433 #endif /* HAVE_PWD_H */
434 #endif /* NO_GETUID */
435
436 #ifdef HAVE_GETCWD
437 #ifdef HAVE_UNISTD_H
438   /* Use getcwd to set "user.dir". */
439   int buflen = 250;
440   char *buffer = (char *) malloc (buflen);
441   while (buffer != NULL)
442     {
443       if (getcwd (buffer, buflen) != NULL)
444         {
445           SET ("user.dir", buffer);
446           break;
447         }
448       if (errno != ERANGE)
449         break;
450       buflen = 2 * buflen;
451       buffer = (char *) realloc (buffer, buflen);
452     }
453   if (buffer != NULL)
454     free (buffer);
455 #endif /* HAVE_UNISTD_H */
456 #endif /* HAVE_GETCWD */
457
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)
468     {
469       char buf[3];
470       buf[2] = '\0';
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
475       locale += 2;
476       if (locale[0] == '_')
477         {
478           locale++;
479           strncpy (buf, locale, 2);
480           SET ("user.region", buf);
481         }
482     }
483   else
484 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
485     {
486       SET ("user.language", "en");
487       SET ("user.region", "US");
488     }  
489
490   // Set some properties according to whatever was compiled in with
491   // `-D'.
492   for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
493     {
494       const char *s, *p;
495       // Find the `='.
496       for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
497         ;
498       jstring name = JvNewStringLatin1 (p, s - p);
499       jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
500       newprops->put (name, val);
501     }
502
503   // Set the system properties from the user's environment.
504 #ifndef DISABLE_GETENV_PROPERTIES
505   if (_Jv_Environment_Properties)
506     {
507       size_t i = 0;
508
509       while (_Jv_Environment_Properties[i].key)
510         {
511           SET (_Jv_Environment_Properties[i].key, 
512                _Jv_Environment_Properties[i].value);
513           i++;
514         }
515     }
516 #endif
517
518   if (_Jv_Jar_Class_Path)
519     newprops->put(JvNewStringLatin1 ("java.class.path"),
520                   JvNewStringLatin1 (_Jv_Jar_Class_Path));
521   else
522     {
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 ();
527       
528       if (classpath)
529         {
530           sb->append (JvNewStringLatin1 (classpath));
531 #ifdef WIN32
532           sb->append ((jchar) ';');
533 #else
534           sb->append ((jchar) ':');
535 #endif
536         }
537       if (cp != NULL)
538         sb->append (cp);
539       else
540         sb->append ((jchar) '.');
541       
542       newprops->put(JvNewStringLatin1 ("java.class.path"),
543                       sb->toString ());
544     }
545
546   // Allow platform specific settings and overrides.
547   _Jv_platform_initProperties (newprops);
548 }
549
550 java::lang::Process *
551 java::lang::Runtime::execInternal (jstringArray cmd,
552                                    jstringArray env)
553 {
554   return new java::lang::ConcreteProcess (cmd, env);
555 }
556
557 jint
558 java::lang::Runtime::availableProcessors (void)
559 {
560   // FIXME: find the real value.
561   return 1;
562 }
563
564 jstring
565 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
566 {
567   java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
568   sb->append(pathname);
569   if (pathname->length() > 0)
570     {
571       // FIXME: use platform function here.
572 #ifdef WIN32
573       sb->append ((jchar) '\\');
574 #else
575       sb->append ((jchar) '/');
576 #endif
577     }
578
579   // FIXME: use platform function here.
580 #ifndef WIN32
581   sb->append (JvNewStringLatin1 ("lib"));
582 #endif
583
584   sb->append(libname);
585
586   // FIXME: use platform function here.
587 #ifdef WIN32
588   sb->append (JvNewStringLatin1 ("dll"));
589 else
590   sb->append (JvNewStringLatin1 ("so"));
591 #endif
592
593   return sb->toString();
594 }