Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / native / jni / java-lang / java_lang_VMProcess.c
blob169c7850172552c8bc359b8262e54a6dac3348b7
1 /* java_lang_VMProcess.c -- native code for java.lang.VMProcess
2 Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 #include <config.h>
40 #include "java_lang_VMProcess.h"
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <signal.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <stdio.h>
51 #include "target_native.h"
52 #include "target_native_misc.h"
54 /* Internal functions */
55 static char *copy_string (JNIEnv * env, jobject string);
56 static char *copy_elem (JNIEnv * env, jobject stringArray, jint i);
58 /* Some O/S's don't declare 'environ' */
59 #if HAVE_CRT_EXTERNS_H
60 /* Darwin does not have a variable named environ
61 but has a function which you can get the environ
62 variable with. */
63 #include <crt_externs.h>
64 #define environ (*_NSGetEnviron())
65 #else
66 extern char **environ;
67 #endif /* HAVE_CRT_EXTERNS_H */
70 * Internal helper function to copy a String in UTF-8 format.
72 static char *
73 copy_string (JNIEnv * env, jobject string)
75 char errbuf[64];
76 const char *utf;
77 jclass clazz;
78 char *copy;
80 /* Check for null */
81 if (string == NULL)
83 clazz = (*env)->FindClass (env, "java/lang/NullPointerException");
84 if ((*env)->ExceptionOccurred (env))
85 return NULL;
86 (*env)->ThrowNew (env, clazz, NULL);
87 (*env)->DeleteLocalRef (env, clazz);
88 return NULL;
91 /* Extract UTF-8 */
92 utf = (*env)->GetStringUTFChars (env, string, NULL);
93 if ((*env)->ExceptionOccurred (env))
94 return NULL;
96 /* Copy it */
97 if ((copy = strdup (utf)) == NULL)
99 TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf, sizeof (errbuf),
100 "strdup: %s", strerror (errno));
101 clazz = (*env)->FindClass (env, "java/lang/InternalError");
102 if ((*env)->ExceptionOccurred (env))
103 return NULL;
104 (*env)->ThrowNew (env, clazz, errbuf);
105 (*env)->DeleteLocalRef (env, clazz);
108 /* Done */
109 (*env)->ReleaseStringUTFChars (env, string, utf);
110 return copy;
114 * Internal helper function to copy a String[] element in UTF-8 format.
116 static char *
117 copy_elem (JNIEnv * env, jobject stringArray, jint i)
119 jobject elem;
120 char *rtn;
122 elem = (*env)->GetObjectArrayElement (env, stringArray, i);
123 if ((*env)->ExceptionOccurred (env))
124 return NULL;
125 if ((rtn = copy_string (env, elem)) == NULL)
126 return NULL;
127 (*env)->DeleteLocalRef (env, elem);
128 return rtn;
132 * private final native void nativeSpawn(String[], String[], File)
133 * throws java/io/IOException
135 JNIEXPORT void JNICALL
136 Java_java_lang_VMProcess_nativeSpawn (JNIEnv * env, jobject this,
137 jobjectArray cmdArray,
138 jobjectArray envArray, jobject dirFile)
140 int fds[3][2] = { {-1, -1}, {-1, -1}, {-1, -1} };
141 jobject streams[3] = { NULL, NULL, NULL };
142 jobject dirString = NULL;
143 char **newEnviron = NULL;
144 jsize cmdArrayLen = 0;
145 jsize envArrayLen = 0;
146 char **strings = NULL;
147 int num_strings = 0;
148 char *dir = NULL;
149 pid_t pid = -1;
150 char errbuf[64];
151 jmethodID method;
152 jclass clazz;
153 int i;
155 /* Check for null */
156 if (cmdArray == NULL)
157 goto null_pointer_exception;
159 /* Invoke dirFile.getPath() */
160 if (dirFile != NULL)
162 clazz = (*env)->FindClass (env, "java/io/File");
163 if ((*env)->ExceptionOccurred (env))
164 return;
165 method = (*env)->GetMethodID (env,
166 clazz, "getPath", "()Ljava/lang/String;");
167 if ((*env)->ExceptionOccurred (env))
168 return;
169 dirString = (*env)->CallObjectMethod (env, dirFile, method);
170 if ((*env)->ExceptionOccurred (env))
171 return;
172 (*env)->DeleteLocalRef (env, clazz);
176 * Allocate array of C strings. We put all the C strings we need to
177 * handle the command parameters, the new environment, and the new
178 * directory into a single array for simplicity of (de)allocation.
180 cmdArrayLen = (*env)->GetArrayLength (env, cmdArray);
181 if (cmdArrayLen == 0)
182 goto null_pointer_exception;
183 if (envArray != NULL)
184 envArrayLen = (*env)->GetArrayLength (env, envArray);
185 if ((strings = malloc (((cmdArrayLen + 1)
186 + (envArray != NULL ? envArrayLen + 1 : 0)
187 + (dirString !=
188 NULL ? 1 : 0)) * sizeof (*strings))) == NULL)
190 TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf,
191 sizeof (errbuf), "malloc: %s",
192 strerror (errno));
193 goto out_of_memory;
196 /* Extract C strings from the various String parameters */
197 for (i = 0; i < cmdArrayLen; i++)
199 if ((strings[num_strings++] = copy_elem (env, cmdArray, i)) == NULL)
200 goto done;
202 strings[num_strings++] = NULL; /* terminate array with NULL */
203 if (envArray != NULL)
205 newEnviron = strings + num_strings;
206 for (i = 0; i < envArrayLen; i++)
208 if ((strings[num_strings++] = copy_elem (env, envArray, i)) == NULL)
209 goto done;
211 strings[num_strings++] = NULL; /* terminate array with NULL */
213 if (dirString != NULL)
215 if ((dir = copy_string (env, dirString)) == NULL)
216 goto done;
217 strings[num_strings++] = dir;
220 /* Create inter-process pipes */
221 for (i = 0; i < 3; i++)
223 if (pipe (fds[i]) == -1)
225 TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf,
226 sizeof (errbuf), "pipe: %s",
227 strerror (errno));
228 goto system_error;
232 /* Set close-on-exec flag for parent's ends of pipes */
233 (void) fcntl (fds[0][1], F_SETFD, 1);
234 (void) fcntl (fds[1][0], F_SETFD, 1);
235 (void) fcntl (fds[2][0], F_SETFD, 1);
237 /* Fork into parent and child processes */
238 if ((pid = fork ()) == (pid_t) - 1)
240 TARGET_NATIVE_MISC_FORMAT_STRING1 (errbuf,
241 sizeof (errbuf), "fork: %s",
242 strerror (errno));
243 goto system_error;
246 /* Child becomes the new process */
247 if (pid == 0)
249 char *const path = strings[0];
251 /* Move file descriptors to standard locations */
252 if (fds[0][0] != 0)
254 if (dup2 (fds[0][0], 0) == -1)
256 fprintf (stderr, "dup2: %s", strerror (errno));
257 exit (127);
259 close (fds[0][0]);
261 if (fds[1][1] != 1)
263 if (dup2 (fds[1][1], 1) == -1)
265 fprintf (stderr, "dup2: %s", strerror (errno));
266 exit (127);
268 close (fds[1][1]);
270 if (fds[2][1] != 2)
272 if (dup2 (fds[2][1], 2) == -1)
274 fprintf (stderr, "dup2: %s", strerror (errno));
275 exit (127);
277 close (fds[2][1]);
280 /* Change into destination directory */
281 if (dir != NULL && chdir (dir) == -1)
283 fprintf (stderr, "%s: %s", dir, strerror (errno));
284 exit (127);
287 /* Make argv[0] last component of executable pathname */
288 /* XXX should use "file.separator" property here XXX */
289 for (i = strlen (path); i > 0 && path[i - 1] != '/'; i--);
290 strings[0] = path + i;
292 /* Set new environment */
293 if (newEnviron != NULL)
294 environ = newEnviron;
296 /* Execute new program (this will close the parent end of the pipes) */
297 execvp (path, strings);
299 /* Failed */
300 fprintf (stderr, "%s: %s", path, strerror (errno));
301 exit (127);
304 /* Create Input/OutputStream objects around parent file descriptors */
305 clazz = (*env)->FindClass (env, "gnu/java/nio/channels/FileChannelImpl");
306 if ((*env)->ExceptionOccurred (env))
307 goto done;
308 method = (*env)->GetMethodID (env, clazz, "<init>", "(II)V");
309 if ((*env)->ExceptionOccurred (env))
310 goto done;
311 for (i = 0; i < 3; i++)
313 /* Mode is WRITE (2) for in and READ (1) for out and err. */
314 const int fd = fds[i][i == 0];
315 const int mode = (i == 0) ? 2 : 1;
316 jclass sclazz;
317 jmethodID smethod;
319 jobject channel = (*env)->NewObject (env, clazz, method, fd, mode);
320 if ((*env)->ExceptionOccurred (env))
321 goto done;
323 if (mode == 2)
324 sclazz = (*env)->FindClass (env, "java/io/FileOutputStream");
325 else
326 sclazz = (*env)->FindClass (env, "java/io/FileInputStream");
327 if ((*env)->ExceptionOccurred (env))
328 goto done;
330 smethod = (*env)->GetMethodID (env, sclazz, "<init>",
331 "(Lgnu/java/nio/channels/FileChannelImpl;)V");
332 if ((*env)->ExceptionOccurred (env))
333 goto done;
335 streams[i] = (*env)->NewObject (env, sclazz, smethod, channel);
336 if ((*env)->ExceptionOccurred (env))
337 goto done;
339 (*env)->DeleteLocalRef (env, sclazz);
341 (*env)->DeleteLocalRef (env, clazz);
343 /* Invoke VMProcess.setProcessInfo() to update VMProcess object */
344 method = (*env)->GetMethodID (env,
345 (*env)->GetObjectClass (env, this),
346 "setProcessInfo",
347 "(Ljava/io/OutputStream;Ljava/io/InputStream;Ljava/io/InputStream;J)V");
348 if ((*env)->ExceptionOccurred (env))
349 goto done;
350 (*env)->CallVoidMethod (env, this, method,
351 streams[0], streams[1], streams[2], (jlong) pid);
352 if ((*env)->ExceptionOccurred (env))
353 goto done;
355 done:
357 * We get here in both the success and failure cases in the
358 * parent process. Our goal is to clean up the mess we created.
361 /* Close child's ends of pipes */
362 for (i = 0; i < 3; i++)
364 const int fd = fds[i][i != 0];
366 if (fd != -1)
367 close (fd);
371 * Close parent's ends of pipes if Input/OutputStreams never got created.
372 * This can only happen in a failure case. If a Stream object
373 * was created for a file descriptor, we don't close it because it
374 * will get closed when the Stream object is finalized.
376 for (i = 0; i < 3; i++)
378 const int fd = fds[i][i == 0];
380 if (fd != -1 && streams[i] == NULL)
381 close (fd);
384 /* Free C strings */
385 while (num_strings > 0)
386 free (strings[--num_strings]);
387 free (strings);
389 /* Done */
390 return;
392 null_pointer_exception:
393 clazz = (*env)->FindClass (env, "java/lang/NullPointerException");
394 if ((*env)->ExceptionOccurred (env))
395 goto done;
396 (*env)->ThrowNew (env, clazz, NULL);
397 (*env)->DeleteLocalRef (env, clazz);
398 goto done;
400 out_of_memory:
401 clazz = (*env)->FindClass (env, "java/lang/InternalError");
402 if ((*env)->ExceptionOccurred (env))
403 goto done;
404 (*env)->ThrowNew (env, clazz, errbuf);
405 (*env)->DeleteLocalRef (env, clazz);
406 goto done;
408 system_error:
409 clazz = (*env)->FindClass (env, "java/io/IOException");
410 if ((*env)->ExceptionOccurred (env))
411 goto done;
412 (*env)->ThrowNew (env, clazz, errbuf);
413 (*env)->DeleteLocalRef (env, clazz);
414 goto done;
418 * private static final native boolean nativeReap()
420 JNIEXPORT jboolean JNICALL
421 Java_java_lang_VMProcess_nativeReap (JNIEnv * env, jclass clazz)
423 char ebuf[64];
424 jfieldID field;
425 jint status;
426 pid_t pid;
428 /* Try to reap a child process, but don't block */
429 if ((pid = waitpid ((pid_t) - 1, &status, WNOHANG)) == 0)
430 return JNI_FALSE;
432 /* Check result from waitpid() */
433 if (pid == (pid_t) - 1)
435 if (errno == ECHILD || errno == EINTR)
436 return JNI_FALSE;
437 TARGET_NATIVE_MISC_FORMAT_STRING2 (ebuf,
438 sizeof (ebuf), "waitpid(%ld): %s",
439 (long) pid, strerror (errno));
440 clazz = (*env)->FindClass (env, "java/lang/InternalError");
441 if ((*env)->ExceptionOccurred (env))
442 return JNI_FALSE;
443 (*env)->ThrowNew (env, clazz, ebuf);
444 (*env)->DeleteLocalRef (env, clazz);
445 return JNI_FALSE;
448 /* Get exit code; for signal termination return negative signal value XXX */
449 if (WIFEXITED (status))
450 status = (jint) (jbyte) WEXITSTATUS (status);
451 else if (WIFSIGNALED (status))
452 status = -(jint) WTERMSIG (status);
453 else
454 return JNI_FALSE; /* process merely stopped; ignore */
456 /* Return process pid and exit status */
457 field = (*env)->GetStaticFieldID (env, clazz, "reapedPid", "J");
458 if ((*env)->ExceptionOccurred (env))
459 return JNI_FALSE;
460 (*env)->SetStaticLongField (env, clazz, field, (jlong) pid);
461 if ((*env)->ExceptionOccurred (env))
462 return JNI_FALSE;
463 field = (*env)->GetStaticFieldID (env, clazz, "reapedExitValue", "I");
464 if ((*env)->ExceptionOccurred (env))
465 return JNI_FALSE;
466 (*env)->SetStaticIntField (env, clazz, field, status);
467 if ((*env)->ExceptionOccurred (env))
468 return JNI_FALSE;
470 /* Done */
471 return JNI_TRUE;
475 * private static final native void nativeKill(long)
477 JNIEXPORT void JNICALL
478 Java_java_lang_VMProcess_nativeKill (JNIEnv * env, jclass clazz, jlong pid)
480 char ebuf[64];
482 if (kill ((pid_t) pid, SIGKILL) == -1)
484 TARGET_NATIVE_MISC_FORMAT_STRING2 (ebuf,
485 sizeof (ebuf), "kill(%ld): %s",
486 (long) pid, strerror (errno));
487 clazz = (*env)->FindClass (env, "java/lang/InternalError");
488 if ((*env)->ExceptionOccurred (env))
489 return;
490 (*env)->ThrowNew (env, clazz, ebuf);
491 (*env)->DeleteLocalRef (env, clazz);