In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
Today, I would like to share with you the relevant knowledge about how to solve the callback problem in the JNA of advanced usage of java. The content is detailed and the logic is clear. I believe most people still know too much about this, so share this article for your reference. I hope you can get something after reading this article. Let's take a look.
Brief introduction
What is callback? To put it simply, callback is a callback notification. When we need to notify a specific task after a method is completed, or after an event is triggered, callback is needed.
The language most likely to see callback is javascript, and basically in javascript, callback is ubiquitous. In order to solve the callback hell problem caused by callback, promise is specially introduced into ES6 to solve this problem.
To facilitate interaction with the native method, Callback is also provided in JNA for callback. The essence of the callback in JNA is a pointer to the native function, through which you can call methods in the native function. Let's take a look.
Callback in JNA
Let's take a look at the definition of Callback in JNA:
Public interface Callback {interface UncaughtExceptionHandler {void uncaughtException (Callback c, Throwable e);} String METHOD_NAME = "callback"; List FORBIDDEN_NAMES = Collections.unmodifiableList ("hashCode", "equals", "toString");}
All Callback methods need to implement this Callback interface. The Callback interface is simple, with an interface and two properties defined.
Let's take a look at this interface,interface, which is called UncaughtExceptionHandler, and has a uncaughtException method in it. This interface is mainly used to handle exceptions that are not caught in JAVA's callback code.
Note that in the uncaughtException method, you cannot throw an exception, and any exception thrown from this method will be ignored.
The METHOD_NAME field specifies the method to be called by Callback.
If there is only one public method defined in the Callback class, then the default callback method is this method. If more than one public method is defined in the Callback class, the method METHOD_NAME = "callback" is selected as the callback.
The last attribute is FORBIDDEN_NAMES. Indicates that the name in this list cannot be used as a callback method.
At present, it seems that there are three method names that cannot be used: "hashCode", "equals", and "toString".
Callback also has a sibling called DLLCallback. Let's take a look at the definition of DLLCallback:
Public interface DLLCallback extends Callback {@ java.lang.annotation.Native int DLL_FPTRS = 16;}
DLLCallback is mainly used in Windows API visits.
For callback objects, we need to be responsible for releasing the callback objects ourselves. If the native code tries to access a recycled callback, it may cause the VM to crash.
The definition of the application callback of callback
Because callback in JNA actually maps pointers to functions in native. First take a look at the function pointer defined in struct:
Struct _ functions {int (* open) (const char*,int); int (* close) (int);}
In this structure, two function pointers are defined, with two parameters and one parameter, respectively.
The callback definition of the corresponding JNA is as follows:
Public class Functions extends Structure {public static interface OpenFunc extends Callback {int invoke (String name, int options);} public static interface CloseFunc extends Callback {int invoke (int fd);} public OpenFunc open; public CloseFunc close;}
We define two interfaces in Structure that inherit from Callback, and the corresponding invoke methods are defined in the corresponding interfaces.
Then take a look at the specific method of calling:
Functions funcs = new Functions (); lib.init (funcs); int fd = funcs.open.invoke ("myfile", 0); funcs.close.invoke (fd)
In addition, Callback can also be used as the return value of the function, as follows:
Typedef void (* sig_t) (int); sig_t signal (int signal, sig_t sigfunc)
For this separate function pointer, we need to customize a Library and define the corresponding Callback in it, as shown below:
Acquisition and Application of public interface CLibrary extends Library {public interface SignalFunction extends Callback {void invoke (int signal);} SignalFunction signal (int signal, SignalFunction func);} callback
If the callback is defined in the Structure, it can be instantiated automatically when the Structure is initialized, and then only need to access the corresponding properties from the Structure.
If the callback definition is in a normal Library, it looks like this:
Public static interface TestLibrary extends Library {interface VoidCallback extends Callback {void callback ();} interface ByteCallback extends Callback {byte callback (byte arg, byte arg2);} void callVoidCallback (VoidCallback c); byte callInt8Callback (ByteCallback c, byte arg, byte arg2);}
In the above example, we define two callback in a Library, one is the callback with no return value, and the other is the callback that returns byte.
JNA provides a simple utility class to help us get Callback. This utility class is CallbackReference, and the corresponding method is CallbackReference.getCallback, as shown below:
Pointer p = new Pointer ("MultiplyMappedCallback" .hashCode ()); Callback cbV1 = CallbackReference.getCallback (TestLibrary.VoidCallback.class, p); Callback cbB1 = CallbackReference.getCallback (TestLibrary.ByteCallback.class, p); log.info ("cbV1: {}", cbV1); log.info ("cbB1: {}", cbB1)
The output is as follows:
INFO com.flydean.CallbackUsage-cbV1:Proxy interface to native function@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$VoidCallback)
INFO com.flydean.CallbackUsage-cbB1:Proxy interface to native function@0xffffffffc46eeefc (com.flydean.CallbackUsage$TestLibrary$ByteCallback)
As you can see, these two Callback are actually proxies for the native method. If you look at the implementation logic of getCallback in detail:
Private static Callback getCallback (Class type, Pointer p, boolean direct) {if (p = = null) {return null;} if (! type.isInterface ()) throw new IllegalArgumentException ("Callback type must be an interface"); Map map = direct? DirectCallbackMap: callbackMap; synchronized (pointerCallbackMap) {Reference [] array = pointerCallbackMap.get (p); Callback cb = getTypeAssignableCallback (type, array); if (cb! = null) {return cb;} cb = createCallback (type, p); pointerCallbackMap.put (p, addCallbackToArray (cb,array)) / / No CallbackReference for this callback map.remove (cb); return cb;}}
You can see that its implementation logic is to first determine whether type is interface, and if it is not interface, it will report an error. Then determine whether it is direct mapping or not. In fact, the current implementation of JNA is interface mapping, so the next logic is to get the callback corresponding to the function pointer from pointerCallbackMap. Then look for a specific Callback based on the type passed in.
If it is not found, create a new callback and finally store the newly created one in the pointerCallbackMap.
Note that there is a key parameter called Pointer, and when you actually use it, you need to pass in a pointer to the real naitve function. In the above example, we have customized a Pointer for simplicity, and this Pointer does not make much practical sense.
If you really want to call the two call methods created in TestLibrary, callVoidCallback and callInt8Callback, in JNA, you first need to load the corresponding Library:
TestLibrary lib = Native.load ("testlib", TestLibrary.class)
Then the examples of creating TestLibrary.VoidCallback and TestLibrary.ByteCallback are as follows. First, take a look at VoidCallback:
Final boolean [] voidCalled = {false}; TestLibrary.VoidCallback cb1 = new TestLibrary.VoidCallback () {@ Override public void callback () {voidCalled [0] = true;}}; lib.callVoidCallback (cb1); assertTrue ("Callback not called", voidCalled [0])
Here we write back the value of voidCalled to true in callback to indicate that the callback method has been called.
Then take a look at the ByteCallback with the return value:
Final boolean [] int8Called = {false}; final byte [] cbArgs = {0,0}; TestLibrary.ByteCallback cb2 = new TestLibrary.ByteCallback () {@ Override public byte callback (byte arg, byte arg2) {int8Called [0] = true; cbArgs [0] = arg; cbArgs [1] = arg2; return (byte) (arg + arg2) }}; final byte MAGIC = 0x11bot byte value = lib.callInt8Callback (cb2, MAGIC, (byte) (MAGIC*2))
We can just return the byte value to be returned directly in the callback method.
Using callback in a multithreaded environment
By default, the callback method is executed in the current thread. If you want the callback method to be executed in a different thread, you can create a CallbackThreadInitializer, specifying the daemon,detach,name, and threadGroup properties:
Final String tname = "VoidCallbackThreaded"; ThreadGroup testGroup = new ThreadGroup ("Thread group for callVoidCallbackThreaded"); CallbackThreadInitializer init = new CallbackThreadInitializer (true, false, tname, testGroup)
Then create an instance of callback:
TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback () {@ Override public void callback () {Thread thread = Thread.currentThread (); daemon [0] = thread.isDaemon (); name [0] = thread.getName (); group [0] = thread.getThreadGroup (); t [0] = thread If (thread.isAlive ()) {alive [0] = true;} + called [0]; if (THREAD_DETACH_BUG & & called [0] = = 2) {Native.detach (true);}
Then call:
Native.setCallbackThreadInitializer (cb, init)
Associate callback with CallbackThreadInitializer.
Finally, call the callback method:
Lib.callVoidCallbackThreaded (cb, 2, 2000, "callVoidCallbackThreaded", 0); that's all of the article "how to solve the callback problem in JNA in the Advanced usage of java". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.