/*
 * @(#)UNIXProcess.java.solaris	1.33 00/05/04
 *
 * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
 * Copyright 2000 Sun Microsystems, Inc. Tous droits réservés.
 *
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 */

package java.lang;

import java.io.*; 

/* java.lang.Process subclass in the UNIX environment.
 * 
 * @author Mario Wolczko and Ross Knippel.
 */

class UNIXProcess extends Process {
    private FileDescriptor stdin_fd;
    private FileDescriptor stdout_fd;
    private FileDescriptor stderr_fd;
    private int pid;
    private int exitcode;
    private boolean hasExited;

    private OutputStream stdin_stream;
    private InputStream  stdout_stream;
    private InputStream  stderr_stream;

    /* this is for the reaping thread */
    private native int waitForProcessExit(int pid);

    private UNIXProcess() {}

    private native int forkAndExec(String cmd[], String env[], String path,
				   FileDescriptor stdin_fd,
				   FileDescriptor stdout_fd,
				   FileDescriptor stderr_fd)
	throws java.io.IOException;
  
    UNIXProcess(String cmdarray[], String env[]) throws java.io.IOException {
	this(cmdarray, env, null);
    }

    UNIXProcess(String cmdarray[], String env[], String path)
    throws java.io.IOException {

	stdin_fd = new FileDescriptor();
	stdout_fd = new FileDescriptor();
	stderr_fd = new FileDescriptor();
	
	pid = forkAndExec(cmdarray, env, path, stdin_fd, stdout_fd, stderr_fd);

	java.security.AccessController.doPrivileged(
				    new java.security.PrivilegedAction() {
	    public Object run() {
	        stdin_stream = new BufferedOutputStream(new
						    FileOutputStream(stdin_fd));
	        stdout_stream = new BufferedInputStream(new
						    FileInputStream(stdout_fd));
	        stderr_stream = new FileInputStream(stderr_fd);
		return null;
	    }
	});

	/*
	 * For each subprocess forked a corresponding reaper thread
	 * is started.  That thread is the only thread which waits
	 * for the subprocess to terminate and it doesn't hold any
	 * locks while doing so.  This design allows waitFor() and 
	 * exitStatus() to be safely executed in parallel (and they
	 * need no native code).
	 */
	 
	java.security.AccessController.doPrivileged(
			    new java.security.PrivilegedAction() {
	    public Object run() {
		Thread t = new Thread("process reaper") {
		    public void run() {
			int res = waitForProcessExit(pid);
			synchronized (UNIXProcess.this) {
			    hasExited = true;
			    exitcode = res;
			    UNIXProcess.this.notifyAll();
			}
		    }
		};
		t.setDaemon(true);
		t.start();
		return null;
	    }
	});
    }

    public OutputStream getOutputStream() {
	return stdin_stream;
    }

    public InputStream getInputStream() {
	return stdout_stream;
    }

    public InputStream getErrorStream() {
	return stderr_stream;
    }

    public synchronized int waitFor() throws InterruptedException {
        while (!hasExited) {
	    wait();
	}
	return exitcode;
    }

    public synchronized int exitValue() { 
	if (!hasExited) {
	    throw new IllegalThreadStateException("process hasn't exited");
	}
	return exitcode;
    }

    private static native void destroyProcess(int pid);
    public void destroy() {
	destroyProcess(pid);
    }

}
