Skip to content
Merged
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ The library will remain open source and MIT licensed and can still be used, fork
- with this change, you can also create Structs and use them as return value having something like `GetCurrentStateStruct` instead of using the long Tuple-name
- Further details on this in [#285](https://github.com/hypfvieh/dbus-java/issues/285)
- Added new commandline option `--disable-tuples` to `InterfaceCodeGenerator` to create `Struct` classes instead of `Tuple`s for multi value return (**Caution** the generated code will only work with dbus-java 6.0.0+)
- Added support for Virtual-Threads in `ReceivingService`
- This can be enabled using the `DBusConnectionBuilder`, example: `DBusConnection sessionConnection = DBusConnectionBuilder.forSystemBus().receivingThreadConfig().withAllVirtualThreads(true).connectionConfig().build()`
- Virtual-Threads can be enabled/disabled for each of the different executor services used in `ReceivingService`: `SIGNAL`, `ERROR`, `METHODCALL`, `METHODRETURN`
- default remains native threads on all executors

##### Changes in 5.2.0 (2025-12-21):
- removed properties from dbus-java.version which causes issues with reproducable builds ([PR#279](https://github.com/hypfvieh/dbus-java/issues/279))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,7 @@ public static Object[] deSerializeParameters(Object[] _parameters, Type[] _types
return new Object[] {o};
} else if (!_methodCall && Struct.class.isAssignableFrom(clz)) {
LOGGER.trace("(4) Deserializing Struct return");
Object[] val = deSerializeParameters(_parameters, types, _conn, true);
return val;
return deSerializeParameters(_parameters, types, _conn, true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ public Object invoke(Object _proxy, Method _method, Object[] _args) throws Throw
return _args[0] != null && remote.equals(((RemoteInvocationHandler) Proxy.getInvocationHandler(_args[0])).remote);
}
} catch (IllegalArgumentException _exIa) {
return Boolean.FALSE;
LOGGER.trace("Error calling equals method", _exIa);
}
return Boolean.FALSE;
case "finalize":
return null;
case "getClass":
Expand All @@ -85,10 +86,8 @@ public Object invoke(Object _proxy, Method _method, Object[] _args) throws Throw
} else if (_args.length == 2 && _args[0] instanceof Long l && _args[1] instanceof Integer i) {
remote.wait(l, i);
}
if (_args.length <= 2) {
return null;
}
}
return null;
case "toString":
return remote.toString();
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;

/**
* Service providing threads for every type of message expected to be received by DBus.
Expand All @@ -42,20 +40,34 @@ public class ReceivingService {
ReceivingService(String _namePrefix, ReceivingServiceConfig _rsCfg) {
String prefix = _namePrefix == null ? "" : _namePrefix;
ReceivingServiceConfig rsCfg = Optional.ofNullable(_rsCfg).orElse(ReceivingServiceConfigBuilder.getDefaultConfig());
executors.put(ExecutorNames.SIGNAL,
Executors.newFixedThreadPool(rsCfg.getSignalThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-Signal-Receiver-", true, rsCfg.getSignalThreadPriority())));
executors.put(ExecutorNames.ERROR,
Executors.newFixedThreadPool(rsCfg.getErrorThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-Error-Receiver-", true, rsCfg.getErrorThreadPriority())));

// we need multiple threads here so recursive method calls are possible
executors.put(ExecutorNames.METHODCALL,
Executors.newFixedThreadPool(rsCfg.getMethodCallThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-MethodCall-Receiver-", true, rsCfg.getMethodCallThreadPriority())));
executors.put(ExecutorNames.METHODRETURN,
Executors.newFixedThreadPool(rsCfg.getMethodReturnThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-MethodReturn-Receiver-", true, rsCfg.getMethodReturnThreadPriority())));
Arrays.stream(ExecutorNames.values())
.forEach(t -> {
executors.put(t,
Executors.newFixedThreadPool(rsCfg.getPoolSize(t), createFactory(prefix + t.getThreadName() + "-", _rsCfg.isVirtual(t), _rsCfg.getPriority(t))));
});

retryHandler = rsCfg.getRetryHandler();
}

/**
* Create thread factory for creating native or virtual threads.
*
* @param _name name for created threads
* @param _virtualThreads true to create virtual threads
* @param _priority thread priority (only used for non-virtual threads)
* @return {@link ThreadFactory}
*
* @since 6.0.0 - 2026-01-10
*/
private ThreadFactory createFactory(String _name, boolean _virtualThreads, int _priority) {
if (_virtualThreads) {
return Thread.ofVirtual().name(_name, 1L).factory();
} else {
return new NameableThreadFactory(_name, true, _priority);
}
}

