Safe shutdown of ThreadGroup for DnsClient
This commit is contained in:
parent
dfd9e2c69d
commit
04a9365351
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.network;
|
package dorkbox.network;
|
||||||
|
|
||||||
|
import dorkbox.network.connection.EndPoint;
|
||||||
import dorkbox.network.dns.decoder.DomainDecoder;
|
import dorkbox.network.dns.decoder.DomainDecoder;
|
||||||
import dorkbox.network.dns.decoder.MailExchangerDecoder;
|
import dorkbox.network.dns.decoder.MailExchangerDecoder;
|
||||||
import dorkbox.network.dns.decoder.RecordDecoder;
|
import dorkbox.network.dns.decoder.RecordDecoder;
|
||||||
@ -60,8 +61,10 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for now, we only support ipv4
|
* for now, we only support ipv4
|
||||||
@ -69,6 +72,7 @@ import java.util.Map;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public
|
public
|
||||||
class DnsClient {
|
class DnsClient {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
// doesn't work in eclipse.
|
// doesn't work in eclipse.
|
||||||
@ -118,6 +122,9 @@ class DnsClient {
|
|||||||
private final DnsNameResolver resolver;
|
private final DnsNameResolver resolver;
|
||||||
|
|
||||||
private final Map<DnsRecordType, RecordDecoder<?>> customDecoders = new HashMap<DnsRecordType, RecordDecoder<?>>();
|
private final Map<DnsRecordType, RecordDecoder<?>> customDecoders = new HashMap<DnsRecordType, RecordDecoder<?>>();
|
||||||
|
private ThreadGroup threadGroup;
|
||||||
|
public static final String THREAD_NAME = "DnsClient";
|
||||||
|
private EventLoopGroup eventLoopGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new DNS client, using the provided server (default port 53) for DNS query resolution, with a cache that will obey the TTL of the response
|
* Creates a new DNS client, using the provided server (default port 53) for DNS query resolution, with a cache that will obey the TTL of the response
|
||||||
@ -161,38 +168,34 @@ class DnsClient {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
DnsClient(Collection<InetSocketAddress> nameServerAddresses, int minTtl, int maxTtl) {
|
DnsClient(Collection<InetSocketAddress> nameServerAddresses, int minTtl, int maxTtl) {
|
||||||
EventLoopGroup group;
|
|
||||||
Class<? extends DatagramChannel> channelType;
|
Class<? extends DatagramChannel> channelType;
|
||||||
|
|
||||||
final String threadName = "DnsClient";
|
|
||||||
|
|
||||||
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
||||||
SecurityManager s = System.getSecurityManager();
|
SecurityManager s = System.getSecurityManager();
|
||||||
ThreadGroup nettyGroup = new ThreadGroup(s != null
|
threadGroup = new ThreadGroup(s != null
|
||||||
? s.getThreadGroup()
|
? s.getThreadGroup()
|
||||||
: Thread.currentThread()
|
: Thread.currentThread()
|
||||||
.getThreadGroup(), threadName);
|
.getThreadGroup(), THREAD_NAME);
|
||||||
nettyGroup.setDaemon(true);
|
threadGroup.setDaemon(true);
|
||||||
|
|
||||||
if (PlatformDependent.isAndroid()) {
|
if (PlatformDependent.isAndroid()) {
|
||||||
// android ONLY supports OIO (not NIO)
|
// android ONLY supports OIO (not NIO)
|
||||||
group = new OioEventLoopGroup(1, new NamedThreadFactory(threadName + "-UDP", nettyGroup));
|
eventLoopGroup = new OioEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-UDP", threadGroup));
|
||||||
channelType = OioDatagramChannel.class;
|
channelType = OioDatagramChannel.class;
|
||||||
}
|
}
|
||||||
else if (OS.isLinux()) {
|
else if (OS.isLinux()) {
|
||||||
// JNI network stack is MUCH faster (but only on linux)
|
// JNI network stack is MUCH faster (but only on linux)
|
||||||
group = new EpollEventLoopGroup(1, new NamedThreadFactory(threadName + "-UDP", nettyGroup));
|
eventLoopGroup = new EpollEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-UDP", threadGroup));
|
||||||
channelType = EpollDatagramChannel.class;
|
channelType = EpollDatagramChannel.class;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
group = new NioEventLoopGroup(1, new NamedThreadFactory(threadName + "-UDP", nettyGroup));
|
eventLoopGroup = new NioEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-UDP", threadGroup));
|
||||||
channelType = NioDatagramChannel.class;
|
channelType = NioDatagramChannel.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
DnsNameResolverBuilder builder = new DnsNameResolverBuilder(group.next());
|
DnsNameResolverBuilder builder = new DnsNameResolverBuilder(eventLoopGroup.next());
|
||||||
builder.channelFactory(new ReflectiveChannelFactory<DatagramChannel>(channelType))
|
builder.channelFactory(new ReflectiveChannelFactory<DatagramChannel>(channelType))
|
||||||
.channelType(channelType)
|
.channelType(channelType)
|
||||||
.localAddress(null)
|
|
||||||
.ttl(minTtl, maxTtl)
|
.ttl(minTtl, maxTtl)
|
||||||
.resolvedAddressTypes(InternetProtocolFamily.IPv4) // for now, we only support ipv4
|
.resolvedAddressTypes(InternetProtocolFamily.IPv4) // for now, we only support ipv4
|
||||||
.nameServerAddresses(DnsServerAddresses.sequential(nameServerAddresses));
|
.nameServerAddresses(DnsServerAddresses.sequential(nameServerAddresses));
|
||||||
@ -335,6 +338,45 @@ class DnsClient {
|
|||||||
void stop() {
|
void stop() {
|
||||||
reset();
|
reset();
|
||||||
resolver.close();
|
resolver.close();
|
||||||
|
|
||||||
|
|
||||||
|
// we also want to stop the thread group (but NOT in our current thread!)
|
||||||
|
if (Thread.currentThread()
|
||||||
|
.getThreadGroup()
|
||||||
|
.getName()
|
||||||
|
.equals(THREAD_NAME)) {
|
||||||
|
|
||||||
|
Thread thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void run() {
|
||||||
|
DnsClient.this.stopInThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.setDaemon(false);
|
||||||
|
thread.setName("DnsClient Shutdown");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stopInThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
void stopInThread() {
|
||||||
|
// Sometimes there might be "lingering" connections (ie, halfway though registration) that need to be closed.
|
||||||
|
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
||||||
|
|
||||||
|
// we want to WAIT until after the event executors have completed shutting down.
|
||||||
|
List<Future<?>> shutdownThreadList = new LinkedList<Future<?>>();
|
||||||
|
|
||||||
|
// now wait it them to finish!
|
||||||
|
// It can take a few seconds to shut down the executor. This will affect unit testing, where connections are quickly created/stopped
|
||||||
|
eventLoopGroup.shutdownGracefully(maxShutdownWaitTimeInMilliSeconds, maxShutdownWaitTimeInMilliSeconds * 4, TimeUnit.MILLISECONDS)
|
||||||
|
.syncUninterruptibly();
|
||||||
|
|
||||||
|
threadGroup.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
|
Loading…
Reference in New Issue
Block a user