1 // natRuntime.cc - Implementation of native side of Runtime class.
2 
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007  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 #include <platform.h>
13 
14 #include <stdlib.h>
15 
16 #include <gcj/cni.h>
17 #include <jvm.h>
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/FinalizerThread.h>
25 #include <java/io/File.h>
26 #include <java/util/TimeZone.h>
27 #include <java/lang/StringBuffer.h>
28 #include <java/lang/Process.h>
29 #include <java/lang/ClassLoader.h>
30 
31 // It is convenient and safe to simply include all of these.
32 #include <java/lang/Win32Process.h>
33 #include <java/lang/EcosProcess.h>
34 #include <java/lang/PosixProcess.h>
35 
36 #include <jni.h>
37 
38 #ifdef HAVE_PWD_H
39 #include <pwd.h>
40 #endif
41 #include <errno.h>
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 
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 struct lookup_data
61 {
62   const char *symname;
63   void *result;
64 };
65 
66 static int
find_symbol(lt_dlhandle handle,lt_ptr data)67 find_symbol (lt_dlhandle handle, lt_ptr data)
68 {
69   lookup_data *ld = (lookup_data *) data;
70   ld->result = lt_dlsym (handle, ld->symname);
71   return ld->result != NULL;
72 }
73 
74 void *
_Jv_FindSymbolInExecutable(const char * symname)75 _Jv_FindSymbolInExecutable (const char *symname)
76 {
77   lookup_data data;
78   data.symname = symname;
79   data.result = NULL;
80   lt_dlforeach (find_symbol, (lt_ptr) &data);
81   return data.result;
82 }
83 
84 #else
85 
86 void *
_Jv_FindSymbolInExecutable(const char *)87 _Jv_FindSymbolInExecutable (const char *)
88 {
89   return NULL;
90 }
91 
92 #endif /* USE_LTDL */
93 
94 
95 
96 void
runFinalizationForExit()97 java::lang::Runtime::runFinalizationForExit ()
98 {
99   if (finalizeOnExit)
100     _Jv_RunAllFinalizers ();
101 }
102 
103 void
exitInternal(jint status)104 java::lang::Runtime::exitInternal (jint status)
105 {
106   // Make status right for Unix.  This is perhaps strange.
107   if (status < 0 || status > 255)
108     status = 255;
109 
110   ::exit (status);
111 }
112 
113 jlong
freeMemory(void)114 java::lang::Runtime::freeMemory (void)
115 {
116   return _Jv_GCFreeMemory ();
117 }
118 
119 void
gc(void)120 java::lang::Runtime::gc (void)
121 {
122   _Jv_RunGC ();
123 }
124 
125 #ifdef USE_LTDL
126 // List of names for JNI_OnLoad.
127 static const char *onload_names[] = _Jv_platform_onload_names;
128 #endif
129 
130 void
_load(jstring path,jboolean do_search)131 java::lang::Runtime::_load (jstring path, jboolean do_search)
132 {
133   JvSynchronize sync (this);
134   using namespace java::lang;
135 #ifdef USE_LTDL
136   jint len = _Jv_GetStringUTFLength (path);
137   char buf[len + 1 + strlen (_Jv_platform_solib_prefix)
138 	   + strlen (_Jv_platform_solib_suffix)];
139   int offset = 0;
140   if (do_search)
141     {
142       strcpy (buf, _Jv_platform_solib_prefix);
143       offset = strlen (_Jv_platform_solib_prefix);
144     }
145   jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
146   buf[offset + total] = '\0';
147 
148   char *lib_name = buf;
149 
150   if (do_search)
151     {
152       ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader ();
153 
154       if (look != NULL)
155 	{
156 	  // Don't include solib prefix in string passed to
157 	  // findLibrary.
158 	  jstring name = look->findLibrary(JvNewStringUTF(&buf[offset]));
159 	  if (name != NULL)
160 	    {
161 	      len = _Jv_GetStringUTFLength (name);
162 	      lib_name = (char *) _Jv_AllocBytes(len + 1);
163 	      total = JvGetStringUTFRegion (name, 0,
164 					    name->length(), lib_name);
165 	      lib_name[total] = '\0';
166 	      // Don't append suffixes any more; we have the full file
167 	      // name.
168 	      do_search = false;
169 	    }
170 	}
171     }
172 
173   lt_dlhandle h;
174   // FIXME: make sure path is absolute.
175   {
176     // Synchronize on java.lang.Class. This is to protect the class chain from
177     // concurrent modification by class registration calls which may be run
178     // during the dlopen().
179     JvSynchronize sync (&java::lang::Class::class$);
180     h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name);
181   }
182   if (h == NULL)
183     {
184       const char *msg = lt_dlerror ();
185       jstring str = JvNewStringLatin1 (lib_name);
186       str = str->concat (JvNewStringLatin1 (": "));
187       str = str->concat (JvNewStringLatin1 (msg));
188       throw new UnsatisfiedLinkError (str);
189     }
190 
191   // Search for JNI_OnLoad function.
192   void *onload = NULL;
193   const char **name = onload_names;
194   while (*name != NULL)
195     {
196       onload = lt_dlsym (h, *name);
197       if (onload != NULL)
198 	break;
199       ++name;
200     }
201 
202   if (onload != NULL)
203     {
204       JavaVM *vm = _Jv_GetJavaVM ();
205       if (vm == NULL)
206 	{
207 	  // FIXME: what?
208 	  return;
209 	}
210 
211       // Push a new frame so that JNI_OnLoad will get the right class
212       // loader if it calls FindClass.
213       ::java::lang::ClassLoader *loader
214 	  = _Jv_StackTrace::GetFirstNonSystemClassLoader();
215       JNIEnv *env = _Jv_GetJNIEnvNewFrameWithLoader (loader);
216       jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
217       _Jv_JNI_PopSystemFrame (env);
218       if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
219 	  && vers != JNI_VERSION_1_4)
220 	{
221 	  // FIXME: unload the library.
222 	  throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
223 	}
224     }
225 #else
226   throw new UnknownError
227     (JvNewStringLatin1 (do_search
228 			? "Runtime.loadLibrary not implemented"
229 			: "Runtime.load not implemented"));
230 #endif /* USE_LTDL */
231 }
232 
233 jboolean
loadLibraryInternal(jstring lib)234 java::lang::Runtime::loadLibraryInternal (jstring lib)
235 {
236   JvSynchronize sync (this);
237   using namespace java::lang;
238 #ifdef USE_LTDL
239   jint len = _Jv_GetStringUTFLength (lib);
240   char buf[len + 1];
241   jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
242   buf[total] = '\0';
243   // FIXME: make sure path is absolute.
244   lt_dlhandle h = lt_dlopenext (buf);
245   return h != NULL;
246 #else
247   return false;
248 #endif /* USE_LTDL */
249 }
250 
251 void
init(void)252 java::lang::Runtime::init (void)
253 {
254 #ifdef USE_LTDL
255   lt_dlinit ();
256   // Set module load path.
257   lt_dlsetsearchpath (_Jv_Module_Load_Path);
258   // Make sure self is opened.
259   lt_dlopen (NULL);
260 #endif
261 }
262 
263 void
runFinalization(void)264 java::lang::Runtime::runFinalization (void)
265 {
266   gnu::gcj::runtime::FinalizerThread::finalizerReady ();
267 }
268 
269 jlong
totalMemory(void)270 java::lang::Runtime::totalMemory (void)
271 {
272   return _Jv_GCTotalMemory ();
273 }
274 
275 jlong
maxMemory(void)276 java::lang::Runtime::maxMemory (void)
277 {
278   // We don't have a maximum.  FIXME: we might if we ask the GC for
279   // one.
280   return Long::MAX_VALUE;
281 }
282 
283 void
traceInstructions(jboolean)284 java::lang::Runtime::traceInstructions (jboolean)
285 {
286   // Do nothing.
287 }
288 
289 void
traceMethodCalls(jboolean)290 java::lang::Runtime::traceMethodCalls (jboolean)
291 {
292   // Do nothing.
293 }
294 
295 java::lang::Process *
execInternal(jstringArray cmd,jstringArray env,java::io::File * dir)296 java::lang::Runtime::execInternal (jstringArray cmd,
297 				   jstringArray env,
298 				   java::io::File *dir)
299 {
300   return new _Jv_platform_process (cmd, env, dir, false);
301 }
302 
303 jint
availableProcessors(void)304 java::lang::Runtime::availableProcessors (void)
305 {
306   // FIXME: find the real value.
307   return 1;
308 }
309 
310 jstring
nativeGetLibname(jstring pathname,jstring libname)311 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
312 {
313   java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
314   sb->append(pathname);
315   if (pathname->length() > 0)
316     sb->append (_Jv_platform_file_separator);
317 
318   sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix));
319   sb->append(libname);
320   sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix));
321 
322   return sb->toString();
323 }
324