Index: main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java
===================================================================
--- main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31697)
+++ main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31699)
@@ -751,4 +751,81 @@
 }
 
+// https://stackoverflow.com/questions/8533377/why-child-process-still-alive-after-parent-process-was-killed-in-linux
+// Didn't work for when build scripts run from GLI: kill -TERM -pid
+// but the other suggestion did work: pkill -TERM -P pid did work
+// https://unix.stackexchange.com/questions/117227/why-pidof-and-pgrep-are-behaving-differently
+// https://unix.stackexchange.com/questions/67635/elegantly-get-list-of-children-processes
+// https://stackoverflow.com/questions/994033/mac-os-x-quickest-way-to-kill-quit-an-entire-process-tree-from-within-a-cocoa-a
+// https://unix.stackexchange.com/questions/132224/is-it-possible-to-get-process-group-id-from-procâÃâÃ
+
+/**
+ * On Unix, will kill the process denoted by processID and any subprocessed this launched. Tested on a Mac.
+ * @force if true will send the -KILL (-9) signal, which may result in abrupt termination
+ * if false, will send the -TERM (-15) signal, which will allow cleanup before termination
+ * @killEntireTree if false, will terminate only the process denoted by processID, otherwise all descendants too.
+ * @return true if running the kill process returned an exit value of 0
+ * 
+*/
+static boolean killUnixProcessTreeWithID(long processID, boolean force, boolean killEntireTree) {
+    // Kill signals, their names and numerical equivalents: http://www.faqs.org/qa/qa-831.html
+
+    /*
+    String cmd = force ? "kill -KILL" : "kill -TERM"; // kill -15 vs kill -9
+    // https://stackoverflow.com/questions/8533377/why-child-process-still-alive-after-parent-process-was-killed-in-linux
+    cmd += killEntireTree ? " -" : " "; // prefix hyphen to pid to kill all subprocesses launched by pid
+    cmd = cmd + processID;
+    */
+
+    String cmd = "pkill -TERM -P " + processID;
+    if(force) {
+	cmd = "pkill -KILL -P " + processID;
+    } 
+
+    SafeProcess proc = new SafeProcess(cmd);
+    int exitValue = proc.runProcess();
+    if(exitValue != 0) {
+	log("@@@ Not able to successfull terminate process, got exitvalue " + exitValue);
+	log("@@@ Got output " + proc.getStdOutput()); 
+	log("@@@ Got err output " + proc.getStdError());
+	// caller can try again with kill -KILL, by setting force parameter to true
+	return false;
+    } else {
+	if(force) {
+	    log("@@@ Successfully sent SIGKILL to unix process tree rooted at " + processID);
+	} else { 
+	    log("@@@ Successfully sent SIGTERM to unix process tree rooted at " + processID);
+	}
+	return true;
+    }    
+}
+
+/** UNUSED. Kills only the process represented by the processID.
+ * @force if true will send the -KILL (-9) signal, which may result in abrupt termination
+ * if false, will send the -TERM (-15) signal, which will allow cleanup before termination
+ * @return true if running the kill process returned an exit value of 0
+*/
+static boolean killUnixProcessWithID(long processID, boolean force) {
+    // Kill signals, their names and numerical equivalents: http://www.faqs.org/qa/qa-831.html
+    String cmd = force ? "kill -KILL" : "kill -TERM"; // kill -15 vs kill -9
+    cmd = cmd + " " + processID;
+
+    SafeProcess proc = new SafeProcess(cmd);
+    int exitValue = proc.runProcess();
+    if(exitValue != 0) {
+	log("@@@ Not able to successfull terminate process, got exitvalue " + exitValue);
+	log("@@@ Got output " + proc.getStdOutput()); 
+	log("@@@ Got err output " + proc.getStdError());
+	// caller can try again with kill -KILL, by setting force parameter to true
+	return false;
+    } else {
+	if(force) {
+	    log("@@@ Successfully sent SIGKILL to unix process " + processID);
+	} else { 
+	    log("@@@ Successfully sent SIGTERM to unix process " + processID);
+	}
+	return true;
+    }    
+}
+
 
 // On linux and mac, p.destroy() suffices to kill processes launched by p as well.
