Skip to content

Commit

Permalink
Support OpenSlide cache management API
Browse files Browse the repository at this point in the history
Use the same semantics as the OpenSlide API.

The OpenSlide class implements java.io.Closeable, which is documented to
be for "a source or destination of data that can be closed".
OpenSlideCache is technically a source or destination of data, but not at
the Java API level, and the only reason it needs to be closeable is to
release the underlying resource in the C API.  Its superinterface
java.lang.AutoCloseable is documented to be for "an object that may hold
resources [...] until it is closed"; implement that instead.

OpenSlide has a legacy dispose() method which is an alias for close().
Don't add a similar method to OpenSlideCache.

Closes: #36
Signed-off-by: Benjamin Gilbert <[email protected]>
  • Loading branch information
bgilbert committed Apr 14, 2024
1 parent dabbd6b commit 12ba0c3
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 3 deletions.
15 changes: 15 additions & 0 deletions org/openslide/OpenSlide.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* OpenSlide, a library for reading whole slide image files
*
* Copyright (c) 2007-2011 Carnegie Mellon University
* Copyright (c) 2024 Benjamin Gilbert
* All rights reserved.
*
* OpenSlide is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -420,6 +421,20 @@ BufferedImage getAssociatedImage(String name) throws IOException {
}
}

public void setCache(OpenSlideCache cache) {
Lock cl = cache.getLock();
Lock rl = lock.readLock();
cl.lock();
rl.lock();
try {
checkDisposed();
OpenSlideFFM.openslide_set_cache(osr, cache.getSegment());
} finally {
rl.unlock();
cl.unlock();
}
}

public static String getLibraryVersion() {
return LIBRARY_VERSION;
}
Expand Down
63 changes: 63 additions & 0 deletions org/openslide/OpenSlideCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* OpenSlide, a library for reading whole slide image files
*
* Copyright (c) 2007-2011 Carnegie Mellon University
* Copyright (c) 2024 Benjamin Gilbert
* All rights reserved.
*
* OpenSlide is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 2.1.
*
* OpenSlide is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with OpenSlide. If not, see
* <http://www.gnu.org/licenses/>.
*
*/

package org.openslide;

import java.lang.foreign.MemorySegment;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public final class OpenSlideCache implements AutoCloseable {
private final Lock lock = new ReentrantLock();

private MemorySegment cache;

public OpenSlideCache(long capacity) {
cache = OpenSlideFFM.openslide_cache_create(capacity);
}

Lock getLock() {
return lock;
}

// call, and use result, with lock held
MemorySegment getSegment() {
if (cache == null) {
throw new OpenSlideDisposedException("OpenSlideCache");
}
return cache;
}

// takes the lock
@Override
public void close() {
lock.lock();
try {
if (cache != null) {
OpenSlideFFM.openslide_cache_release(cache);
cache = null;
}
} finally {
lock.unlock();
}
}
}
8 changes: 6 additions & 2 deletions org/openslide/OpenSlideDisposedException.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@
package org.openslide;

public class OpenSlideDisposedException extends RuntimeException {
private static final String MSG = "OpenSlide object has been disposed";
private static final String MSG = " object has been closed";

public OpenSlideDisposedException() {
super(MSG);
this("OpenSlide");
}

public OpenSlideDisposedException(String what) {
super(what + MSG);
}
}
36 changes: 36 additions & 0 deletions org/openslide/OpenSlideFFM.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class OpenSlideFFM {
private static final AddressLayout C_POINTER = ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_BYTE));

private static final MemoryLayout SIZE_T = Linker.nativeLinker()
.canonicalLayouts().get("size_t");

private OpenSlideFFM() {
}

Expand Down Expand Up @@ -305,6 +308,39 @@ static void openslide_read_associated_image(MemorySegment osr, String name,
}
}

private static final MethodHandle cache_create = function(
C_POINTER, "openslide_cache_create", SIZE_T);

static MemorySegment openslide_cache_create(long capacity) {
try {
return (MemorySegment) cache_create.invokeExact(capacity);
} catch (Throwable ex) {
throw new AssertionError("Invalid call", ex);
}
}

private static final MethodHandle set_cache = function(
null, "openslide_set_cache", C_POINTER, C_POINTER);

static void openslide_set_cache(MemorySegment osr, MemorySegment cache) {
try {
set_cache.invokeExact(osr, cache);
} catch (Throwable ex) {
throw new AssertionError("Invalid call", ex);
}
}

private static final MethodHandle cache_release = function(
null, "openslide_cache_release", C_POINTER);

static void openslide_cache_release(MemorySegment cache) {
try {
cache_release.invokeExact(cache);
} catch (Throwable ex) {
throw new AssertionError("Invalid call", ex);
}
}

private static final MethodHandle get_version = function(
C_POINTER, "openslide_get_version");

Expand Down
5 changes: 4 additions & 1 deletion org/openslide/TestCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ public static void main(String args[]) throws IOException {

osr.dispose();

osr = new OpenSlide(f);
try (OpenSlideCache cache = new OpenSlideCache(64 << 20)) {
osr = new OpenSlide(f);
osr.setCache(cache);
}

w = osr.getLevel0Width();
h = osr.getLevel0Height();
Expand Down

0 comments on commit 12ba0c3

Please sign in to comment.