diff --git a/build.xml b/build.xml
index d9e6993b6..0272177d4 100644
--- a/build.xml
+++ b/build.xml
@@ -137,7 +137,7 @@
executable="make">
-
diff --git a/src/java/com/threerings/util/unsafe/FreeBSD/Makefile b/src/java/com/threerings/util/unsafe/FreeBSD/Makefile
new file mode 100644
index 000000000..39a78063f
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/FreeBSD/Makefile
@@ -0,0 +1,45 @@
+#
+# $Id: Makefile 3332 2005-02-03 01:30:33Z mdb $
+
+#
+# Executable definitions
+
+CC=gcc
+RM=rm
+CP=cp
+MKDIR=mkdir
+
+#
+# Directory definitions
+
+ROOT=../../../../../../..
+LIBRARIES_PATH=
+OSINCDIR!=uname -s | tr 'A-Z' 'a-z'
+INSTALL_PATH=${ROOT}/dist/lib/i386-FreeBSD
+
+#
+# Parameter and file definitions
+
+INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/${OSINCDIR}
+LIBRARIES=
+TARGET=libunsafe.so
+
+#
+# Target definitions
+
+all: ${TARGET}
+
+install: ${TARGET}
+ @${MKDIR} -p ${INSTALL_PATH}
+ cp ${TARGET} ${INSTALL_PATH}
+
+${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 libunsafe.so"
+ @${CC} -o ${TARGET} com_threerings_util_unsafe_Unsafe.o \
+ ${LIBRARIES} ${LIBRARIES_PATH} -shared
+
+clean:
+ -${RM} -f *.o ${TARGET}
diff --git a/src/java/com/threerings/util/unsafe/FreeBSD/com_threerings_util_unsafe_Unsafe.c b/src/java/com/threerings/util/unsafe/FreeBSD/com_threerings_util_unsafe_Unsafe.c
new file mode 100644
index 000000000..04ac0526c
--- /dev/null
+++ b/src/java/com/threerings/util/unsafe/FreeBSD/com_threerings_util_unsafe_Unsafe.c
@@ -0,0 +1,97 @@
+/*
+ * $Id: com_threerings_util_unsafe_Unsafe.c 3653 2005-07-21 19:10:08Z mdb $
+ */
+
+#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)
+{
+ jvmpi->EnableGC();
+}
+
+JNIEXPORT void JNICALL
+Java_com_threerings_util_unsafe_Unsafe_disableGC (JNIEnv* env, jclass clazz)
+{
+ 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_nativeSetuid (
+ JNIEnv* env, jclass clazz, jint uid)
+{
+ if (setuid((uid_t)uid) != 0) {
+ fprintf(stderr, "setuid(%d) failed: %s\n", uid, strerror(errno));
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_threerings_util_unsafe_Unsafe_nativeSetgid (
+ JNIEnv* env, jclass clazz, jint gid)
+{
+ if (setgid((gid_t)gid) != 0) {
+ fprintf(stderr, "setgid(%d) failed: %s\n", gid, strerror(errno));
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+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;
+}
diff --git a/src/java/com/threerings/util/unsafe/FreeBSD/libunsafe.so b/src/java/com/threerings/util/unsafe/FreeBSD/libunsafe.so
new file mode 100755
index 000000000..2a6a9e536
Binary files /dev/null and b/src/java/com/threerings/util/unsafe/FreeBSD/libunsafe.so differ