用 Java 启动 Shell 脚本并在退出时销毁所有进程

Don*_*mpf 5 linux bash shell processing

我需要一些特殊的设置来控制 LED 墙。可悲的是,我无法真正改变我使用的编程语言。我的设置如下所示:

处理(一些疯狂的 java fork ......)草图在启动过程后开始。处理草图扫描文件夹中的子文件夹(可以启动和控制 LED 墙的其他草图)并启动 Web 服务器。服务器呈现一个包含所有扫描文件夹的列表。单击“Webserver”通过 ProcessBuilder 启动选定的 Sketch。处理草图如下所示:

import http.*;
import java.util.*;
import java.lang.*;

SimpleHTTPServer server;
String prog = "";
int ExitValue = 1;
ProcessBuilder preparedsketch;
Process runningsketch;

void setup() {
  SimpleHTTPServer.useIndexHtml = false;
  server = new SimpleHTTPServer(this);
  TemplateFileHandler templateHandler = new ResultFiles("index.ftl");
  server.createContext("", templateHandler);
}


class ResultFiles extends TemplateFileHandler {
  public ResultFiles(String templateFileName) {
    super(templateFileName);
  }
  void createMap() {
    Map<String, String> params = queryToMap();
    if (params.containsKey("prog")) {
      if (params.get("prog").equals(prog)) {
        println("Has not changed");
      } else {
        println("PrevProcess: " + runningsketch);
        if (runningsketch != null) {
          println("Killing: " + runningsketch);
          runningsketch.destroy();
        }
        prog = params.get("prog");
        try {
          runningsketch = new ProcessBuilder("/Users/kessleml/dev/pixelpusher/base/processing-quit.sh", "--sketch=/Users/kessleml/dev/pixelpusher/base/sketches/pixelpusher_colourcycle_halloween", "--run").start();
          // runningsketch = new ProcessBuilder("/usr/local/bin/processing-java", "--force", "--sketch=" + sketchPath("sketches/" + prog + "/"), "--no-java", "--run").start();
        } catch (IOException ex) {
          println(ex);
        }
        println("ProjChagned: " + prog);
        println("NewProcess: " + runningsketch);
      }
    }

    File files = new File(sketchPath("sketches"));
    String[] fileslist = files.list();
    addVariable("files", fileslist);
    addVariable("selectedprog", prog);
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切正常。但是,如果我改变了(点击网站上的另一个 Sketch),我当然想关闭一个正在运行的(和循环的)Sketch。问题是:

当我通过runninngsketch = new ProcessBuilder("Path/To/ProcessingCLI", "--sketch=Path/To/Selected/Sketch", "--run").start();多个进程启动选定的 Sketch 时。这样做的原因是 ProcessingCLI 文件:

#!/bin/sh

# Prevents processing-java from stealing focus, see:
# https://github.com/processing/processing/issues/3996.
OPTION_FOR_HEADLESS_RUN=""
for ARG in "$@"
do
    if [ "$ARG" = "--build" ]; then
        OPTION_FOR_HEADLESS_RUN="-Djava.awt.headless=true"
    fi
done

cd "/Applications/Processing.app/Contents/Java" && /Applications/Processing.app/Contents/PlugIns/jdk1.8.0_74.jdk/Contents/Home/jre/bin/java -Djna.nosys=true $OPTION_FOR_HEADLESS_RUN -cp "ant-launcher.jar:ant.jar:core.jar:jna.jar:pde.jar:core/library/core.jar:core/library/gluegen-rt-natives-linux-amd64.jar:core/library/gluegen-rt-natives-linux-armv6hf.jar:core/library/gluegen-rt-natives-linux-i586.jar:core/library/gluegen-rt-natives-macosx-universal.jar:core/library/gluegen-rt-natives-windows-amd64.jar:core/library/gluegen-rt-natives-windows-i586.jar:core/library/gluegen-rt.jar:core/library/jogl-all-natives-linux-amd64.jar:core/library/jogl-all-natives-linux-armv6hf.jar:core/library/jogl-all-natives-linux-i586.jar:core/library/jogl-all-natives-macosx-universal.jar:core/library/jogl-all-natives-windows-amd64.jar:core/library/jogl-all-natives-windows-i586.jar:core/library/jogl-all.jar:modes/java/mode/antlr.jar:modes/java/mode/classpath-explorer-1.0.jar:modes/java/mode/com.ibm.icu.jar:modes/java/mode/JavaMode.jar:modes/java/mode/jdi.jar:modes/java/mode/jdimodel.jar:modes/java/mode/jdtCompilerAdapter.jar:modes/java/mode/jsoup-1.7.1.jar:modes/java/mode/org.eclipse.core.contenttype.jar:modes/java/mode/org.eclipse.core.jobs.jar:modes/java/mode/org.eclipse.core.resources.jar:modes/java/mode/org.eclipse.core.runtime.jar:modes/java/mode/org.eclipse.equinox.common.jar:modes/java/mode/org.eclipse.equinox.preferences.jar:modes/java/mode/org.eclipse.jdt.core.jar:modes/java/mode/org.eclipse.osgi.jar:modes/java/mode/org.eclipse.text.jar:modes/java/mode/org.netbeans.swing.outline.jar" processing.mode.java.Commander "$@"
Run Code Online (Sandbox Code Playgroud)

因此 ProcessBuilder 启动三个进程:一个 sh-process 启动两个 Java-Children-Processes。当我使用runningsketch.destroy()它时,它只会杀死 sh 进程。两个 Java 进程继续运行。(不确定这是否也是因为这个错误:http : //bugs.java.com/bugdatabase/view_bug.do?bug_id=4770092因为我是在 MacOS Yosemite 上开发的。最终产品应该在 Linux 机器上运行。)

我的解决方案是编写一个新的 sh 脚本,通过trap以下方式杀死其所有子项:

#!/bin/sh

OPTION_FOR_HEADLESS_RUN=""

function killAllChildren {
    kill -9 -$(ps -o pgid= $$ | grep -o '[0-9]*')
}

trap killAllChildren SIGTERM SIGKILL
# trap "trap - SIGTERM && kill -- $$" SIGINT SIGTERM EXIT

cd "/Applications/Processing.app/Contents/Java"

/Applications/Processing.app/Contents/PlugIns/jdk1.8.0_74.jdk/Contents/Home/jre/bin/java -Djna.nosys=true $OPTION_FOR_HEADLESS_RUN -cp "ant-launcher.jar:ant.jar:core.jar:jna.jar:pde.jar:core/library/core.jar:core/library/gluegen-rt-natives-linux-amd64.jar:core/library/gluegen-rt-natives-linux-armv6hf.jar:core/library/gluegen-rt-natives-linux-i586.jar:core/library/gluegen-rt-natives-macosx-universal.jar:core/library/gluegen-rt-natives-windows-amd64.jar:core/library/gluegen-rt-natives-windows-i586.jar:core/library/gluegen-rt.jar:core/library/jogl-all-natives-linux-amd64.jar:core/library/jogl-all-natives-linux-armv6hf.jar:core/library/jogl-all-natives-linux-i586.jar:core/library/jogl-all-natives-macosx-universal.jar:core/library/jogl-all-natives-windows-amd64.jar:core/library/jogl-all-natives-windows-i586.jar:core/library/jogl-all.jar:modes/java/mode/antlr.jar:modes/java/mode/classpath-explorer-1.0.jar:modes/java/mode/com.ibm.icu.jar:modes/java/mode/JavaMode.jar:modes/java/mode/jdi.jar:modes/java/mode/jdimodel.jar:modes/java/mode/jdtCompilerAdapter.jar:modes/java/mode/jsoup-1.7.1.jar:modes/java/mode/org.eclipse.core.contenttype.jar:modes/java/mode/org.eclipse.core.jobs.jar:modes/java/mode/org.eclipse.core.resources.jar:modes/java/mode/org.eclipse.core.runtime.jar:modes/java/mode/org.eclipse.equinox.common.jar:modes/java/mode/org.eclipse.equinox.preferences.jar:modes/java/mode/org.eclipse.jdt.core.jar:modes/java/mode/org.eclipse.osgi.jar:modes/java/mode/org.eclipse.text.jar:modes/java/mode/org.netbeans.swing.outline.jar" processing.mode.java.Commander "$@"
Run Code Online (Sandbox Code Playgroud)

但不知何故,这也不起作用。即使启动新的 sh 脚本并向启动的 sh 进程发送例如 SIGTERM,也不会破坏两个 Java 进程和 sh 进程。

Don*_*mpf 2

我找到了解决方案:

Java 发送了一个 SIGTERM 信号,所以我必须捕获这个信号。但 java/processing 文件不是问题,sh 脚本没有按预期工作。

我必须添加& wait到我的脚本的 和 。否则 SIGTERM 无法被捕获(请参阅这篇文章:https ://apple.stackexchange.com/questions/123631/why-does-a-shell-script-trapping-sigterm-work-when-run-manually-but-not-当-ru)。

而且杀戮过程也没有顺利进行。我必须杀死所有子进程,即 sh 脚本本身,但不能杀死 sh 脚本的父进程(在本用例中是网络服务器等)。所以我编写了一个函数来查找所有子进程并杀死它们。诸如此类的事情kill -9 -$(ps -o pgid= $$ | grep -o '[0-9]*')不起作用,因为他们杀死了整棵树。最终 sh 文件如下所示:

#!/bin/sh

function killAllChildren {
    getChild $$
    pkill -TERM -P $$
}

function getChild() {
    cpids=`pgrep -P $1|xargs`
    for cpid in $cpids;
    do
        kill -15 $cpid
        getChild $cpid
    done
}

trap killAllChildren SIGUSR1 SIGTERM SIGKILL EXIT

cd "/Applications/Processing.app/Contents/Java"

/Applications/Processing.app/Contents/PlugIns/jdk1.8.0_74.jdk/Contents/Home/jre/bin/java -Djna.nosys=true -cp "ant-launcher.jar:ant.jar:core.jar:jna.jar:pde.jar:core/library/core.jar:core/library/gluegen-rt-natives-linux-amd64.jar:core/library/gluegen-rt-natives-linux-armv6hf.jar:core/library/gluegen-rt-natives-linux-i586.jar:core/library/gluegen-rt-natives-macosx-universal.jar:core/library/gluegen-rt-natives-windows-amd64.jar:core/library/gluegen-rt-natives-windows-i586.jar:core/library/gluegen-rt.jar:core/library/jogl-all-natives-linux-amd64.jar:core/library/jogl-all-natives-linux-armv6hf.jar:core/library/jogl-all-natives-linux-i586.jar:core/library/jogl-all-natives-macosx-universal.jar:core/library/jogl-all-natives-windows-amd64.jar:core/library/jogl-all-natives-windows-i586.jar:core/library/jogl-all.jar:modes/java/mode/antlr.jar:modes/java/mode/classpath-explorer-1.0.jar:modes/java/mode/com.ibm.icu.jar:modes/java/mode/JavaMode.jar:modes/java/mode/jdi.jar:modes/java/mode/jdimodel.jar:modes/java/mode/jdtCompilerAdapter.jar:modes/java/mode/jsoup-1.7.1.jar:modes/java/mode/org.eclipse.core.contenttype.jar:modes/java/mode/org.eclipse.core.jobs.jar:modes/java/mode/org.eclipse.core.resources.jar:modes/java/mode/org.eclipse.core.runtime.jar:modes/java/mode/org.eclipse.equinox.common.jar:modes/java/mode/org.eclipse.equinox.preferences.jar:modes/java/mode/org.eclipse.jdt.core.jar:modes/java/mode/org.eclipse.osgi.jar:modes/java/mode/org.eclipse.text.jar:modes/java/mode/org.netbeans.swing.outline.jar" processing.mode.java.Commander "$@" & wait
Run Code Online (Sandbox Code Playgroud)