jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux
author duke
Sat, 01 Dec 2007 00:00:00 +0000
changeset 2 90ce3da70b43
child 48 dc5744ca15ea
permissions -rw-r--r--
Initial load
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/* 
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 1995-2006 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package java.lang;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.io.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
/* java.lang.Process subclass in the UNIX environment.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
 * @author Mario Wolczko and Ross Knippel.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
 * @author Konstantin Kladko (ported to Linux)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
final class UNIXProcess extends Process {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
    private FileDescriptor stdin_fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
    private FileDescriptor stdout_fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
    private FileDescriptor stderr_fd;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
    private int pid;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
    private int exitcode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
    private boolean hasExited;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
    private OutputStream stdin_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
    private InputStream  stdout_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
    private InputStream  stderr_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
    /* this is for the reaping thread */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
    private native int waitForProcessExit(int pid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
    private native int forkAndExec(byte[] prog,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
				   byte[] argBlock, int argc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
				   byte[] envBlock, int envc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
				   byte[] dir,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
				   boolean redirectErrorStream,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
				   FileDescriptor stdin_fd,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
				   FileDescriptor stdout_fd,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
				   FileDescriptor stderr_fd)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
	throws IOException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    /* In the process constructor we wait on this gate until the process    */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
    /* has been created. Then we return from the constructor.               */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    /* fork() is called by the same thread which later waits for the process */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    /* to terminate */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    private static class Gate {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
        private boolean exited = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
        private IOException savedException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
        synchronized void exit() { /* Opens the gate */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
           exited = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
           this.notify();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
        synchronized void waitForExit() { /* wait until the gate is open */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
            boolean interrupted = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
            while (!exited) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
                    this.wait();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
                } catch (InterruptedException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
                    interrupted = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
            if (interrupted) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
                Thread.currentThread().interrupt();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
        void setException (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
            savedException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
        IOException getException() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
            return savedException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
    UNIXProcess(final byte[] prog,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
		final byte[] argBlock, final int argc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
		final byte[] envBlock, final int envc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
		final byte[] dir,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
		final boolean redirectErrorStream)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
    throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
	stdin_fd  = new FileDescriptor();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
	stdout_fd = new FileDescriptor();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
	stderr_fd = new FileDescriptor();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
        final Gate gate = new Gate();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
	/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
	 * For each subprocess forked a corresponding reaper thread
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
	 * is started.  That thread is the only thread which waits
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
	 * for the subprocess to terminate and it doesn't hold any
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
	 * locks while doing so.  This design allows waitFor() and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
	 * exitStatus() to be safely executed in parallel (and they
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
	 * need no native code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
	 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
	java.security.AccessController.doPrivileged(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
			    new java.security.PrivilegedAction() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
	    public Object run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
		Thread t = new Thread("process reaper") {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
		    public void run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
                        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
                            pid = forkAndExec(prog,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
					      argBlock, argc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
					      envBlock, envc,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
					      dir,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
					      redirectErrorStream,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
					      stdin_fd, stdout_fd, stderr_fd);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
                        } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                            gate.setException(e); /*remember to rethrow later*/
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
                            gate.exit();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
                            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
                        java.security.AccessController.doPrivileged(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
                        new java.security.PrivilegedAction() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
                            public Object run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
                            stdin_stream = new BufferedOutputStream(new
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
                                                    FileOutputStream(stdin_fd));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
                            stdout_stream = new BufferedInputStream(new
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
                                                    FileInputStream(stdout_fd));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
                            stderr_stream = new FileInputStream(stderr_fd);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
                            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
                        });
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
                        gate.exit(); /* exit from constructor */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
			int res = waitForProcessExit(pid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
			synchronized (UNIXProcess.this) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
			    hasExited = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
			    exitcode = res;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
			    UNIXProcess.this.notifyAll();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
			}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
		    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
		};
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
                t.setDaemon(true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
                t.start();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
		return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
	    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
	});
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        gate.waitForExit();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        IOException e = gate.getException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
        if (e != null)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
            throw new IOException(e.toString());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
    public OutputStream getOutputStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
	return stdin_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
    public InputStream getInputStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
	return stdout_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
    public InputStream getErrorStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
	return stderr_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
    public synchronized int waitFor() throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
        while (!hasExited) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
	    wait();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
	}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
	return exitcode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
    public synchronized int exitValue() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
	if (!hasExited) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
	    throw new IllegalThreadStateException("process hasn't exited");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
	}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
	return exitcode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
    private static native void destroyProcess(int pid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
    public void destroy() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
	// There is a risk that pid will be recycled, causing us to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
	// kill the wrong process!  So we only terminate processes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
	// that appear to still be running.  Even with this check,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
	// there is an unavoidable race condition here, but the window
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
	// is very small, and OSes try hard to not recycle pids too
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
	// soon, so this is quite safe.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
	synchronized (this) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
	    if (!hasExited)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
		destroyProcess(pid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
	}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            stdin_stream.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
            stdout_stream.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
            stderr_stream.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
        } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
            // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
    /* This routine initializes JNI field offsets for the class */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
    private static native void initIDs();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
    static {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
	initIDs();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
}