diff --git a/src/java/com/threerings/util/keybd/i686-Linux/Makefile b/src/java/com/threerings/util/keybd/i686-Linux/Makefile index 9db89014e..fc0adc4e1 100644 --- a/src/java/com/threerings/util/keybd/i686-Linux/Makefile +++ b/src/java/com/threerings/util/keybd/i686-Linux/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.4 2003/02/18 23:06:54 ray Exp $ +# $Id: Makefile,v 1.5 2003/03/31 02:10:04 mdb Exp $ # # Executable definitions @@ -30,10 +30,12 @@ INSTALL_TARGET=${INSTALL_PATH}/${TARGET} all: ${INSTALL_TARGET} ${INSTALL_TARGET}: com_threerings_util_keybd_Keyboard.c - ${CC} ${INCLUDES} -c com_threerings_util_keybd_Keyboard.c \ + @echo Compiling Keyboard.c + @${CC} ${INCLUDES} -c com_threerings_util_keybd_Keyboard.c \ -o com_threerings_util_keybd_Keyboard.o - ${MKDIR} -p ${INSTALL_PATH} - ${CC} -o ${INSTALL_TARGET} com_threerings_util_keybd_Keyboard.o \ + @echo Creating libkeybd.so + @${MKDIR} -p ${INSTALL_PATH} + @${CC} -o ${INSTALL_TARGET} com_threerings_util_keybd_Keyboard.o \ ${LIBRARIES} ${LIBRARIES_PATH} -shared clean: diff --git a/src/java/com/threerings/util/signal/SignalManager.java b/src/java/com/threerings/util/signal/SignalManager.java new file mode 100644 index 000000000..0d87ff766 --- /dev/null +++ b/src/java/com/threerings/util/signal/SignalManager.java @@ -0,0 +1,261 @@ +// +// $Id: SignalManager.java,v 1.1 2003/03/31 02:10:04 mdb Exp $ + +package com.threerings.util.signal; + +import com.samskivert.util.HashIntMap; +import com.samskivert.util.ObserverList; +import com.threerings.util.Log; + +/** + * Uses native code to catch Unix signals and invoke callbacks on a + * separate signal handler thread. If the native library cannot be loaded, + * signal handlers will be allowed to be registered but will never be + * called. + */ +public class SignalManager +{ + /* Hangup (POSIX). */ + public static final int SIGHUP = 1; + + /* Interrupt (ANSI). */ + public static final int SIGINT = 2; + + /* Quit (POSIX). */ + public static final int SIGQUIT = 3; + + /* Illegal instruction (ANSI). */ + public static final int SIGILL = 4; + + /* Trace trap (POSIX). */ + public static final int SIGTRAP = 5; + + /* Abort (ANSI). */ + public static final int SIGABRT = 6; + + /* IOT trap (4.2 BSD). */ + public static final int SIGIOT = 6; + + /* BUS error (4.2 BSD). */ + public static final int SIGBUS = 7; + + /* Floating-point exception (ANSI). */ + public static final int SIGFPE = 8; + + /* Kill, unblockable (POSIX). */ + public static final int SIGKILL = 9; + + /* User-defined signal 1 (POSIX). */ + public static final int SIGUSR1 = 10; + + /* Segmentation violation (ANSI). */ + public static final int SIGSEGV = 11; + + /* User-defined signal 2 (POSIX). */ + public static final int SIGUSR2 = 12; + + /* Broken pipe (POSIX). */ + public static final int SIGPIPE = 13; + + /* Alarm clock (POSIX). */ + public static final int SIGALRM = 14; + + /* Termination (ANSI). */ + public static final int SIGTERM = 15; + + /* Stack fault. */ + public static final int SIGSTKFLT = 16; + + /* Child status has changed (POSIX). */ + public static final int SIGCHLD = 17; + + /* Continue (POSIX). */ + public static final int SIGCONT = 18; + + /* Stop, unblockable (POSIX). */ + public static final int SIGSTOP = 19; + + /* Keyboard stop (POSIX). */ + public static final int SIGTSTP = 20; + + /* Background read from tty (POSIX). */ + public static final int SIGTTIN = 21; + + /* Background write to tty (POSIX). */ + public static final int SIGTTOU = 22; + + /* Urgent condition on socket (4.2 BSD). */ + public static final int SIGURG = 23; + + /* CPU limit exceeded (4.2 BSD). */ + public static final int SIGXCPU = 24; + + /* File size limit exceeded (4.2 BSD). */ + public static final int SIGXFSZ = 25; + + /* Virtual alarm clock (4.2 BSD). */ + public static final int SIGVTALRM = 26; + + /* Profiling alarm clock (4.2 BSD). */ + public static final int SIGPROF = 27; + + /* Window size change (4.3 BSD, Sun). */ + public static final int SIGWINCH = 28; + + /* I/O now possible (4.2 BSD). */ + public static final int SIGIO = 29; + + /* Pollable event occurred (System V). */ + public static final int SIGPOLL = SIGIO; + + /* Power failure restart (System V). */ + public static final int SIGPWR = 30; + + /* Bad system call. */ + public static final int SIGSYS = 31; + + /** Used to dispatch signal notifications. */ + public static interface SignalHandler + { + /** + * Called when the specified signal is received. + * + * @return true if the signal handler should remain registered, + * false if it should be removed. + */ + public boolean signalReceived (int signal); + } + + /** + * Returns true if signal dispatching services are available, false if + * we could not load our native library. + */ + public boolean servicesAvailable () + { + return _haveLibrary; + } + + /** + * Registers a signal handler for the specified signal. + */ + public synchronized static void registerSignalHandler ( + int signal, SignalHandler handler) + { + ObserverList list = (ObserverList)_handlers.get(signal); + if (list == null) { + _handlers.put(signal, list = new ObserverList( + ObserverList.SAFE_IN_ORDER_NOTIFY)); + if (_haveLibrary) { + activateHandler(signal); + } + } + list.add(handler); + + // make sure the signal dispatcher thread is started + if (_haveLibrary && _sigdis == null) { + _sigdis = new Thread() { + public void run () { + Log.info("Dispatching signals..."); + dispatchSignals(); + } + }; + _sigdis.setDaemon(true); + _sigdis.start(); + } + } + + /** + * Removes the registration for the specified signal handler. + */ + public synchronized static void removeSignalHandler ( + int signal, SignalHandler handler) + { + ObserverList list = (ObserverList)_handlers.get(signal); + if (list == null || !list.contains(handler)) { + Log.warning("Requested to remove non-registered handler " + + "[signal=" + signal + ", handler=" + handler + "]."); + return; + } + list.remove(handler); + checkEmpty(signal); + } + + /** + * Called by native code when a signal is received. + */ + protected synchronized static void signalReceived (final int signal) + { + // this is hack, but we seem to get a call to our signal handler + // for each thread if the user presses ctrl-c in the terminal, so + // we "collapse" those into one call back + long now = System.currentTimeMillis(); + if (signal == SIGINT) { + if (_lastINTed == now) { + return; + } else { + _lastINTed = now; + } + } + ObserverList list = (ObserverList)_handlers.get(signal); + if (list != null) { + list.apply(new ObserverList.ObserverOp() { + public boolean apply (Object obs) { + return ((SignalHandler)obs).signalReceived(signal); + } + }); + } + checkEmpty(signal); + } + + /** + * Called when a signal handler is removed. + */ + protected static void checkEmpty (int signal) + { + ObserverList list = (ObserverList)_handlers.get(signal); + if (list != null && list.size() == 0) { + _handlers.remove(signal); + if (_haveLibrary) { + deactivateHandler(signal); + } + } + } + + /** + * Activates the signal handler for the specified signal. + */ + protected static native void activateHandler (int signal); + + /** + * Deactivates the signal handler for the specified signal. + */ + protected static native void deactivateHandler (int signal); + + /** + * Consigns a Java thread to the task of dispatching signal handler + * callbacks. + */ + protected static native void dispatchSignals (); + + /** A mapping from signal number to a list of handlers. */ + protected static HashIntMap _handlers = new HashIntMap(); + + /** Our signal dispatcher thread. */ + protected static Thread _sigdis; + + /** Set to true if we successfully load our native library. */ + protected static boolean _haveLibrary; + + /** Used to collapse bogus multiple delivery of SIGINT when the user + * pressed ctrl-c in the console. */ + protected static long _lastINTed = 0L; + + static { + try { + System.loadLibrary("signal"); + _haveLibrary = true; + } catch (Throwable t) { + Log.info("Could not load libsignal.so; signal handling disabled."); + } + } +} diff --git a/src/java/com/threerings/util/signal/com_threerings_util_signal_SignalManager.h b/src/java/com/threerings/util/signal/com_threerings_util_signal_SignalManager.h new file mode 100644 index 000000000..afb53a0aa --- /dev/null +++ b/src/java/com/threerings/util/signal/com_threerings_util_signal_SignalManager.h @@ -0,0 +1,104 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_threerings_util_signal_SignalManager */ + +#ifndef _Included_com_threerings_util_signal_SignalManager +#define _Included_com_threerings_util_signal_SignalManager +#ifdef __cplusplus +extern "C" { +#endif +#undef com_threerings_util_signal_SignalManager_SIGHUP +#define com_threerings_util_signal_SignalManager_SIGHUP 1L +#undef com_threerings_util_signal_SignalManager_SIGINT +#define com_threerings_util_signal_SignalManager_SIGINT 2L +#undef com_threerings_util_signal_SignalManager_SIGQUIT +#define com_threerings_util_signal_SignalManager_SIGQUIT 3L +#undef com_threerings_util_signal_SignalManager_SIGILL +#define com_threerings_util_signal_SignalManager_SIGILL 4L +#undef com_threerings_util_signal_SignalManager_SIGTRAP +#define com_threerings_util_signal_SignalManager_SIGTRAP 5L +#undef com_threerings_util_signal_SignalManager_SIGABRT +#define com_threerings_util_signal_SignalManager_SIGABRT 6L +#undef com_threerings_util_signal_SignalManager_SIGIOT +#define com_threerings_util_signal_SignalManager_SIGIOT 6L +#undef com_threerings_util_signal_SignalManager_SIGBUS +#define com_threerings_util_signal_SignalManager_SIGBUS 7L +#undef com_threerings_util_signal_SignalManager_SIGFPE +#define com_threerings_util_signal_SignalManager_SIGFPE 8L +#undef com_threerings_util_signal_SignalManager_SIGKILL +#define com_threerings_util_signal_SignalManager_SIGKILL 9L +#undef com_threerings_util_signal_SignalManager_SIGUSR1 +#define com_threerings_util_signal_SignalManager_SIGUSR1 10L +#undef com_threerings_util_signal_SignalManager_SIGSEGV +#define com_threerings_util_signal_SignalManager_SIGSEGV 11L +#undef com_threerings_util_signal_SignalManager_SIGUSR2 +#define com_threerings_util_signal_SignalManager_SIGUSR2 12L +#undef com_threerings_util_signal_SignalManager_SIGPIPE +#define com_threerings_util_signal_SignalManager_SIGPIPE 13L +#undef com_threerings_util_signal_SignalManager_SIGALRM +#define com_threerings_util_signal_SignalManager_SIGALRM 14L +#undef com_threerings_util_signal_SignalManager_SIGTERM +#define com_threerings_util_signal_SignalManager_SIGTERM 15L +#undef com_threerings_util_signal_SignalManager_SIGSTKFLT +#define com_threerings_util_signal_SignalManager_SIGSTKFLT 16L +#undef com_threerings_util_signal_SignalManager_SIGCHLD +#define com_threerings_util_signal_SignalManager_SIGCHLD 17L +#undef com_threerings_util_signal_SignalManager_SIGCONT +#define com_threerings_util_signal_SignalManager_SIGCONT 18L +#undef com_threerings_util_signal_SignalManager_SIGSTOP +#define com_threerings_util_signal_SignalManager_SIGSTOP 19L +#undef com_threerings_util_signal_SignalManager_SIGTSTP +#define com_threerings_util_signal_SignalManager_SIGTSTP 20L +#undef com_threerings_util_signal_SignalManager_SIGTTIN +#define com_threerings_util_signal_SignalManager_SIGTTIN 21L +#undef com_threerings_util_signal_SignalManager_SIGTTOU +#define com_threerings_util_signal_SignalManager_SIGTTOU 22L +#undef com_threerings_util_signal_SignalManager_SIGURG +#define com_threerings_util_signal_SignalManager_SIGURG 23L +#undef com_threerings_util_signal_SignalManager_SIGXCPU +#define com_threerings_util_signal_SignalManager_SIGXCPU 24L +#undef com_threerings_util_signal_SignalManager_SIGXFSZ +#define com_threerings_util_signal_SignalManager_SIGXFSZ 25L +#undef com_threerings_util_signal_SignalManager_SIGVTALRM +#define com_threerings_util_signal_SignalManager_SIGVTALRM 26L +#undef com_threerings_util_signal_SignalManager_SIGPROF +#define com_threerings_util_signal_SignalManager_SIGPROF 27L +#undef com_threerings_util_signal_SignalManager_SIGWINCH +#define com_threerings_util_signal_SignalManager_SIGWINCH 28L +#undef com_threerings_util_signal_SignalManager_SIGIO +#define com_threerings_util_signal_SignalManager_SIGIO 29L +#undef com_threerings_util_signal_SignalManager_SIGPOLL +#define com_threerings_util_signal_SignalManager_SIGPOLL 29L +#undef com_threerings_util_signal_SignalManager_SIGPWR +#define com_threerings_util_signal_SignalManager_SIGPWR 30L +#undef com_threerings_util_signal_SignalManager_SIGSYS +#define com_threerings_util_signal_SignalManager_SIGSYS 31L +/* Inaccessible static: _handlers */ +/* + * Class: com_threerings_util_signal_SignalManager + * Method: activateHandler + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_threerings_util_signal_SignalManager_activateHandler + (JNIEnv *, jclass, jint); + +/* + * Class: com_threerings_util_signal_SignalManager + * Method: deactivateHandler + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_threerings_util_signal_SignalManager_deactivateHandler + (JNIEnv *, jclass, jint); + +/* + * Class: com_threerings_util_signal_SignalManager + * Method: dispatchSignals + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_threerings_util_signal_SignalManager_dispatchSignals + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/java/com/threerings/util/signal/i686-Linux/Makefile b/src/java/com/threerings/util/signal/i686-Linux/Makefile new file mode 100644 index 000000000..8ee1cbd27 --- /dev/null +++ b/src/java/com/threerings/util/signal/i686-Linux/Makefile @@ -0,0 +1,43 @@ +# +# $Id: Makefile,v 1.1 2003/03/31 02:10:04 mdb Exp $ + +# +# Executable definitions + +CC=gcc +RM=rm +CP=cp +MKDIR=mkdir + +# +# Directory definitions + +ROOT=../../../../../../.. +LIBRARIES_PATH= +INSTALL_PATH=${ROOT}/dist/lib/i686-Linux + +# +# Parameter and file definitions + +INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux +LIBRARIES= +TARGET=libsignal.so +INSTALL_TARGET=${INSTALL_PATH}/${TARGET} + +# +# Target definitions + +all: ${INSTALL_TARGET} + +${INSTALL_TARGET}: com_threerings_util_signal_SignalManager.c + @echo Compiling SignalManager.c + @${CC} ${INCLUDES} -c com_threerings_util_signal_SignalManager.c \ + -o com_threerings_util_signal_SignalManager.o + @echo Creating libsignal.so + @${MKDIR} -p ${INSTALL_PATH} + @${CC} -o ${INSTALL_TARGET} com_threerings_util_signal_SignalManager.o \ + ${LIBRARIES} ${LIBRARIES_PATH} -shared + +clean: + -${RM} *.o + -${RM} ${INSTALL_TARGET} diff --git a/src/java/com/threerings/util/signal/i686-Linux/com_threerings_util_signal_SignalManager.c b/src/java/com/threerings/util/signal/i686-Linux/com_threerings_util_signal_SignalManager.c new file mode 100644 index 000000000..6045fd35e --- /dev/null +++ b/src/java/com/threerings/util/signal/i686-Linux/com_threerings_util_signal_SignalManager.c @@ -0,0 +1,96 @@ +/** + * $Id: com_threerings_util_signal_SignalManager.c,v 1.1 2003/03/31 02:10:04 mdb Exp $ + */ + +#include +#include +#include +#include + +#include +#include "com_threerings_util_signal_SignalManager.h" + +static int writefd; + +typedef void (*sighandler_t)(int); +static sighandler_t old_handlers[64]; +static sighandler_t handlers[64]; + +static void +signal_handler (int signo) +{ + write(writefd, &signo, sizeof(signo)); + signal(SIGINT, signal_handler); +} + +/** + * Class: com_threerings_util_signal_SignalManager + * Method: activateHandler + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_com_threerings_util_signal_SignalManager_activateHandler ( + JNIEnv* env, jclass clazz, jint signo) +{ + old_handlers[signo] = signal(signo, signal_handler); + if (old_handlers[signo] == SIG_ERR) { + fprintf(stderr, "Error setting signal handler (%d): %s\n", + signo, strerror(errno)); + old_handlers[signo] = 0; + } else { + handlers[signo] = signal_handler; + } +} + +/** + * Class: com_threerings_util_signal_SignalManager + * Method: deactivateHandler + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_com_threerings_util_signal_SignalManager_deactivateHandler ( + JNIEnv* env, jclass clazz, jint signo) +{ + if (old_handlers[signo] != 0) { + signal(signo, old_handlers[signo]); + old_handlers[signo] = 0; + handlers[signo] = 0; + } +} + +/** + * Class: com_threerings_util_signal_SignalManager + * Method: dispatchSignals + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_com_threerings_util_signal_SignalManager_dispatchSignals ( + JNIEnv* env, jclass clazz) +{ + int filedes[2], readfd; + jint signo; + jmethodID mid = (*env)->GetStaticMethodID( + env, clazz, "signalReceived", "(I)V"); + + if (pipe(filedes) < 0) { + fprintf(stderr, "Failed to create signal pipe: %s\n", strerror(errno)); + return; + } + readfd = filedes[0]; + writefd = filedes[1]; + + while (1) { + int got = read(readfd, &signo, sizeof(int)); + if (got < 0) { + fprintf(stderr, "Signal pipe read failed: %s\n", strerror(errno)); + } else if (got == 0) { + fprintf(stderr, "Signal pipe read returned zero bytes.\n"); + } else { + if (signo < 0 || signo >= 64 || handlers[signo] == 0) { + fprintf(stderr, "Received bogus signal (%d).\n", signo); + } else { + (*env)->CallStaticVoidMethod(env, clazz, mid, signo); + } + } + } +}