Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/java/lang/UNIXProcess.java

/*
 * @(#)UNIXProcess.java	1.10 95/11/12 Chris Warth
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package java.lang;

import java.io.*; 
import java.util.Hashtable;
import java.lang.SecurityManager;

class ProcessReaper extends Thread {

    ProcessReaper() {
	SecurityManager.setScopePermission();
	setDaemon(true);
    }

    /*
     * This routine is called once from the Process Reaper thread and
     * never returns.  It's job is to catch sigchld events and pass them
     * on to class UNIXProcess.
     */ 
    private native void waitForDeath();


    public void run() {
	SecurityManager.setScopePermission();
	setName("ProcessReaper");
	SecurityManager.resetScopePermission();
	waitForDeath();
    }
}


public class UNIXProcess extends Process {
    static Hashtable subprocs = null;

    private boolean isalive = false;
    private int exit_code = 0;
    private int pid = 0;
    private FileDescriptor sync_fd;
    private FileDescriptor stdin_fd;
    private FileDescriptor stdout_fd;
    private FileDescriptor stderr_fd;
    private OutputStream stdin_stream;
    private InputStream stdout_stream;
    private InputStream stderr_stream;

    /*
     * This version of exec both forks a new subprocess and executes
     * the given command.
     */
    private native void exec(String cmd[], String env[]) throws java.io.IOException;
    private native int fork() throws java.io.IOException;

    private static synchronized void newChild(UNIXProcess p, int pid) {
	subprocs.put(new Integer(pid), p);
    }

    /*
    This method is called in response to receiving a signal
    */
    public static synchronized void deadChild(int pid, int exitcode) {
	System.err.println("Received sigchild for "+pid+" exit="+exitcode);

	UNIXProcess p = (UNIXProcess) subprocs.get(new Integer(pid));
	if (p == null) {
	    System.err.println("Warning: received SIGCHLD for nonexistant process "+pid);
	} else {
	    p.isalive = false;
	    subprocs.remove(new Integer(pid));
	    p.exit_code = exitcode;
	    try {
		/* if there is anyone doing io to the process - wake them up*/
		p.stdin_stream.close();
		p.stdout_stream.close();
		p.stderr_stream.close();
	    } catch (IOException e) {
	    }	
	    try {
		/* also wake up anyone who is doing a waitFor() */
		Class.forName("java.lang.UNIXProcess").notify();
	    } catch (ClassNotFoundException e) {
	    }
	}
    }

    private static synchronized void waitChild(int pid) throws InterruptedException {
	UNIXProcess p = (UNIXProcess) subprocs.get(new Integer(pid));
	if (p != null) {
	    try {
		Class.forName("java.lang.UNIXProcess").wait();
	    } catch (ClassNotFoundException e) {
	    }
	}
    }

    UNIXProcess(String cmdarray[], String env[]) throws java.io.IOException {
	SecurityManager.setScopePermission();
	if (subprocs == null) {
	    subprocs = new Hashtable();
	    (new ProcessReaper()).start();
	}
	SecurityManager.resetScopePermission();

	stdin_fd = new FileDescriptor();
	stdout_fd = new FileDescriptor();
	stderr_fd = new FileDescriptor();
	sync_fd = new FileDescriptor();

	if ((pid = fork()) == 0) {
	    /* child process */
	    exec(cmdarray, env);
	} else {
	    /* parent process */
	    isalive = true;
	    stdin_stream = new BufferedOutputStream(new FileOutputStream(stdin_fd));
	    stdout_stream = new BufferedInputStream(new FileInputStream(stdout_fd));
	    stderr_stream = new FileInputStream(stderr_fd);
	    newChild(this, pid);

	    FileOutputStream fp = new FileOutputStream(sync_fd);
	    fp.write(0);
	    fp.close();
	    fp = null;
	}

    }

    public OutputStream getOutputStream() {
	return stdin_stream;
    }

    public InputStream getInputStream() {
	return stdout_stream;
    }

    public InputStream getErrorStream() {
	return stderr_stream;
    }

    public int waitFor() throws InterruptedException {
	waitChild(pid);
	return exit_code;
    }

    private native int waitForUNIXProcess() throws InterruptedException;

    public int exitValue() { return exit_code; }

    public native void destroy();
}