You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2011/04/13 10:35:40 UTC

svn commit: r1091701 - in /commons/sandbox/runtime/trunk/src/main: java/org/apache/commons/runtime/NioByteBuffer.java native/Makefile.unx.in native/shared/nbb.c test/org/apache/commons/runtime/TestNioByteBuffer.java

Author: mturk
Date: Wed Apr 13 08:35:40 2011
New Revision: 1091701

URL: http://svn.apache.org/viewvc?rev=1091701&view=rev
Log:
Add NativeByteBuffer support

Added:
    commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java   (with props)
    commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c   (with props)
    commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java   (with props)
Modified:
    commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in

Added: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java?rev=1091701&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java (added)
+++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java Wed Apr 13 08:35:40 2011
@@ -0,0 +1,262 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.runtime;
+
+import java.nio.ByteBuffer;
+
+/** Manages NIO direct ByteBuffers
+ * <p>
+ * <b>Warning:</b><br/>Using this class improperly may crash the running JVM.
+ * Any method call after free method was called might write or read from
+ * the memory location that has been already allocated for
+ * something else.
+ * </p>
+ * <p>
+ * Using this class methods on ByteBuffers that were not created by
+ * DirectNioByteBuffer.allocate methods will almost certainly crash the
+ * running JVM.
+ * </p>
+ * @since Runtime 1.0
+ */
+public final class NioByteBuffer
+{
+
+    private NioByteBuffer()
+    {
+        // No class instance
+    }
+
+    private static native ByteBuffer    malloc0(long size)
+        throws OutOfMemoryError, IllegalArgumentException;
+
+    private static native ByteBuffer    calloc0(long size)
+        throws OutOfMemoryError, IllegalArgumentException;
+
+    private static native ByteBuffer    attach0(long ptr, long len)
+        throws OutOfMemoryError;
+
+    private static native long addr0(ByteBuffer buf);
+
+    private static native void copy0(ByteBuffer src, long srcPos, ByteBuffer dst,
+                                     long dstPos, int count)
+        throws NullPointerException, IllegalArgumentException,
+        IndexOutOfBoundsException;
+
+    /**
+     * Allocate a new {@code ByteBuffer} from {@link Pointer} memory area.
+     * <p>
+     * <b>Warning:</b><br/>
+     * Allocated array elements share the same memory segment
+     * so the {@code free()} must <b>not</b> be called on the retured
+     * {@code ByteBuffer}, neither it can be used after the {@code ptr}
+     * has been destroyed.
+     * </p>
+     * @param ptr Memory area to use.
+     * @param off Start offset of the {@code ptr} memory area.
+     * @param len The length of the {@code ptr} memory areat to use.
+     * @return The {@code ByteBuffer} backed by the {@code ptr} memory area.
+     *
+     * @throws NullPointerException if {@code ptr} is null.
+     * @throws IllegalArgumentException if {@code off} or {@code len}
+     *         is invalid.
+     * @throws IndexOutOfBoundsException if copying would cause access of
+     *         data outside array bounds.
+     */
+    public static ByteBuffer allocate(Pointer ptr, long off, long len)
+        throws NullPointerException, IllegalArgumentException,
+        IndexOutOfBoundsException, OutOfMemoryError
+    {
+        if (ptr == null || ptr.POINTER == 0L)
+            throw new NullPointerException();
+        if (off < 0L || len < 1L)
+            throw new IllegalArgumentException();
+        if (off + len >= ptr.PLENGTH)
+            throw new IndexOutOfBoundsException();
+
+        return attach0(ptr.POINTER + off, len);
+    }
+
+    /**
+     * Allocate a new {@code ByteBuffer} from {@link Pointer} memory area.
+     * <p>
+     * <b>Warning:</b><br/>
+     * Allocated array elements share the same memory segment
+     * so the {@code free()} must <b>not</b> be called on the retured
+     * {@code ByteBuffer}, neither it can be used after the {@code ptr}
+     * has been destroyed.
+     * </p>
+     * @param ptr Memory area to use.
+     * @return The {@code ByteBuffer} backed by the {@code ptr} memory area.
+     *
+     * @throws NullPointerException if {@code ptr} is null.
+     */
+    public static ByteBuffer allocate(Pointer ptr)
+        throws NullPointerException, OutOfMemoryError
+    {
+        if (ptr == null || ptr.POINTER == 0L)
+            throw new NullPointerException();
+        return attach0(ptr.POINTER, ptr.PLENGTH);
+    }
+
+    /**
+     * Returns the allocated memory size of the ByteBuffer.
+     * @param buf Previously allocated ByteBuffer.
+     */
+    public static native long size(ByteBuffer buf)
+        throws NullPointerException;
+
+    /**
+     * Set ByteBuffer to specified character.
+     * @param buf The ByteBuffer to use
+     * @param c The character to set
+     * @param count Number of characters
+     *
+     * @throws NullPointerException if {@code buf} is null.
+     * @throws IllegalArgumentException if {@code count} is less then {@code 1}.
+     * @throws IndexOutOfBoundsException if copying would cause access of
+     *         data outside ByteBuffer bounds.
+     */
+    public static native void set(ByteBuffer buf, int c, int count)
+        throws NullPointerException, IllegalArgumentException,
+        IndexOutOfBoundsException;
+
+    /**
+     * Copy an ByteBuffer content from specified source ByteBuffer.
+     * @param src The source ByteBuffer.
+     * @param dst The destination ByteBuffer.
+     * @param length The number of bytes to be copied.
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code length} invalid
+     * @throws IndexOutOfBoundsException if copying would cause access of
+     *         data outside ByteBuffer bounds.
+     */
+    public static void copy(ByteBuffer src, ByteBuffer dst, int length)
+        throws NullPointerException, IllegalArgumentException,
+        IndexOutOfBoundsException
+    {
+        if (src == null || dst == null)
+            throw new NullPointerException();
+        copy0(src, 0, dst, 0, length);
+    }
+
+    /**
+     * Copy an ByteBuffer content from specified source ByteBuffer.
+     * @param src The source ByteBuffer.
+     * @param srcPos Starting position in the source ByteBuffer.
+     * @param dst The destination ByteBuffer.
+     * @param dstPos Starting position in the source ByteBuffer.
+     * @param length The number of bytes to be copied.
+     *
+     * @throws NullPointerException if {@code src} or {@code dst} is null
+     * @throws IllegalArgumentException if {@code length} invalid
+     * @throws IndexOutOfBoundsException if copying would cause access of
+     *         data outside ByteBuffer bounds.
+     */
+    public static void copy(ByteBuffer src, long srcPos, ByteBuffer dst,
+                            long dstPos, int length)
+        throws NullPointerException, IllegalArgumentException,
+        IndexOutOfBoundsException
+    {
+        if (src == null || dst == null)
+            throw new NullPointerException();
+        copy0(src, srcPos, dst, dstPos, length);
+    }
+
+    // Unsafe methods
+    // TODO: See if those methods should be present at the first
+    //       place because they can very easily crash the VM.
+
+    /**
+     * Allocate a new ByteBuffer from memory.
+     * @param size The amount of memory to allocate
+     * @return The ByteBuffer with allocated memory
+     *
+     * @throws OutOfMemoryError if memory cannot be allocated from the system.
+     * @throws IllegalArgumentException if {@code size} is invalid.
+     */
+    public static ByteBuffer allocate(long size)
+        throws OutOfMemoryError, IllegalArgumentException
+    {
+        return malloc0(size);
+    }
+
+    /**
+     * Allocate a new ByteBuffer from memory and set all of the memory
+     * bytes to zero.
+     * @param size Length in bytes of each element.
+     * @return The ByteBuffer with allocated memory
+     *
+     * @throws OutOfMemoryError if memory cannot be allocated from the system.
+     * @throws IllegalArgumentException if {@code size} is invalid.
+     */
+    public static ByteBuffer allocateAndClear(long size)
+        throws OutOfMemoryError, IllegalArgumentException
+    {
+        return calloc0(size);
+    }
+
+    /**
+     * Allocate a new ByteBuffer from already allocated ByteBuffer.
+     * @param buf The ByteBuffer who's memory to use
+     * @param offset Offset from the memory to use
+     * @param size The amount of memory to use
+     * @return The ByteBuffer with attached memory
+     *
+     * @throws NullPointerException if {@code buf} is null
+     * @throws IllegalArgumentException if {@code offset} or
+     *         {@code size} are invalid.
+     */
+    public static ByteBuffer allocate(ByteBuffer buf, long offset, long size)
+        throws NullPointerException, IllegalArgumentException
+    {
+        if (buf == null)
+            throw new NullPointerException();
+        long mem = addr0(buf);
+        if (mem == 0L)
+            throw new NullPointerException();
+        if (offset < 0L || size < 1L)
+            throw new IllegalArgumentException();
+        long len = size(buf);
+        if (offset + size > len)
+            throw new IndexOutOfBoundsException();
+        return attach0(mem + offset, size);
+    }
+
+    /**
+     * Deallocates or frees a memory block used by ByteBuffer.
+     * <p>
+     * <b>Warning:</b><br/>
+     * Invoke this method only on ByteBuffers
+     * that were created by {@code NioByteBuffer.allocate} methods
+     * and only if the Buffer was not allocated from the {@code Pointer}
+     * object.
+     * </p>
+     * <p>
+     * <b>Warning:</b><br/>
+     * This method must be called when the buffer is no longer needed.
+     * Failing to do so will leak system memory resources, causing memory
+     * growth because the underlying memory has to be explicitly released.
+     * </p>
+     * @param buf Previously allocated ByteBuffer to be deallocated.
+     *
+     * @throws NullPointerException if {@code buf} is null
+     */
+    public static native void free(ByteBuffer buf)
+        throws NullPointerException;
+
+}

