hypfvieh / dbus-java

Improved version of java DBus library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/)
https://hypfvieh.github.io/dbus-java/
MIT License
185 stars 73 forks source link

Interrupts are swallowed when a remote method call is done #150

Closed Xerxekyran closed 3 years ago

Xerxekyran commented 3 years ago

I ran into a problem when using dbus-java in a threaded environment were I need to interrupt the thread running dbus-java. I traced the problem and found the following:

In "org.freedesktop.dbus.messages.MethodCall" both "getReply" methods catch a possible ocurring InterruptedException and do not set the interrupted state (Thread.currentThread().interrupt()). This leads to my thread never being canceled in time correctly. I currently added a workaround where I listen for a thrown NoReply exception (which is the result of that method returning null) and then myself reset the interrupt state correctly.

It can easily be recreated by:

  1. Setting the interrupt state to the currently used thread
  2. Call a method to a remote object using dbus-java
  3. Reading the interrupt state, which is now not interrupted anymore

I would appreciate a fix in an upcoming version.

hypfvieh commented 3 years ago

Can you provide a sample for this?

Xerxekyran commented 3 years ago

Sure, is a code excerpt enough for you? In my example I am accessing the wpa_supplicant dbus object and call the "CreateInterface" method with my wifi interface (mlan0). For a simpler example I set the interrupted state even before calling the method (although this might also happen inbetween).

DBusConnection connection = DBusConnection.getConnection(DBusBusType.SYSTEM);
IWpa_supplicant1 wpaSupplicant = connection.getRemoteObject("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1", IWpa_supplicant1.class);

Thread.currentThread().interrupt();
System.out.println("Is interrupted before: "+ Thread.currentThread().isInterrupted());      
try {
  DBusInterface createInterface = wpaSupplicant.CreateInterface("mlan0");
} catch (Exception e) {
  System.out.println("An exception ocurred: "+ e.toString());
} 
System.out.println("Is interrupted after: "+ Thread.currentThread().isInterrupted());

The result of executing the example above is than:

Is interrupted before: true An exception ocurred: org.freedesktop.dbus.errors.NoReply: No reply within specified time Is interrupted after: false

I would expect the interrupted state to be true also after calling a method of an instance of the DBusInterface.

Is there more clarification / example code needed?

hypfvieh commented 3 years ago

Issue should be fixed now in master and java16 branch.

Xerxekyran commented 3 years ago

Very good, thank you. This should improve the usage in a threaded environment a lot. Do you already have plans when you want to release the next version of dbus-java?

hypfvieh commented 3 years ago

No real plans or roadmap. Java 17 has arrived and I think the java16 branch (which will be used for 17 as well) is in pretty good shape, I guess I will create a release soon. After that 'final' release for Java 1.8, which will have a 3.x version number, all following versions will be based on the java16 branch, require at least Java 11 (if you not plan to use native-unixsockets) and will get a new major version 4.x. This will also introduce breaking changes in code (not only required Java version). For more details on the upcoming 4.x version, see #145

Xerxekyran commented 3 years ago

Okay thank you for the information. The interrupt fix seems to work fine, I will close this issue now.