/**
* Execute a runnable which handles a signal.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,98 +1,146 @@
package org.freedesktop.dbus.connections.config;

import org.freedesktop.dbus.connections.shared.ExecutorNames;
import org.freedesktop.dbus.connections.shared.IThreadPoolRetryHandler;

import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;

/**
* Bean which holds configuration for {@link org.freedesktop.dbus.connections.base.ReceivingService}.
*
* @author hypfvieh
* @since 4.2.0 - 2022-07-14
*/
public final class ReceivingServiceConfig {
private int signalThreadPoolSize = 1;
private int errorThreadPoolSize = 1;
private int methodCallThreadPoolSize = 4;
private int methodReturnThreadPoolSize = 1;
private int signalThreadPriority = Thread.NORM_PRIORITY;
private int methodCallThreadPriority = Thread.NORM_PRIORITY;
private int errorThreadPriority = Thread.NORM_PRIORITY;
private int methodReturnThreadPriority = Thread.NORM_PRIORITY;

private final Map<ExecutorNames, ThreadCfg> threadConfigs = new EnumMap<>(ExecutorNames.class);

private IThreadPoolRetryHandler retryHandler;

ReceivingServiceConfig() {
threadConfigs.put(ExecutorNames.SIGNAL, new ThreadCfg(1, Thread.NORM_PRIORITY, false));
threadConfigs.put(ExecutorNames.ERROR, new ThreadCfg(1, Thread.NORM_PRIORITY, false));
threadConfigs.put(ExecutorNames.METHODCALL, new ThreadCfg(4, Thread.NORM_PRIORITY, false));
threadConfigs.put(ExecutorNames.METHODRETURN, new ThreadCfg(1, Thread.NORM_PRIORITY, false));
}

public int getSignalThreadPoolSize() {
return signalThreadPoolSize;
return threadConfigs.get(ExecutorNames.SIGNAL).poolSize();
}

public int getErrorThreadPoolSize() {
return errorThreadPoolSize;
return threadConfigs.get(ExecutorNames.ERROR).poolSize();
}

public int getMethodCallThreadPoolSize() {
return methodCallThreadPoolSize;
return threadConfigs.get(ExecutorNames.METHODCALL).poolSize();
}

public int getMethodReturnThreadPoolSize() {
return methodReturnThreadPoolSize;
return threadConfigs.get(ExecutorNames.METHODRETURN).poolSize();
}

public int getSignalThreadPriority() {
return signalThreadPriority;
return threadConfigs.get(ExecutorNames.SIGNAL).priority();
}

public int getMethodCallThreadPriority() {
return methodCallThreadPriority;
return threadConfigs.get(ExecutorNames.METHODCALL).priority();
}

public int getErrorThreadPriority() {
return errorThreadPriority;
return threadConfigs.get(ExecutorNames.ERROR).priority();
}

public int getMethodReturnThreadPriority() {
return methodReturnThreadPriority;
return threadConfigs.get(ExecutorNames.METHODRETURN).priority();
}

public IThreadPoolRetryHandler getRetryHandler() {
return retryHandler;
}

public boolean isSignalVirtualThreads() {
return threadConfigs.get(ExecutorNames.SIGNAL).virtual();
}

public boolean isErrorVirtualThreads() {
return threadConfigs.get(ExecutorNames.ERROR).virtual();
}

public boolean isMethodCallVirtualThreads() {
return threadConfigs.get(ExecutorNames.METHODCALL).virtual();
}

public boolean isMethodReturnVirtualThreads() {
return threadConfigs.get(ExecutorNames.METHODRETURN).virtual();
}

public boolean isVirtual(ExecutorNames _type) {
return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).virtual()).orElseThrow();
}

public int getPoolSize(ExecutorNames _type) {
return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).poolSize()).orElseThrow();
}

public int getPriority(ExecutorNames _type) {
return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).priority()).orElseThrow();
}

void setSignalThreadPoolSize(int _signalThreadPoolSize) {
signalThreadPoolSize = _signalThreadPoolSize;
threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(_signalThreadPoolSize, u.priority(), u.virtual()));
}

void setErrorThreadPoolSize(int _errorThreadPoolSize) {
errorThreadPoolSize = _errorThreadPoolSize;
threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(_errorThreadPoolSize, u.priority(), u.virtual()));
}

void setMethodCallThreadPoolSize(int _methodCallThreadPoolSize) {
methodCallThreadPoolSize = _methodCallThreadPoolSize;
threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(_methodCallThreadPoolSize, u.priority(), u.virtual()));
}

void setMethodReturnThreadPoolSize(int _methodReturnThreadPoolSize) {
methodReturnThreadPoolSize = _methodReturnThreadPoolSize;
threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(_methodReturnThreadPoolSize, u.priority(), u.virtual()));
}

void setSignalThreadPriority(int _signalThreadPriority) {
signalThreadPriority = _signalThreadPriority;
threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(u.poolSize(), _signalThreadPriority, u.virtual()));
}

void setMethodCallThreadPriority(int _methodCallThreadPriority) {
methodCallThreadPriority = _methodCallThreadPriority;
threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(u.poolSize(), _methodCallThreadPriority, u.virtual()));
}

void setErrorThreadPriority(int _errorThreadPriority) {
errorThreadPriority = _errorThreadPriority;
threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(u.poolSize(), _errorThreadPriority, u.virtual()));
}

void setMethodReturnThreadPriority(int _methodReturnThreadPriority) {
methodReturnThreadPriority = _methodReturnThreadPriority;
threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(u.poolSize(), _methodReturnThreadPriority, u.virtual()));
}

void setRetryHandler(IThreadPoolRetryHandler _retryHandler) {
retryHandler = _retryHandler;
}

void setSignalVirtualThreads(boolean _signalVirtualThreads) {
threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _signalVirtualThreads));
}

void setErrorVirtualThreads(boolean _errorVirtualThreads) {
threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _errorVirtualThreads));
}

void setMethodCallVirtualThreads(boolean _methodCallVirtualThreads) {
threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _methodCallVirtualThreads));
}

void setMethodReturnVirtualThreads(boolean _methodReturnVirtualThreads) {
threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _methodReturnVirtualThreads));
}

private record ThreadCfg(int poolSize, int priority, boolean virtual) {}
}
Loading
Loading