OSDN Git Service

* java/lang/natRuntime.cc: Don't include sys/time.h and time.h.
[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 \f
52
53 #ifdef USE_LTDL
54 #include <ltdl.h>
55
56 /* FIXME: we don't always need this.  The next libtool will let us use
57    AC_LTDL_PREOPEN to see if we do.  */
58 extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
59
60 // We keep track of all the libraries loaded by this application.  For
61 // now we use them to look up symbols for JNI.  `libraries_size' holds
62 // the total size of the buffer.  `libraries_count' is the number of
63 // items which are in use.
64 static int libraries_size;
65 static int libraries_count;
66 static lt_dlhandle *libraries;
67
68 static void
69 add_library (lt_dlhandle lib)
70 {
71   if (libraries_count == libraries_size)
72     {
73       int ns = libraries_size * 2;
74       if (ns == 0)
75         ns = 10;
76       lt_dlhandle *n = (lt_dlhandle *) _Jv_Malloc (ns * sizeof (lt_dlhandle));
77       if (libraries)
78         {
79           memcpy (n, libraries, libraries_size * sizeof (lt_dlhandle));
80           _Jv_Free (libraries);
81         }
82       libraries = n;
83       libraries_size = ns;
84       for (int i = libraries_count; i < libraries_size; ++i)
85         libraries[i] = NULL;
86     }
87
88   libraries[libraries_count++] = lib;
89 }
90
91 void *
92 _Jv_FindSymbolInExecutable (const char *symname)
93 {
94   for (int i = 0; i < libraries_count; ++i)
95     {
96       void *r = lt_dlsym (libraries[i], symname);
97       if (r)
98         return r;
99     }
100
101   return NULL;
102 }
103
104 #else
105
106 void *
107 _Jv_FindSymbolInExecutable (const char *symname)
108 {
109   return NULL;
110 }
111
112 #endif /* USE_LTDL */
113
114 \f
115
116 void
117 java::lang::Runtime::exitInternal (jint status)
118 {
119   // Make status right for Unix.  This is perhaps strange.
120   if (status < 0 || status > 255)
121     status = 255;
122
123   if (finalizeOnExit)
124     _Jv_RunAllFinalizers ();
125
126   // Delete all files registered with File.deleteOnExit()
127   gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
128
129   ::exit (status);
130 }
131
132 jlong
133 java::lang::Runtime::freeMemory (void)
134 {
135   return _Jv_GCFreeMemory ();
136 }
137
138 void
139 java::lang::Runtime::gc (void)
140 {
141   _Jv_RunGC ();
142 }
143
144 void
145 java::lang::Runtime::_load (jstring path, jboolean do_search)
146 {
147   JvSynchronize sync (this);
148   using namespace java::lang;
149 #ifdef USE_LTDL
150   jint len = _Jv_GetStringUTFLength (path);
151   char buf[len + 1 + 3];
152   int offset = 0;
153 #ifndef WIN32
154   // On Unix boxes, prefix library name with `lib', for loadLibrary.
155   if (do_search)
156     {
157       strcpy (buf, "lib");
158       offset = 3;
159     }
160 #endif
161   jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
162   buf[offset + total] = '\0';
163   lt_dlhandle h;
164   // FIXME: make sure path is absolute.
165   {
166     // Synchronize on java.lang.Class. This is to protect the class chain from
167     // concurrent modification by class registration calls which may be run
168     // during the dlopen().
169     JvSynchronize sync (&java::lang::Class::class$);
170     h = do_search ? lt_dlopenext (buf) : lt_dlopen (buf);
171   }
172   if (h == NULL)
173     {
174       const char *msg = lt_dlerror ();
175       jstring str = path->concat (JvNewStringLatin1 (": "));
176       str = str->concat (JvNewStringLatin1 (msg));
177       throw new UnsatisfiedLinkError (str);
178     }
179
180   add_library (h);
181
182   void *onload = lt_dlsym (h, "JNI_OnLoad");
183   if (onload != NULL)
184     {
185       JavaVM *vm = _Jv_GetJavaVM ();
186       if (vm == NULL)
187         {
188           // FIXME: what?
189           return;
190         }
191       jint vers = ((jint (*) (JavaVM *, void *)) onload) (vm, NULL);
192       if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
193           && vers != JNI_VERSION_1_4)
194         {
195           // FIXME: unload the library.
196           throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
197         }
198     }
199 #else
200   throw new UnknownError
201     (JvNewStringLatin1 (do_search
202                         ? "Runtime.loadLibrary not implemented"
203                         : "Runtime.load not implemented"));
204 #endif /* USE_LTDL */
205 }
206
207 jboolean
208 java::lang::Runtime::loadLibraryInternal (jstring lib)
209 {
210   JvSynchronize sync (this);
211   using namespace java::lang;
212 #ifdef USE_LTDL
213   jint len = _Jv_GetStringUTFLength (lib);
214   char buf[len + 1];
215   jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
216   buf[total] = '\0';
217   // FIXME: make sure path is absolute.
218   lt_dlhandle h = lt_dlopenext (buf);
219   if (h != NULL)
220     add_library (h);
221   return h != NULL;
222 #else
223   return false;
224 #endif /* USE_LTDL */
225 }
226
227 void
228 java::lang::Runtime::init (void)
229 {
230 #ifdef USE_LTDL
231   lt_dlinit ();
232   lt_dlhandle self = lt_dlopen (NULL);
233   if (self != NULL)
234     add_library (self);
235 #endif
236 }
237
238 void
239 java::lang::Runtime::runFinalization (void)
240 {
241   gnu::gcj::runtime::FinalizerThread::finalizerReady ();
242 }
243
244 jlong
245 java::lang::Runtime::totalMemory (void)
246 {
247   return _Jv_GCTotalMemory ();
248 }
249
250 jlong
251 java::lang::Runtime::maxMemory (void)
252 {
253   // We don't have a maximum.  FIXME: we might if we ask the GC for
254   // one.
255   return Long::MAX_VALUE;
256 }
257
258 void
259 java::lang::Runtime::traceInstructions (jboolean)
260 {
261   // Do nothing.
262 }
263
264 void
265 java::lang::Runtime::traceMethodCalls (jboolean)
266 {
267   // Do nothing.
268 }
269
270 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
271     && defined (HAVE_NL_LANGINFO)
272
273 static char *
274 file_encoding ()
275 {
276   setlocale (LC_CTYPE, "");
277   char *e = nl_langinfo (CODESET);
278   if (e == NULL || *e == '\0')
279     e = "8859_1";
280   return e;
281 }
282
283 #define DEFAULT_FILE_ENCODING file_encoding ()
284
285 #endif
286
287 #ifndef DEFAULT_FILE_ENCODING
288 #define DEFAULT_FILE_ENCODING "8859_1"
289 #endif
290
291 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
292
293 #if HAVE_GETPWUID_R
294 /* Use overload resolution to find out the signature of getpwuid_r.  */
295
296   /* This is Posix getpwuid_r.  */
297 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
298 static inline int
299 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
300                                    T_buf *buf_r, T_len len_r,
301                                    T_passwd **pwd_entry_ptr),
302                  uid_t user_id, struct passwd *pwd_r,
303                  char *buf_r, size_t len_r, struct passwd **pwd_entry)
304 {
305   return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
306 }
307
308 /* This is used on HPUX 10.20 */
309 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
310 static inline int
311 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
312                                    T_buf *buf_r, T_len len_r),
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);
317 }
318
319 /* This is used on IRIX 5.2.  */
320 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
321 static inline int
322 getpwuid_adaptor(T_passwd * (*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   *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
328   return (*pwd_entry == NULL) ? errno : 0;
329 }
330 #endif
331
332 void
333 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
334 {
335   // A convenience define.
336 #define SET(Prop,Val) \
337         newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
338
339   // A mixture of the Java Product Versioning Specification
340   // (introduced in 1.2), and earlier versioning properties.
341   SET ("java.version", GCJVERSION);
342   SET ("java.vendor", "Free Software Foundation, Inc.");
343   SET ("java.vendor.url", "http://gcc.gnu.org/java/");
344   SET ("java.class.version", "46.0");
345   SET ("java.vm.specification.version", "1.0");
346   SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
347   SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
348   SET ("java.vm.version", __VERSION__);
349   SET ("java.vm.vendor", "Free Software Foundation, Inc.");
350   SET ("java.vm.name", "GNU libgcj");
351   SET ("java.specification.version", "1.3");
352   SET ("java.specification.name", "Java(tm) Platform API Specification");
353   SET ("java.specification.vendor", "Sun Microsystems Inc.");
354
355   char value[100];
356 #define NAME "GNU libgcj "
357   strcpy (value, NAME);
358   strncpy (value + sizeof (NAME) - 1, __VERSION__,
359            sizeof(value) - sizeof(NAME));
360   value[sizeof (value) - 1] = '\0';
361   jstring version = JvNewStringLatin1 (value);
362   newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
363   newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
364
365   // This definition is rather arbitrary: we choose $(prefix).  In
366   // part we do this because most people specify only --prefix and
367   // nothing else when installing gcj.  Plus, people are free to
368   // redefine `java.home' with `-D' if necessary.
369   SET ("java.home", PREFIX);
370   
371   SET ("file.encoding", default_file_encoding);
372
373 #ifdef HAVE_UNAME
374   struct utsname u;
375   if (! uname (&u))
376     {
377       SET ("os.name", u.sysname);
378       SET ("os.arch", u.machine);
379       SET ("os.version", u.release);
380     }
381   else
382     {
383       SET ("os.name", "unknown");
384       SET ("os.arch", "unknown");
385       SET ("os.version", "unknown");
386     }
387 #endif /* HAVE_UNAME */
388
389 #ifndef NO_GETUID
390 #ifdef HAVE_PWD_H
391   uid_t user_id = getuid ();
392   struct passwd *pwd_entry;
393
394 #ifdef HAVE_GETPWUID_R
395   struct passwd pwd_r;
396   size_t len_r = 200;
397   char *buf_r = (char *) _Jv_AllocBytes (len_r);
398
399   while (buf_r != NULL)
400     {
401       int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
402                                 buf_r, len_r, &pwd_entry);
403       if (r == 0)
404         break;
405       else if (r != ERANGE)
406         {
407           pwd_entry = NULL;
408           break;
409         }
410       len_r *= 2;
411       buf_r = (char *) _Jv_AllocBytes (len_r);
412     }
413 #else
414   pwd_entry = getpwuid (user_id);
415 #endif /* HAVE_GETPWUID_R */
416
417   if (pwd_entry != NULL)
418     {
419       SET ("user.name", pwd_entry->pw_name);
420       SET ("user.home", pwd_entry->pw_dir);
421     }
422 #endif /* HAVE_PWD_H */
423 #endif /* NO_GETUID */
424
425 #ifdef HAVE_GETCWD
426 #ifdef HAVE_UNISTD_H
427   /* Use getcwd to set "user.dir". */
428   int buflen = 250;
429   char *buffer = (char *) malloc (buflen);
430   while (buffer != NULL)
431     {
432       if (getcwd (buffer, buflen) != NULL)
433         {
434           SET ("user.dir", buffer);
435           break;
436         }
437       if (errno != ERANGE)
438         break;
439       buflen = 2 * buflen;
440       buffer = (char *) realloc (buffer, buflen);
441     }
442   if (buffer != NULL)
443     free (buffer);
444 #endif /* HAVE_UNISTD_H */
445 #endif /* HAVE_GETCWD */
446
447   // Set user locale properties based on setlocale()
448 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
449   // We let the user choose the locale.  However, since Java differs
450   // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
451   // Java locale.  We can't use LC_ALL because it might return a full
452   // list of all the settings.  If we don't have LC_MESSAGES then we
453   // just default to `en_US'.
454   setlocale (LC_ALL, "");
455   char *locale = setlocale (LC_MESSAGES, "");
456   if (locale && strlen (locale) >= 2)
457     {
458       char buf[3];
459       buf[2] = '\0';
460       // copy the first two chars to user.language
461       strncpy (buf, locale, 2);
462       SET ("user.language", buf);
463       // if the next char is a '_', copy the two after that to user.region
464       locale += 2;
465       if (locale[0] == '_')
466         {
467           locale++;
468           strncpy (buf, locale, 2);
469           SET ("user.region", buf);
470         }
471     }
472   else
473 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
474     {
475       SET ("user.language", "en");
476       SET ("user.region", "US");
477     }  
478
479   // Set some properties according to whatever was compiled in with
480   // `-D'.
481   for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
482     {
483       const char *s, *p;
484       // Find the `='.
485       for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
486         ;
487       jstring name = JvNewStringLatin1 (p, s - p);
488       jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
489       newprops->put (name, val);
490     }
491
492   // Set the system properties from the user's environment.
493 #ifndef DISABLE_GETENV_PROPERTIES
494   if (_Jv_Environment_Properties)
495     {
496       size_t i = 0;
497
498       while (_Jv_Environment_Properties[i].key)
499         {
500           SET (_Jv_Environment_Properties[i].key, 
501                _Jv_Environment_Properties[i].value);
502           i++;
503         }
504     }
505 #endif
506
507   if (_Jv_Jar_Class_Path)
508     newprops->put(JvNewStringLatin1 ("java.class.path"),
509                   JvNewStringLatin1 (_Jv_Jar_Class_Path));
510   else
511     {
512       // FIXME: find libgcj.zip and append its path?
513       char *classpath = ::getenv("CLASSPATH");
514       jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
515       java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
516       
517       if (classpath)
518         {
519           sb->append (JvNewStringLatin1 (classpath));
520 #ifdef WIN32
521           sb->append ((jchar) ';');
522 #else
523           sb->append ((jchar) ':');
524 #endif
525         }
526       if (cp != NULL)
527         sb->append (cp);
528       else
529         sb->append ((jchar) '.');
530       
531       newprops->put(JvNewStringLatin1 ("java.class.path"),
532                       sb->toString ());
533     }
534
535   // Allow platform specific settings and overrides.
536   _Jv_platform_initProperties (newprops);
537 }
538
539 java::lang::Process *
540 java::lang::Runtime::execInternal (jstringArray cmd,
541                                    jstringArray env)
542 {
543   return new java::lang::ConcreteProcess (cmd, env);
544 }
545
546 jint
547 java::lang::Runtime::availableProcessors (void)
548 {
549   // FIXME: find the real value.
550   return 1;
551 }
552
553 jstring
554 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
555 {
556   java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
557   sb->append(pathname);
558   if (pathname->length() > 0)
559     {
560       // FIXME: use platform function here.
561 #ifdef WIN32
562       sb->append ((jchar) '\\');
563 #else
564       sb->append ((jchar) '/');
565 #endif
566     }
567
568   // FIXME: use platform function here.
569 #ifndef WIN32
570   sb->append (JvNewStringLatin1 ("lib"));
571 #endif
572
573   sb->append(libname);
574
575   // FIXME: use platform function here.
576 #ifdef WIN32
577   sb->append (JvNewStringLatin1 ("dll"));
578 else
579   sb->append (JvNewStringLatin1 ("so"));
580 #endif
581
582   return sb->toString();
583 }