From ff691ca88c8b7b5d91f2ee78a917c363ebc98122 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 8 May 2003 21:25:20 +0000 Subject: [PATCH] There's no two ways about it. This shit is definitely not safe. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2556 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/util/unsafe/Unsafe.java | 90 +++++++++++++++++++ .../com_threerings_util_unsafe_Unsafe.h | 47 ++++++++++ .../util/unsafe/i686-Linux/Makefile | 43 +++++++++ .../com_threerings_util_unsafe_Unsafe.c | 77 ++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 src/java/com/threerings/util/unsafe/Unsafe.java create mode 100644 src/java/com/threerings/util/unsafe/com_threerings_util_unsafe_Unsafe.h create mode 100644 src/java/com/threerings/util/unsafe/i686-Linux/Makefile create mode 100644 src/java/com/threerings/util/unsafe/i686-Linux/com_threerings_util_unsafe_Unsafe.c 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; +}