]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nameserv: add asynchronous resolving with POSIX threads
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 23 Apr 2014 15:50:36 +0000 (17:50 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 29 Apr 2014 13:19:06 +0000 (15:19 +0200)
Run getaddrinfo()/gethostbyname() in separate thread to avoid blocking.
Only one resolving thread is running at one time, so this should work
also on systems where the functions are not thread-safe.

configure
logging.h
nameserv_async.c

index db022426db6811b941341919272d95883e07e52d..420a177b068ecc24810f2c97b3abdf219de237ac 100755 (executable)
--- a/configure
+++ b/configure
@@ -112,6 +112,7 @@ For better control, use the options below.
   --disable-pps          Disable PPS API support
   --disable-rtc          Don't include RTC even on Linux
   --disable-linuxcaps    Disable Linux capabilities support
+  --disable-asyncdns     Disable asynchronous name resolving
   --disable-forcednsretry Don't retry on permanent DNS error
   --with-user=USER       Specify default chronyd user [root]
   --with-sendmail=PATH   Path to sendmail binary [/usr/lib/sendmail]
@@ -191,6 +192,7 @@ try_phc=0
 feat_pps=1
 try_setsched=0
 try_lockmem=0
+feat_asyncdns=1
 feat_forcednsretry=1
 default_user="root"
 mail_program="/usr/lib/sendmail"
@@ -267,6 +269,9 @@ do
     --disable-linuxcaps)
       feat_linuxcaps=0
     ;;
+    --disable-asyncdns)
+      feat_asyncdns=0
+    ;;
     --disable-forcednsretry)
       feat_forcednsretry=0
     ;;
@@ -419,6 +424,15 @@ then
   add_def HAVE_GETADDRINFO
 fi
 
+if [ $feat_asyncdns = "1" ] && \
+  test_code 'pthread' 'pthread.h' '-pthread' '' \
+    'return pthread_create(NULL, NULL, NULL, NULL);'
+then
+  add_def FEAT_ASYNCDNS
+  add_def USE_PTHREAD_ASYNCDNS
+  MYCFLAGS="$MYCFLAGS -pthread"
+fi
+
 timepps_h=""
 if [ $feat_pps = "1" ]; then
   if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
index fcadb7bbd268a45fe567fd4ac7fb575b7c66c2b9..9d7cbfbd9d497ec8c65208dd7d4ce067138aafd8 100644 (file)
--- a/logging.h
+++ b/logging.h
@@ -77,6 +77,7 @@ typedef enum {
   LOGF_Manual,
   LOGF_Keys,
   LOGF_Logging,
+  LOGF_Nameserv,
   LOGF_Rtc,
   LOGF_Regress,
   LOGF_Sys,
index b11da8699d0f18cfbea8fa9f0aad5d524650df5f..3ea187f4792e12467e6a09aa6eaf2fd5e25bcc16 100644 (file)
 
 #include "nameserv_async.h"
 #include "logging.h"
+#include "memory.h"
+#include "sched.h"
 #include "util.h"
 
+#ifdef FEAT_ASYNCDNS
+
+#ifdef USE_PTHREAD_ASYNCDNS
+#include <pthread.h>
+
+/* ================================================== */
+
+struct DNS_Async_Instance {
+  const char *name;
+  DNS_Status status;
+  IPAddr addr;
+  DNS_NameResolveHandler handler;
+  void *arg;
+
+  pthread_t thread;
+  int pipe[2];
+};
+
+static int resolving_threads = 0;
+
+/* ================================================== */
+
+static void *
+start_resolving(void *anything)
+{
+  struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
+
+  inst->status = DNS_Name2IPAddress(inst->name, &inst->addr);
+
+  /* Notify the main thread that the result is ready */
+  if (write(inst->pipe[1], "", 1) < 0)
+    ;
+
+  return NULL;
+}
+
+/* ================================================== */
+
+static void
+end_resolving(void *anything)
+{
+  struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
+
+  if (pthread_join(inst->thread, NULL)) {
+    LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
+  }
+
+  resolving_threads--;
+
+  SCH_RemoveInputFileHandler(inst->pipe[0]);
+  close(inst->pipe[0]);
+  close(inst->pipe[1]);
+
+  (inst->handler)(inst->status, &inst->addr, inst->arg);
+
+  Free(inst);
+}
+
 /* ================================================== */
 
+void
+DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
+{
+  struct DNS_Async_Instance *inst;
+
+  inst = MallocNew(struct DNS_Async_Instance);
+  inst->name = name;
+  inst->handler = handler;
+  inst->arg = anything;
+  inst->status = DNS_Failure;
+
+  if (pipe(inst->pipe)) {
+    LOG_FATAL(LOGF_Nameserv, "pipe() failed");
+  }
+
+  resolving_threads++;
+  assert(resolving_threads <= 1);
+
+  if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
+    LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
+  }
+
+  SCH_AddInputFileHandler(inst->pipe[0], end_resolving, inst);
+}
+
+/* ================================================== */
+
+#else
+#error
+#endif
+
+#else
+
 /* This is a blocking implementation used when nothing else is available */
 
 void
@@ -47,3 +140,5 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
 }
 
 /* ================================================== */
+
+#endif