diff --git a/src/java/com/threerings/util/unsafe/Unsafe.java b/src/java/com/threerings/util/unsafe/Unsafe.java
new file mode 100644
index 000000000..b8e870881
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/Unsafe.java
@@ -0,0 +1,90 @@
+//
+// $Id: Unsafe.java,v 1.1 2003/05/08 21:25:20 mdb Exp $
+
+package com.threerings.util.unsafe;
+
+import com.threerings.util.Log;
+import com.samskivert.util.RunAnywhere;
+
+/**
+ * A native library for doing unsafe things. Don't use this library. If
+ * you must ignore that warning, then be sure you use it sparingly and
+ * only in very well considered cases.
+ */
+public class Unsafe
+{
+ /**
+ * Enables or disables garbage collection. Warning: you will
+ * be fucked if you leave it disabled for too long. Do not do this
+ * unless you are dang sure about what you're doing and are prepared
+ * to test your code on every platform this side of Nantucket.
+ *
+ *
Calls to this method do not nest. Regardless of how many times
+ * you disable GC, only one call is required to reenable it.
+ */
+ public static void setGCEnabled (boolean enabled)
+ {
+ // we don't support nesting, NOOP if the state doesn't change
+ if (_loaded && enabled != _gcEnabled) {
+ if (_gcEnabled = enabled) {
+ enableGC();
+ } else {
+ disableGC();
+ }
+ }
+ }
+
+ /**
+ * Causes the current thread to block for the specified number of
+ * milliseconds. This exists primarily to work around the fact that on
+ * Linux, {@link Thread#sleep} is only accurate to around 12ms which
+ * is wholly unacceptable.
+ */
+ public static void sleep (int millis)
+ {
+ if (_loaded && RunAnywhere.isLinux()) {
+ nativeSleep(millis);
+ } else {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException ie) {
+ Log.info("Thread.sleep(" + millis + ") interrupted.");
+ }
+ }
+ }
+
+ /**
+ * Reenable garbage collection after a call to {@link #disableGC}.
+ */
+ protected static native void enableGC ();
+
+ /**
+ * Disables garbage collection.
+ */
+ protected static native void disableGC ();
+
+ /**
+ * Sleeps the current thread for the specified number of milliseconds.
+ */
+ protected static native void nativeSleep (int millis);
+
+ /**
+ * Called to initialize our library.
+ */
+ protected static native boolean init ();
+
+ /** The current state of GC enablement. */
+ protected static boolean _gcEnabled = true;
+
+ /** Whether or not we were able to load and initialize our library. */
+ protected static boolean _loaded;
+
+ static {
+ try {
+ System.loadLibrary("unsafe");
+ _loaded = init();
+ } catch (UnsatisfiedLinkError e) {
+ Log.warning("Failed to load 'unsafe' library: " + e + ".");
+ }
+ }
+}
diff --git a/src/java/com/threerings/util/unsafe/com_threerings_util_unsafe_Unsafe.h b/src/java/com/threerings/util/unsafe/com_threerings_util_unsafe_Unsafe.h
new file mode 100644
index 000000000..f439fed8e
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/com_threerings_util_unsafe_Unsafe.h
@@ -0,0 +1,47 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_threerings_util_unsafe_Unsafe */
+
+#ifndef _Included_com_threerings_util_unsafe_Unsafe
+#define _Included_com_threerings_util_unsafe_Unsafe
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Inaccessible static: _gcEnabled */
+/* Inaccessible static: _loaded */
+/*
+ * Class: com_threerings_util_unsafe_Unsafe
+ * Method: enableGC
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_enableGC
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_threerings_util_unsafe_Unsafe
+ * Method: disableGC
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_disableGC
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_threerings_util_unsafe_Unsafe
+ * Method: nativeSleep
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_nativeSleep
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: com_threerings_util_unsafe_Unsafe
+ * Method: init
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_threerings_util_unsafe_Unsafe_init
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/java/com/threerings/util/unsafe/i686-Linux/Makefile b/src/java/com/threerings/util/unsafe/i686-Linux/Makefile
new file mode 100644
index 000000000..251b89837
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/i686-Linux/Makefile
@@ -0,0 +1,43 @@
+#
+# $Id: Makefile,v 1.1 2003/05/08 21:25:20 mdb Exp $
+
+#
+# Executable definitions
+
+CC=gcc
+RM=rm
+CP=cp
+MKDIR=mkdir
+
+#
+# Directory definitions
+
+ROOT=../../../../../../..
+LIBRARIES_PATH=-L/usr/X11R6/lib
+INSTALL_PATH=${ROOT}/dist/lib/i686-Linux
+
+#
+# Parameter and file definitions
+
+INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
+LIBRARIES=-lX11
+TARGET=libunsafe.so
+INSTALL_TARGET=${INSTALL_PATH}/${TARGET}
+
+#
+# Target definitions
+
+all: ${INSTALL_TARGET}
+
+${INSTALL_TARGET}: com_threerings_util_unsafe_Unsafe.c
+ @echo Compiling Unsafe.c
+ @${CC} ${INCLUDES} -c com_threerings_util_unsafe_Unsafe.c \
+ -o com_threerings_util_unsafe_Unsafe.o
+ @echo Creating ${TARGET}
+ @${MKDIR} -p ${INSTALL_PATH}
+ @${CC} -o ${INSTALL_TARGET} com_threerings_util_unsafe_Unsafe.o \
+ ${LIBRARIES} ${LIBRARIES_PATH} -shared
+
+clean:
+ -${RM} *.o
+ -${RM} ${INSTALL_TARGET}
diff --git a/src/java/com/threerings/util/unsafe/i686-Linux/com_threerings_util_unsafe_Unsafe.c b/src/java/com/threerings/util/unsafe/i686-Linux/com_threerings_util_unsafe_Unsafe.c
new file mode 100644
index 000000000..5598f23da
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/i686-Linux/com_threerings_util_unsafe_Unsafe.c
@@ -0,0 +1,77 @@
+/*
+ * $Id: com_threerings_util_unsafe_Unsafe.c,v 1.1 2003/05/08 21:25:20 mdb Exp $
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "com_threerings_util_unsafe_Unsafe.h"
+
+/* global jvmpi interface pointer */
+static JVMPI_Interface* jvmpi;
+
+/** A sleep method that uses select(). This seems to have about 10ms
+ * granularity where nanosleep() has about 20ms. Sigh. */
+static int select_sleep (int millisecs)
+{
+ fd_set dummy;
+ struct timeval toWait;
+ FD_ZERO(&dummy);
+ toWait.tv_sec = millisecs / 1000;
+ toWait.tv_usec = (millisecs % 1000) * 1000;
+ return select(0, &dummy, NULL, NULL, &toWait);
+}
+
+JNIEXPORT void JNICALL
+Java_com_threerings_util_unsafe_Unsafe_enableGC (JNIEnv* env, jclass clazz)
+{
+ fprintf(stderr, "Reenabling GC.\n");
+ jvmpi->EnableGC();
+}
+
+JNIEXPORT void JNICALL
+Java_com_threerings_util_unsafe_Unsafe_disableGC (JNIEnv* env, jclass clazz)
+{
+ fprintf(stderr, "Disabling GC.\n");
+ jvmpi->DisableGC();
+}
+
+JNIEXPORT void JNICALL
+Java_com_threerings_util_unsafe_Unsafe_nativeSleep (
+ JNIEnv* env, jclass clazz, jint millis)
+{
+/* struct timespec tmspec; */
+/* tmspec.tv_sec = millis/1000; */
+/* tmspec.tv_nsec = (millis%1000)*1000000; */
+/* if (nanosleep(&tmspec, NULL) < 0) { */
+/* fprintf(stderr, "nanosleep() failed: %s\n", strerror(errno)); */
+/* } */
+ if (select_sleep(millis) < 0) {
+ fprintf(stderr, "select_sleep() failed: %s\n", strerror(errno));
+ }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_threerings_util_unsafe_Unsafe_init (JNIEnv* env, jclass clazz)
+{
+ JavaVM* jvm;
+
+ if ((*env)->GetJavaVM(env, &jvm) > 0) {
+ fprintf(stderr, "Failed to get JavaVM from env.\n");
+ return JNI_FALSE;
+ }
+
+ /* get jvmpi interface pointer */
+ if (((*jvm)->GetEnv(jvm, (void**)&jvmpi, JVMPI_VERSION_1)) < 0) {
+ fprintf(stderr, "Failed to get JVMPI from JavaVM.\n");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}