com.kenai.jffi.ClosureManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnr-unixsocket-nodep Show documentation
Show all versions of jnr-unixsocket-nodep Show documentation
com.github.jnr:jnr-unixsocket with orh.objectweb.asm shaded
/*
* Copyright (C) 2009 Wayne Meissner
*
* This file is part of jffi.
*
* 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.
*
*
* Alternatively, 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, either version 3 of the License, or
* (at your option) any later version.
*
* This code 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 this work. If not, see .
*/
package com.kenai.jffi;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Allocates and manages the lifecycle of native closures (aka callbacks)
*/
public final class ClosureManager {
/**
* ClosurePool instances are linked via a SoftReference in the lookup map, so
* when all closure instances that that were allocated from the ClosurePool have been
* reclaimed, and there is memory pressure, the native closure pool can be freed.
* This will allow the CallContext instance to also be collected if it is not
* strongly referenced elsewhere, and ejected from the {@link CallContextCache}
*/
private final Map> poolMap = new WeakHashMap>();
/** Holder class to do lazy allocation of the ClosureManager instance */
private static final class SingletonHolder {
static final ClosureManager INSTANCE = new ClosureManager();
}
/**
* Gets the global instance of the ClosureManager
*
* @return An instance of a ClosureManager
*/
public static ClosureManager getInstance() {
return SingletonHolder.INSTANCE;
}
/** Constructs a ClosureManager */
private ClosureManager() { }
/**
* Wraps a java object that implements the {@link Closure} interface in a
* native closure.
*
* @param closure The java object to be called when the native closure is invoked.
* @param returnType The return type of the closure.
* @param parameterTypes The parameter types of the closure.
* @param convention The calling convention of the closure.
* @return A new {@link Closure.Handle} instance.
*/
public final Closure.Handle newClosure(Closure closure, Type returnType, Type[] parameterTypes, CallingConvention convention) {
return newClosure(closure, CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention));
}
/**
* Wraps a java object that implements the {@link Closure} interface in a
* native closure.
*
* @param closure The java object to be called when the native closure is invoked.
* @param callContext The call context (return type, param types, convention) of the Closure
* @return A new {@link Closure.Handle} instance.
*/
public final Closure.Handle newClosure(Closure closure, CallContext callContext) {
ClosurePool pool = getClosurePool(callContext);
return pool.newClosureHandle(closure);
}
public final synchronized ClosurePool getClosurePool(CallContext callContext) {
Reference ref = poolMap.get(callContext);
ClosurePool pool;
if (ref != null && (pool = ref.get()) != null) {
return pool;
}
poolMap.put(callContext, new SoftReference(pool = new ClosurePool(callContext)));
return pool;
}
public ClosureMagazine newClosureMagazine(CallContext callContext, Method method) {
Foreign foreign = Foreign.getInstance();
Class[] methodParameterTypes = method.getParameterTypes();
boolean callWithPrimitiveArgs = methodParameterTypes.length < 1 ||
!Closure.Buffer.class.isAssignableFrom(method.getParameterTypes()[0]);
long magazine = foreign.newClosureMagazine(callContext.getAddress(), method, callWithPrimitiveArgs);
if (magazine == 0L) {
throw new RuntimeException("could not allocate new closure magazine");
}
return new ClosureMagazine(foreign, callContext, magazine);
}
}