Permalink
Browse files

signals mostly work over the pty now

- ^C, ^Z, and ^\ weren't working because bash disables SIGINT, SIGQUIT
  and SIGTSTP when a command is started in the background with &.
- So I wrote another C wrapper called drip_daemon to start a background
  process without disabling these signals.
- I also moved the setsid() call from java in to drip_daemon.
  • Loading branch information...
1 parent cf6b89b commit a8cd938700ef7e569f12f14850b50e824c4a2fcb @ninjudd ninjudd committed Sep 6, 2012
Showing with 139 additions and 70 deletions.
  1. +2 −1 .gitignore
  2. +29 −23 bin/drip
  3. +47 −0 src/drip_daemon.c
  4. +51 −32 src/drip_proxy.c
  5. +10 −14 src/org/flatland/drip/Main.java
View
3 .gitignore
@@ -2,4 +2,5 @@
*.class
*.jar
*.tgz
-test/scala
+test/scala
+repl-port
View
52 bin/drip
@@ -45,15 +45,26 @@ function bootstrap {
DRIP_JAR=$(mvn_get 'drip' 'org/flatland' "$DRIP_VERSION" "$DRIP_JAR_URL")
fi
fi
+ drip_proxy=$(compile 'drip_proxy')
+ drip_daemon=$(compile 'drip_daemon')
+}
+
+function compile {
+ local base=$1
+ local src_file
+ local bin_file="$DRIP_HOME/$base"
if [[ -z $drip_dir ]]; then
- [[ -e $DRIP_PROXY_SRC ]] || http_get "$DRIP_PROXY_URL" "$proxy_src"
+ mkdir -p "$DRIP_SRC"
+ src_file=$DRIP_SRC/$base.c
+ [[ -e $src_file ]] || http_get "$DRIP_SRC_URL/$base.c" "$src_file"
else
- DRIP_PROXY_SRC=$drip_dir/src/drip_proxy.c
+ src_file=$drip_dir/src/$base.c
fi
- if [[ $DRIP_PROXY_SRC -nt $DRIP_PROXY ]]; then
- gcc $DRIP_PROXY_SRC -o $DRIP_PROXY
+ if [[ $src_file -nt $bin_file ]]; then
+ gcc $src_file -o $bin_file
fi
+ echo "$bin_file"
}
function mvn_get {
@@ -132,21 +143,15 @@ function launch_jvm {
export DRIP_INIT=${DRIP_INIT:-$(default_init_args)}
- { # Need to write the exit status to a file.
- java "${jvm_args[@]}" -Djava.awt.headless=true "-Xbootclasspath/a:$DRIP_JAR:$JNA_JAR" \
- org.flatland.drip.Main "$main_class" "$jvm_dir" &
- echo $! > "$jvm_dir/pid"
- wait %%
- status=$?
- [[ -e $jvm_dir/status ]] && echo $status > "$jvm_dir/status"
- } > /dev/null &
- disown %%
+ $drip_daemon $JAVA_CMD "${jvm_args[@]}" -Djava.awt.headless=true \
+ "-Xbootclasspath/a:$DRIP_JAR:$JNA_JAR" \
+ org.flatland.drip.Main "$main_class" "$jvm_dir" > /dev/null
fi
}
function lock_dir {
if mkdir "$jvm_dir/lock" 2> /dev/null; then
- if kill -0 $(cat "$jvm_dir/pid") 2> /dev/null; then
+ if kill -0 $(cat "$jvm_dir/jvm.pid") 2> /dev/null; then
echo $$ > "$jvm_dir/client.pid"
active_jvm_dir=$jvm_dir
fi
@@ -175,7 +180,7 @@ function find_jvm {
done
if [[ -z $active_jvm_dir ]]; then
- exec java "${jvm_args[@]}" "${runtime_args[@]}" "$main_class" "${main_args[@]}"
+ exec $JAVA_CMD "${jvm_args[@]}" "${runtime_args[@]}" "$main_class" "${main_args[@]}"
fi
}
@@ -184,7 +189,7 @@ function kill_jvms {
for jvm_dir in $DRIP_HOME/*/*/*-*; do
if lock_dir; then
- kill "$1" "$(cat $jvm_dir/pid)" 2> /dev/null
+ kill "$1" "$(cat $jvm_dir/jvm.pid)" 2> /dev/null
rm -rf "$jvm_dir"
killed=true
fi
@@ -240,7 +245,7 @@ function wait_for_exit {
function run_main {
send_args
- $DRIP_PROXY "$active_jvm_dir"/{in,out,err}
+ $drip_proxy "$active_jvm_dir"/{in,out,err}
wait_for_exit
@@ -251,7 +256,7 @@ function run_drip_command {
case $drip_command in
version)
echo "drip version \"$DRIP_VERSION\"" >&2
- java -version;;
+ $JAVA_CMD -version;;
kill)
kill_jvms "$2";;
ps)
@@ -260,7 +265,7 @@ function run_drip_command {
if [[ -z $drip_dir ]]; then
http_get "$DRIP_BIN_URL" "$script" || exit $?
chmod +x "$script"
- rm "$DRIP_PROXY_SRC" # need to refetch in case it has changed
+ rm -rf "$DRIP_SRC" # need to refetch in case it has changed
elif [[ -d $drip_dir/.git ]]; then
(cd "$drip_dir" && git pull)
else
@@ -283,19 +288,20 @@ DRIP_VERSION=${DRIP_VERSION:-0.0.4}
DRIP_REPO=${DRIP_REPO:-http://clojars.org/repo}
DRIP_JAR_URL=${DRIP_JAR_URL:-$DRIP_REPO/org/flatland/drip/$DRIP_VERSION/drip-$DRIP_VERSION.jar}
DRIP_BIN_URL=${DRIP_BIN_URL:-https://raw.github.com/flatland/drip/master/bin/drip}
-DRIP_PROXY_URL=${DRIP_PROXY_URL:-https://raw.github.com/flatland/drip/master/src/drip_proxy.c}
-DRIP_PROXY_SRC=${DRIP_PROXY_SRC:-$DRIP_HOME/drip_proxy.c}
-DRIP_PROXY=${DRIP_PROXY:-$DRIP_HOME/drip_proxy}
+DRIP_SRC_URL=${DRIP_SRC_URL:-https://raw.github.com/flatland/drip/master/src}
+DRIP_SRC=${DRIP_SRC:-$DRIP_HOME/src}
JNA_VERSION=${JNA_VERSION:-3.4.1}
JNA_JAR_URL=${JNA_JAR_URL:-https://raw.github.com/twall/jna/$JNA_VERSION/dist/jna.jar}
MVN_REPO=${MVN_REPO:-~/.m2/repository}
+JAVA_CMD=${JAVA_CMD:-java}
+JAVA_CMD=$(which java)
bootstrap
parse_args "$@"
if [[ -z $drip_command ]]; then
- [[ -z $java_command ]] || exec java $java_command
+ [[ -z $java_command ]] || exec $JAVA_CMD $java_command
find_jvm
run_main
status=$?
View
47 src/drip_daemon.c
@@ -0,0 +1,47 @@
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int check(char* prefix, int n) {
+ if (n < 0) {
+ perror(prefix);
+ exit(1);
+ } else {
+ return n;
+ }
+}
+
+#define LEN 1024
+
+void spit_int(char* dir, char* base, int i) {
+ static char buf[LEN];
+ snprintf(buf, LEN, "%s/%s", dir, base);
+
+ FILE* file = fopen(buf,"w");
+ fprintf(file,"%d\n", i);
+ fclose(file);
+}
+
+int main(int argc, char **argv) {
+ char* jvm_dir = argv[argc - 1];
+
+ // Start a child process and exit the parent.
+ if (check("fork parent", fork()) != 0) exit(0);
+
+ /* close(0); */
+ /* close(1); */
+ umask(0);
+
+ int pid = check("fork child", fork());
+ if (pid == 0) {
+ check("setsid", setsid());
+ check("execv", execv(argv[1], argv+1));
+ } else {
+ spit_int(jvm_dir, "jvm.pid", pid);
+
+ int status;
+ waitpid(pid, &status, 0);
+ spit_int(jvm_dir, "status", status);
+ }
+}
View
83 src/drip_proxy.c
@@ -3,16 +3,21 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#include <setjmp.h>
+#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/types.h>
#include <termios.h>
+jmp_buf env;
+char* err_prefix;
+
// Based on code from https://github.com/nelhage/reptyr
-int check(char* name, int n) {
+int check(char* prefix, int n) {
if (n < 0) {
- fprintf(stderr, "Error %d on %s\n", errno, name);
- exit(1);
+ err_prefix = prefix;
+ longjmp(env, errno);
} else {
return n;
}
@@ -68,7 +73,7 @@ void proxy(int in, int out, int err) {
}
int open_pty() {
- int fd = check("open", open("/dev/ptmx", O_RDWR));
+ int fd = check("posix_openpt", posix_openpt(O_RDWR | O_NOCTTY));
check("grantpt", grantpt(fd));
check("unlockpt", unlockpt(fd));
@@ -82,45 +87,59 @@ int open_fifo(char* path, int oflag) {
}
int main(int argc, char **argv) {
- struct termios prev;
+ if (argc != 4) {
+ fprintf(stderr, "Usage: drip_proxy in out err\n");
+ exit(1);
+ }
+
char* tty_name = ttyname(0);
+ struct termios prev;
+ int exit_code = 0;
int in = 0;
int out = 0;
int err = 0;
- if (tty_name) {
- check("tcgetcattr", tcgetattr(0, &prev));
-
- int pty = open_pty();
- char* pty_name = ptsname(pty);
-
- in = pty;
- check("symlink in", symlink(pty_name, argv[1]));
-
- struct termios raw = prev;
- cfmakeraw(&raw);
- check("tcsetattr raw", tcsetattr(0, TCSANOW, &raw));
-
- if (strcmp(tty_name, ttyname(1)) == 0) {
- out = pty;
- check("symlink out", symlink(pty_name, argv[2]));
- }
- if (strcmp(tty_name, ttyname(1)) == 0) {
- err = pty;
- check("symlink err", symlink(pty_name, argv[3]));
+ if (setjmp(env) == 0) {
+ if (tty_name) {
+ check("tcgetcattr", tcgetattr(0, &prev));
+ struct termios raw = prev;
+ cfmakeraw(&raw);
+ check("tcsetattr raw", tcsetattr(0, TCSANOW, &raw));
+
+ int pty = open_pty();
+ char* pty_name = ptsname(pty);
+
+ in = pty;
+ check("symlink in", symlink(pty_name, argv[1]));
+
+ char* out_name = ttyname(1);
+ if (out_name && strcmp(tty_name, out_name) == 0) {
+ out = pty;
+ check("symlink out", symlink(pty_name, argv[2]));
+ }
+
+ char* err_name = ttyname(2);
+ if (err_name && strcmp(tty_name, err_name) == 0) {
+ err = pty;
+ check("symlink err", symlink(pty_name, argv[3]));
+ }
}
+
+ if (!in) in = open_fifo(argv[1], O_WRONLY);
+ if (!out) out = open_fifo(argv[2], O_RDONLY);
+ if (!err) err = open_fifo(argv[3], O_RDONLY);
+
+ proxy(in, out, err);
+ } else {
+ exit_code = 1;
}
- if (!in) in = open_fifo(argv[2], O_WRONLY);
- if (!out) out = open_fifo(argv[2], O_RDONLY);
- if (!err) err = open_fifo(argv[3], O_RDONLY);
-
- proxy(in, out, err);
-
if (tty_name) {
check("tcsetattr prev", tcsetattr(0, TCSANOW, &prev));
}
- return 0;
+ if (exit_code) perror(err_prefix);
+
+ return exit_code;
}
View
24 src/org/flatland/drip/Main.java
@@ -13,6 +13,8 @@
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.LastErrorException;
+import sun.misc.Signal;
+import sun.misc.SignalHandler;
public class Main {
private List<Switchable> lazyStreams;
@@ -50,7 +52,7 @@ private void killAfterTimeout() {
// someone is already connected; let the process finish
}
}
-
+
private void startIdleKiller() {
Thread idleKiller = new Thread() {
public void run() {
@@ -62,6 +64,10 @@ public void run() {
idleKiller.start();
}
+ public static void main(String[] args) throws Exception {
+ new Main(args[0], args[1]).start();
+ }
+
public void start() throws Exception {
reopenStreams();
@@ -93,10 +99,6 @@ public void start() throws Exception {
invoke(main, split(mainArgs, "\u0000"));
}
- public static void main(String[] args) throws Exception {
- new Main(args[0], args[1]).start();
- }
-
private Method mainMethod(String className)
throws ClassNotFoundException, NoSuchMethodException {
if (className != null) {
@@ -177,8 +179,6 @@ private void setControllingTerminal() throws Exception {
Integer fd = (Integer) field.get(fdesc);
field.setAccessible(false);
- LibC libc = (LibC) Native.loadLibrary("c", LibC.class);
- libc.setsid();
libc.ioctl(fd, TIOCSCTTY, 0);
}
@@ -215,15 +215,11 @@ private String readString(Scanner s) throws IOException {
return arg;
}
- private static final int TIOCSCTTY=536900705;
- private static final int TIOCNOTTY=536900721;
+ private static final int TIOCSCTTY = 536900705;
public interface LibC extends Library {
int ioctl(int fildes, long request, Object... args) throws LastErrorException;
- int setsid() throws LastErrorException;
- int getpgrp();
- int getpid();
- int getsid(int pid);
- void exit(int status);
}
+
+ private static final LibC libc = (LibC) Native.loadLibrary("c", LibC.class);
}

0 comments on commit a8cd938

Please sign in to comment.