Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions libraries/BridJ/src/main/java/org/bridj/BridJ.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,14 @@ public static boolean isCastingNativeObjectInCurrentThread() {
public static boolean isCastingNativeObjectReturnTypeInCurrentThread() {
return currentlyCastingNativeObject.get().peek() == CastingType.CastingNativeObjectReturnType;
}
private static WeakHashMap<Long, NativeObject> knownNativeObjects = new WeakHashMap<Long, NativeObject>();
private static KnownNativeObjectSupport knownNativeObjectSupport = new KnownNativeObjectSupport();

public static synchronized <O extends NativeObject> void setJavaObjectFromNativePeer(long peer, O object) {
if (object == null) {
knownNativeObjects.remove(peer);
} else {
knownNativeObjects.put(peer, object);
}
knownNativeObjectSupport.setJavaObjectFromNativePeer(peer, object);
}

public static synchronized Object getJavaObjectFromNativePeer(long peer) {
return knownNativeObjects.get(peer);
return knownNativeObjectSupport.getJavaObjectFromNativePeer(peer);
}

private static <O extends NativeObject> O createNativeObjectFromPointer(Pointer<? super O> pointer, Type type, CastingType castingType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.bridj;

import java.util.HashMap;
import java.util.Map;

import org.bridj.WeakReferenceMonitor.ReleaseListener;

public class KnownNativeObjectSupport {

private Map<Long, NativeObject> knownNativeObjects = new HashMap<Long, NativeObject>();

public <O extends NativeObject> void setJavaObjectFromNativePeer(final long peer, O object) {
if (object == null) {
knownNativeObjects.remove(peer);
} else {
knownNativeObjects.put(peer, object);
WeakReferenceMonitor.monitor(object, new ReleaseListener() {
public void released() {
knownNativeObjects.remove(peer);
}
});

}
}

public Object getJavaObjectFromNativePeer(long peer) {
return knownNativeObjects.get(peer);
}
}
157 changes: 157 additions & 0 deletions libraries/BridJ/src/main/java/org/bridj/WeakReferenceMonitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package org.bridj;
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed 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.
*/
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
* Track references to arbitrary objects using proxy and weak references. To
* monitor a handle, one should call {@link #monitor(Object, ReleaseListener)},
* with the given handle object usually being a holder that uses the target
* object underneath, and the release listener performing cleanup of the
* target object once the handle is not strongly referenced anymore.
*
* <p>When a given handle becomes weakly reachable, the specified listener
* will be called by a background thread. This thread will only be started
* lazily and will be stopped once no handles are registered for monitoring
* anymore, to be restarted if further handles are added.
*
* <p>Thanks to Tomasz Wysocki for the suggestion and the original
* implementation of this class!
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
*
* @since 1.2
* @see #monitor
*/
public class WeakReferenceMonitor {

// Queue receiving reachability events
private static final ReferenceQueue<?> handleQueue = new ReferenceQueue();

// All tracked entries (WeakReference => ReleaseListener)
private static final Map<Reference<?>,ReleaseListener> trackedEntries = Collections.synchronizedMap(new HashMap());

// Thread polling handleQueue, lazy initialized
private static Thread monitoringThread = null;


/**
* Start to monitor given handle object for becoming weakly reachable.
* When the handle isn't used anymore, the given listener will be called.
* @param handle the object that will be monitored
* @param listener the listener that will be called upon release of the handle
*/
public static void monitor(Object handle, ReleaseListener listener) {

// Make weak reference to this handle, so we can say when
// handle is not used any more by polling on handleQueue.
WeakReference<?> weakRef = new WeakReference(handle, handleQueue);

// Add monitored entry to internal map of all monitored entries.
addEntry(weakRef, listener);
}

/**
* Add entry to internal map of tracked entries.
* Internal monitoring thread is started if not already running.
* @param ref reference to tracked handle
* @param entry the associated entry
*/
private static void addEntry(Reference<?> ref, ReleaseListener entry) {
// Add entry, the key is given reference.
trackedEntries.put(ref, entry);

// Start monitoring thread lazily.
synchronized (WeakReferenceMonitor.class) {
if (!isMonitoringThreadRunning()) {
monitoringThread = new Thread(new MonitoringProcess(), WeakReferenceMonitor.class.getName());
monitoringThread.setDaemon(true);
monitoringThread.start();
}
}
}

/**
* Remove entry from internal map of tracked entries.
* @param reference the reference that should be removed
* @return entry object associated with given reference
*/
private static ReleaseListener removeEntry(Reference<?> reference) {
return (ReleaseListener) trackedEntries.remove(reference);
}

/**
* Check if monitoring thread is currently running.
*/
private static boolean isMonitoringThreadRunning() {
synchronized (WeakReferenceMonitor.class) {
return (monitoringThread != null);
}
}


/**
* Thread implementation that performs the actual monitoring.
*/
private static class MonitoringProcess implements Runnable {

public void run() {
try {
// Check if there are any tracked entries left.
while (!trackedEntries.isEmpty()) {
try {
Reference<?> reference = handleQueue.remove();
// Stop tracking this reference.
ReleaseListener entry = removeEntry(reference);
if (entry != null) {
// Invoke listener callback.
entry.released();
}
}
catch (InterruptedException ex) {
break;
}
}
}
finally {
synchronized (WeakReferenceMonitor.class) {
monitoringThread = null;
}
}
}
}


/**
* Listener that is notified when the handle is being released.
* To be implemented by users of this reference monitor.
*/
public static interface ReleaseListener {

/**
* This callback method is invoked once the associated handle has been released,
* i.e. once there are no monitored strong references to the handle anymore.
*/
void released();
}

}