Propchange: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/NioByteBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in?rev=1091701&r1=1091700&r2=1091701&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in (original)
+++ commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in Wed Apr 13 08:35:40 2011
@@ -97,6 +97,7 @@ LIBSOURCES=\
 	$(TOPDIR)/shared/iofd.c \
 	$(TOPDIR)/shared/memory.c \
 	$(TOPDIR)/shared/native.c \
+	$(TOPDIR)/shared/nbb.c \
 	$(TOPDIR)/shared/pointer.c \
 	$(TOPDIR)/shared/object.c \
 	$(TOPDIR)/shared/observer.c \

Added: commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c?rev=1091701&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c (added)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c Wed Apr 13 08:35:40 2011
@@ -0,0 +1,174 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ */
+
+#include "acr/memory.h"
+#include "acr/clazz.h"
+
+/**
+ * NioByteBuffer utilities
+ */
+ACR_JNI_EXPORT(jobject, NioByteBuffer, malloc0)(JNI_STDARGS,
+                                                jlong size)
+{
+    void *mem;
+    jlong sz = ACR_ALIGN_DEFAULT(size);
+
+    if (size < 1L || size > SIZE_T_MAX) {
+        ACR_THROW(ACR_EX_EINVAL, 0);
+        return 0;
+    }
+    mem = ACR_MALLOC(char, sz);
+    if (mem != 0) {
+        jobject rv = (*env)->NewDirectByteBuffer(env, mem, sz);
+        if (rv == 0)
+            free(mem);
+        return rv;
+    }
+    return 0;
+}
+
+ACR_JNI_EXPORT(jobject, NioByteBuffer, calloc0)(JNI_STDARGS,
+                                                jlong size)
+{
+    jlong sz = ACR_ALIGN_DEFAULT(size);
+    void *mem;
+
+    if (size < 1L || size > SIZE_T_MAX) {
+        ACR_THROW(ACR_EX_EINVAL, 0);
+        return 0;
+    }
+    mem = ACR_CALLOC(char, sz);
+    if (mem != 0) {
+        jobject rv = (*env)->NewDirectByteBuffer(env, mem, sz);
+        if (rv == 0)
+            free(mem);
+        return rv;
+    }
+    return 0;
+}
+
+ACR_JNI_EXPORT(jobject, NioByteBuffer, attach0)(JNI_STDARGS,
+                                                jlong src, jlong len)
+{
+    return (*env)->NewDirectByteBuffer(env, J2P(src, char *), len);
+}
+
+ACR_JNI_EXPORT(void, NioByteBuffer, free)(JNI_STDARGS, jobject bb)
+{
+    void *mem;
+
+    if (bb != 0 && (mem = (*env)->GetDirectBufferAddress(env, bb)) != 0) {
+        /* This can cause core dump if address was
+         * allocated using different method.
+         * Make sure you call Native.enableExceptionHandler() to
+         * throw an exception instead.
+         */
+        free(mem);
+    }
+    else {
+        ACR_THROW(ACR_EX_ENULL, 0);
+    }
+}
+
+ACR_JNI_EXPORT(jlong, NioByteBuffer, addr0)(JNI_STDARGS,
+                                            jobject bb)
+{
+    return P2J((*env)->GetDirectBufferAddress(env, bb));
+}
+
+ACR_JNI_EXPORT(jlong, NioByteBuffer, size)(JNI_STDARGS,
+                                           jobject bb)
+{
+    if (bb == 0) {
+        ACR_THROW(ACR_EX_ENULL, 0);
+        return -1;
+    }
+    return (*env)->GetDirectBufferCapacity(env, bb);
+}
+
+ACR_JNI_EXPORT(void, NioByteBuffer, set)(JNI_STDARGS,
+                                         jobject bb,
+                                         jint c,
+                                         jint count)
+{
+    void *m;
+    jlong sz;
+
+    if (bb == 0) {
+        ACR_THROW(ACR_EX_ENULL, 0);
+        return;
+    }
+    sz = (*env)->GetDirectBufferCapacity(env, bb);
+    if (count < 1) {
+        ACR_THROW(ACR_EX_EINVAL, 0);
+        return;
+    }
+    if ((jlong)count > sz) {
+        ACR_THROW(ACR_EX_EINVAL, ACR_ERANGE);
+        return;
+    }
+    if ((m = (*env)->GetDirectBufferAddress(env, bb))) {
+        memset(m, c, count);
+    }
+    else {
+        ACR_THROW(ACR_EX_ENULL, 0);
+    }
+}
+
+ACR_JNI_EXPORT(void, NioByteBuffer, copy0)(JNI_STDARGS,
+                                           jobject srcb,
+                                           jlong srco,
+                                           jobject dstb,
+                                           jlong dsto,
+                                           jint count)
+{
+    char *d;
+    char *s;
+    jlong ss;
+    jlong ds;
+
+
+    ss = (*env)->GetDirectBufferCapacity(env, srcb);
+    ds = (*env)->GetDirectBufferCapacity(env, dstb);
+    if (ss < 1 || ds < 1) {
+        ACR_THROW(ACR_EX_EINVAL, ACR_EINVALSIZ);
+        return;
+    }
+    if ((count + srco) > ss) {
+        ACR_THROW(ACR_EX_EINDEX, ACR_ERANGE);
+        return;
+    }
+    if ((count + dsto) > ds) {
+        ACR_THROW(ACR_EX_EINDEX, ACR_ERANGE);
+        return;
+    }
+    s = (char *)(*env)->GetDirectBufferAddress(env, srcb);
+    if (s == 0 ) {
+        ACR_THROW(ACR_EX_ENULL, 0);
+        return;
+    }
+    d = (char *)(*env)->GetDirectBufferAddress(env, dstb);
+    if (d == 0 ) {
+        ACR_THROW(ACR_EX_ENULL, 0);
+        return;
+    }
+    memcpy(d + (intptr_t)dsto, s + (intptr_t)srco, count);
+}

