Start a thread for each DNS lookup. Fixes vibe-d/vibe.d#2378.
std.parallelism.Task.executeInNewThread leaks the thread's resources instead of reusing it in later calls. As a workaround, this commit starts a new thread for every lookup and properly tears it down afterwards. At a later point, this code should be changed to reuse the thread(s), if possible, to avoid the startup overhead.
This commit is contained in:
parent
f38a8cdb5a
commit
5255645455
|
@ -28,13 +28,16 @@ version (Posix)
|
||||||
final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriverSignals) : EventDriverDNS {
|
final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriverSignals) : EventDriverDNS {
|
||||||
import std.parallelism : task, taskPool;
|
import std.parallelism : task, taskPool;
|
||||||
import std.string : toStringz;
|
import std.string : toStringz;
|
||||||
|
import core.thread : Thread;
|
||||||
|
|
||||||
private {
|
private {
|
||||||
static struct Lookup {
|
static struct Lookup {
|
||||||
|
bool done;
|
||||||
DNSLookupCallback callback;
|
DNSLookupCallback callback;
|
||||||
addrinfo* result;
|
addrinfo* result;
|
||||||
int retcode;
|
int retcode;
|
||||||
string name;
|
string name;
|
||||||
|
Thread thread;
|
||||||
}
|
}
|
||||||
ChoppedVector!Lookup m_lookups;
|
ChoppedVector!Lookup m_lookups;
|
||||||
Events m_events;
|
Events m_events;
|
||||||
|
@ -69,30 +72,54 @@ final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriver
|
||||||
Lookup* l = () @trusted { return &m_lookups[handle]; } ();
|
Lookup* l = () @trusted { return &m_lookups[handle]; } ();
|
||||||
l.name = name;
|
l.name = name;
|
||||||
l.callback = on_lookup_finished;
|
l.callback = on_lookup_finished;
|
||||||
|
l.done = false;
|
||||||
auto events = () @trusted { return cast(shared)m_events; } ();
|
auto events = () @trusted { return cast(shared)m_events; } ();
|
||||||
auto t = task!taskFun(l, AddressFamily.UNSPEC, events, m_event);
|
|
||||||
try t.executeInNewThread();//taskPool.put(t);
|
try {
|
||||||
catch (Exception e) return DNSLookupID.invalid;
|
auto thr = new class(l, AddressFamily.UNSPEC, events, m_event) Thread {
|
||||||
|
Lookup* m_lookup;
|
||||||
|
AddressFamily m_family;
|
||||||
|
shared(Events) m_events;
|
||||||
|
EventID m_event;
|
||||||
|
|
||||||
|
this(Lookup* l, AddressFamily af, shared(Events) events, EventID event)
|
||||||
|
{
|
||||||
|
m_lookup = l;
|
||||||
|
m_family = af;
|
||||||
|
m_events = events;
|
||||||
|
m_event = event;
|
||||||
|
super(&perform);
|
||||||
|
this.name = "Eventcore DNS Lookup";
|
||||||
|
l.thread = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform()
|
||||||
|
nothrow {
|
||||||
|
debug (EventCoreLogDNS) print("lookup %s start", m_lookup.name);
|
||||||
|
addrinfo hints;
|
||||||
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
|
version (linux) hints.ai_flags |= AI_V4MAPPED;
|
||||||
|
hints.ai_family = m_family;
|
||||||
|
() @trusted { m_lookup.retcode = getaddrinfo(m_lookup.name.toStringz(), null, m_family == AddressFamily.UNSPEC ? null : &hints, &m_lookup.result); } ();
|
||||||
|
if (m_lookup.retcode == -1)
|
||||||
|
version (CRuntime_Glibc) version (linux) __res_init();
|
||||||
|
|
||||||
|
m_lookup.done = true;
|
||||||
|
m_events.trigger(m_event, true);
|
||||||
|
debug (EventCoreLogDNS) print("lookup %s finished", m_lookup.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
() @trusted { thr.start(); } ();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return DNSLookupID.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
debug (EventCoreLogDNS) print("lookup handle: %s", handle);
|
debug (EventCoreLogDNS) print("lookup handle: %s", handle);
|
||||||
m_events.loop.m_waiterCount++;
|
m_events.loop.m_waiterCount++;
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// public
|
|
||||||
static void taskFun(Lookup* lookup, int af, shared(Events) events, EventID event)
|
|
||||||
{
|
|
||||||
debug (EventCoreLogDNS) print("lookup %s start", lookup.name);
|
|
||||||
addrinfo hints;
|
|
||||||
hints.ai_flags = AI_ADDRCONFIG;
|
|
||||||
version (linux) hints.ai_flags |= AI_V4MAPPED;
|
|
||||||
hints.ai_family = af;
|
|
||||||
() @trusted { lookup.retcode = getaddrinfo(lookup.name.toStringz(), null, af == AddressFamily.UNSPEC ? null : &hints, &lookup.result); } ();
|
|
||||||
if (lookup.retcode == -1)
|
|
||||||
version (CRuntime_Glibc) version (linux) __res_init();
|
|
||||||
events.trigger(event, true);
|
|
||||||
debug (EventCoreLogDNS) print("lookup %s finished", lookup.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void cancelLookup(DNSLookupID handle)
|
override void cancelLookup(DNSLookupID handle)
|
||||||
{
|
{
|
||||||
m_lookups[handle].callback = null;
|
m_lookups[handle].callback = null;
|
||||||
|
@ -107,6 +134,15 @@ final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriver
|
||||||
size_t lastmax;
|
size_t lastmax;
|
||||||
foreach (i, ref l; m_lookups) {
|
foreach (i, ref l; m_lookups) {
|
||||||
if (i > m_maxHandle) break;
|
if (i > m_maxHandle) break;
|
||||||
|
if (!l.done) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
l.thread.join();
|
||||||
|
destroy(l.thread);
|
||||||
|
} catch (Exception e) {
|
||||||
|
debug (EventCoreLogDNS) print("Failed to join DNS thread: %s", e.msg);
|
||||||
|
}
|
||||||
|
|
||||||
if (l.callback) {
|
if (l.callback) {
|
||||||
if (l.result || l.retcode) {
|
if (l.result || l.retcode) {
|
||||||
debug (EventCoreLogDNS) print("found finished lookup %s for %s", i, l.name);
|
debug (EventCoreLogDNS) print("found finished lookup %s for %s", i, l.name);
|
||||||
|
|
Loading…
Reference in a new issue