@@ -758,10 +835,34 @@
     log("### in SafeProcess.destroyProcess(Process p)");
 
+    String osName = Utility.getOSdirName();
+
     // If it isn't windows, process.destroy() terminates any child processes too
-    if(!Utility.isWindows()) {
+    if(osName.equals("linux")) {
 	p.destroy();
 	return;
-    }	
-    
+    }
+
+    if(osName.equals("darwin")) {
+	long pid = SafeProcess.getProcessID(p);
+	/*
+	// On Macs (all Unix?) can't get the child processes of a process once it's been destroyed
+	macTerminateSubProcessesRecursively(pid, p); // pid, true)	
+	*/
+	
+	if(pid == -1) {
+	    p.destroy(); // at minimum, will have no effect if the process had already terminated 
+	} else {
+	    boolean forceKill = false;
+	    boolean killEntireProcessTree = true;
+	    if(!killUnixProcessTreeWithID(pid, !forceKill, killEntireProcessTree)) { // send sig TERM (kill -15 or kill -TERM)
+		killUnixProcessTreeWithID(pid, forceKill, killEntireProcessTree); // send sig KILL (kill -9 or kill -KILL)
+	    }
+	}
+
+	return;
+    }
+    
+    // else we're on windows:
+
     if(!SafeProcess.isAvailable("wmic")) {
 	log("wmic, used to kill subprocesses, is not available. Unable to terminate subprocesses...");
@@ -784,4 +885,44 @@
     }
     
+}
+
+
+// UNUSED
+// But if this method is needed, then need to parse childpids printed by "pgrep -P pid" and write recursive step
+// The childpids are probably listed one per line, see https://unix.stackexchange.com/questions/117227/why-pidof-and-pgrep-are-behaving-differently
+private static void macTerminateSubProcessesRecursively(long parent_pid, Process p) { //boolean isTopLevelProcess) {
+    log("@@@ Attempting to terminate mac process recursively");
+
+    // https://unix.stackexchange.com/questions/67635/elegantly-get-list-of-children-processes
+    SafeProcess proc = new SafeProcess("pgrep -P "+parent_pid);
+    int exitValue = proc.runProcess();
+    String stdOutput = proc.getStdOutput();
+    String stdErrOutput = proc.getStdError();
+
+    // now we have the child processes, can terminate the parent process
+    if(p != null) { // top level process, can just be terminated the java way with p.destroy()
+	p.destroy();
+    } else {
+	// get rid of process with current pid
+	if(!SafeProcess.killUnixProcessWithID(parent_pid, false)) { // send kill -TERM, kill -15
+	    SafeProcess.killUnixProcessWithID(parent_pid, true); // send kill -9, kill -KILL
+	}
+    }
+    
+    /*
+    // get rid of any process with current pid
+    if(!isTopLevelProcess && !SafeProcess.killUnixProcessWithID(parent_pid, false)) { // send kill -TERM, kill -15
+	SafeProcess.killUnixProcessWithID(parent_pid, true); // send kill -9, kill -KILL
+    }
+    */
+
+    if(stdOutput.trim().equals("") && stdErrOutput.trim().equals("") && exitValue == 1) {
+	log("No child processes");
+	// we're done
+	return;
+    } else {
+	log("Got childpids on STDOUT: " + stdOutput);
+	log("Got childpids on STDERR: " + stdErrOutput);
+    }
 }
 
@@ -812,5 +953,5 @@
 	p.destroy();
     } else { // terminate windows way		
-	SafeProcess.killWinProcessWithID(parent_pid); // get rid off current pid		
+	SafeProcess.killWinProcessWithID(parent_pid); // get rid of process with current pid		
     }
     