Propchange: commons/sandbox/runtime/trunk/src/main/native/shared/nbb.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java?rev=1091701&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java (added)
+++ commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java Wed Apr 13 08:35:40 2011
@@ -0,0 +1,117 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.runtime;
+
+import java.io.IOException;
+import java.io.File;
+import org.testng.annotations.*;
+import org.testng.Assert;
+import java.nio.ByteBuffer;
+
+@Test(groups = { "utils" })
+public class TestNioByteBuffer
+{
+
+    public void malloc()
+        throws Exception
+    {
+        ByteBuffer bb = NioByteBuffer.allocate(1000);
+        Assert.assertTrue(bb.isDirect());
+        Assert.assertEquals(1000, bb.capacity());
+        NioByteBuffer.free(bb);
+    }
+
+    public void calloc()
+        throws Exception
+    {
+        ByteBuffer bb = NioByteBuffer.allocateAndClear(1000);
+        Assert.assertTrue(bb.isDirect());
+        Assert.assertEquals(1000, bb.capacity());
+        NioByteBuffer.free(bb);
+    }
+
+
+    public void pointer()
+        throws Exception
+    {
+        // ptr, bb1 and bb2 share the same memory
+        Pointer ptr = Memory.malloc(1000);
+        ByteBuffer bb = NioByteBuffer.allocate(ptr);
+        Assert.assertTrue(bb.isDirect());
+        Assert.assertEquals(1000, bb.capacity());
+        /*
+         * Call to the free crashes the JVM !
+         * Also call to the any operation on any
+         * Byte buffer will probably crash the JVM after the
+         * memory is free'd
+         * bb.putInt(0xcafebabe);      might write to something else
+         * NioByteBuffer.free(bb);  will free already free'd memory
+         *                             causing core.
+         */
+    }
+
+    public void doNotDoThis()
+        throws Exception
+    {
+        // ptr, bb1 and bb2 share the same memory
+        Pointer ptr = Memory.malloc(1000);
+        ByteBuffer bb = NioByteBuffer.allocate(ptr);
+        Assert.assertTrue(bb.isDirect());
+        Assert.assertEquals(1000, bb.capacity());
+        try {
+            boolean test_me = Native.HAS_MAINTAINER_MODE;
+            ptr.free();
+            // This is double free. Don't do this!
+            // Exception handler won't help here.
+            test_me = false;
+            if (test_me) {
+                NioByteBuffer.free(bb);
+            }
+        } catch (Throwable t) {
+            // Empty
+        }
+    }
+
+    public void memset()
+        throws Exception
+    {
+        ByteBuffer bb = NioByteBuffer.allocate(1000);
+        Assert.assertTrue(bb.isDirect());
+        bb.putInt(0xcafebabe);
+        bb.rewind();
+        Assert.assertEquals(0xcafebabe, bb.getInt());
+        NioByteBuffer.set(bb, 0x55, 1000);
+        Assert.assertEquals(0x55555555, bb.getInt());
+        NioByteBuffer.free(bb);
+    }
+
+    public void copy()
+        throws Exception
+    {
+        ByteBuffer sb = NioByteBuffer.allocate(1000);
+        ByteBuffer db = NioByteBuffer.allocateAndClear(1000);
+//        Assert.assertTrue(sb.isDirect());
+//        Assert.assertTrue(db.isDirect());
+        sb.putInt(0xcafebabe);
+        NioByteBuffer.copy(sb, 0, db, 4, 996);
+        Assert.assertEquals(0, db.getInt());
+        Assert.assertEquals(0xcafebabe, db.getInt());
+        NioByteBuffer.free(sb);
+        NioByteBuffer.free(db);
+    }
+
+}

Propchange: commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestNioByteBuffer.java
------------------------------------------------------------------------------
    svn:eol-style = native