? ares/compile
? m4/acx_pthread.m4
Index: configure.ac
===================================================================
RCS file: /cvsroot/curl/curl/configure.ac,v
retrieving revision 1.424
diff -u -r1.424 configure.ac
--- configure.ac	24 Aug 2009 11:38:59 -0000	1.424
+++ configure.ac	27 Aug 2009 18:21:04 -0000
@@ -116,7 +116,7 @@
    curl_krb4_msg="no      (--with-krb4*)"
     curl_gss_msg="no      (--with-gssapi)"
  curl_spnego_msg="no      (--with-spnego)"
-   curl_ares_msg="no      (--enable-ares)"
+ curl_asynch_msg="no      (--enable-ares / --enable-threaded-resolve)"
    curl_ipv6_msg="no      (--enable-ipv6)"
     curl_idn_msg="no      (--with-libidn)"
  curl_manual_msg="no      (--enable-manual)"
@@ -2227,7 +2227,7 @@
        dnl substitute HAVE_ARES for curl-config and similar
        HAVE_ARES="1"
        AC_SUBST(HAVE_ARES)
-       curl_ares_msg="enabled"
+       curl_asynch_msg="enabled (c-ares)"
 
        LIBS="-lcares $LIBS"
 
@@ -2282,6 +2282,56 @@
 dnl set variable for use in automakefile(s)
 AM_CONDITIONAL(USE_EMBEDDED_ARES, test x$aresembedded = xyes)
 
+dnl **********************************************************************
+dnl If we don't have ares, threaded resolve is the next best thing.
+dnl **********************************************************************
+USE_THREADED_RESOLVE=yes
+AC_ARG_ENABLE(threaded-resolve,
+AC_HELP_STRING([--enable-threaded-resolve],[Enable threaded DNS resolution])
+AC_HELP_STRING([--disable-threaded-resolve],[Disable threaded DNS resolution]),
+[ case "$enableval" in
+  no)
+       AC_MSG_RESULT(no)
+       AC_DEFINE(CURL_DISABLE_THREADED_RESOLVE, 1,
+                 [to disable threaded DNS resolution explicitly])
+       USE_THREADED_RESOLVE=no
+       ;;
+  *)   AC_MSG_RESULT(yes)
+       ;;
+  esac ],
+       AC_MSG_RESULT(yes)
+)
+
+if test x$USE_THREADED_RESOLVE = xyes && test X"$OPT_THREAD" = Xon; then
+
+if test x$HAVE_ARES = x1; then
+   AC_MSG_WARN(already using c-ares, no need for threaded DNS)
+else
+   dnl Check for threading libraries and headers.
+   if test x$ac_cv_native_windows = xyes; then
+      dnl if you have a working Win32 SDK, you have threads.
+      curl_async_msg="yes (Windows threads)"
+   else
+      ACX_PTHREAD
+
+      # Also check for error-checking mutex availability.
+      AC_MSG_CHECKING(for error-checking mutex availability)
+      AC_PREPROC_IFELSE(
+         [AC_LANG_PROGRAM([[#define _XOPEN_SOURCE
+                            #include <pthread.h>]],
+                          [[int i = PTHREAD_MUTEX_ERRORCHECK;]])],
+         [have_errorcheck_mutex=yes],
+         [have_errorcheck_mutex=no])
+
+      AC_MSG_RESULT([$have_errorcheck_mutex])
+
+      if test x$acx_pthread_ok = xyes && test x$have_errorcheck_mutex = xyes; then
+         curl_asynch_msg="yes (pthreads)"
+      fi
+   fi
+fi
+fi
+
 dnl ************************************************************
 dnl disable verbose text strings
 dnl
@@ -2585,7 +2635,7 @@
   krb4 support:    ${curl_krb4_msg}
   GSSAPI support:  ${curl_gss_msg}
   SPNEGO support:  ${curl_spnego_msg}
-  c-ares support:  ${curl_ares_msg}
+  Asynch DNS:      ${curl_asynch_msg}
   ipv6 support:    ${curl_ipv6_msg}
   IDN support:     ${curl_idn_msg}
   Build libcurl:   Shared=${enable_shared}, Static=${enable_static}
Index: lib/hostthre.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/hostthre.c,v
retrieving revision 1.59
diff -u -r1.59 hostthre.c
--- lib/hostthre.c	21 Apr 2009 11:46:16 -0000	1.59
+++ lib/hostthre.c	27 Aug 2009 18:21:04 -0000
@@ -21,6 +21,16 @@
  * $Id: hostthre.c,v 1.59 2009-04-21 11:46:16 yangtse Exp $
  ***************************************************************************/
 
+/* to get defines for error-checking mutexes */
+#define _XOPEN_SOURCE 500
+
+/* Needed for NI_MAXSERV - default normally but _XOPEN_SOURCE disables it*/
+#ifdef __APPLE__
+#  define _DARWIN_C_SOURCE
+#else
+#  define _BSD_SOURCE
+#endif
+
 #include "setup.h"
 
 #include <string.h>
@@ -50,6 +60,10 @@
 #include <stdlib.h>
 #endif
 
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
 #ifdef HAVE_PROCESS_H
 #include <process.h>
 #endif
@@ -83,7 +97,7 @@
 #endif
 
 /***********************************************************************
- * Only for Windows threaded name resolves builds
+ * Only for Windows and Mac threaded name resolves builds
  **********************************************************************/
 #ifdef CURLRES_THREADED
 
@@ -94,24 +108,196 @@
 
 #ifdef CURLRES_IPV4
   #define THREAD_FUNC  gethostbyname_thread
-  #define THREAD_NAME "gethostbyname_thread"
 #else
   #define THREAD_FUNC  getaddrinfo_thread
-  #define THREAD_NAME "getaddrinfo_thread"
+#endif
+
+/* Here's where we abstract everything out. */
+#ifdef _WIN32
+typedef HANDLE thread_handle;
+typedef HANDLE thread_mutex;
+typedef HANDLE thread_event;
+typedef DWORD thread_status;
+
+#define STDCALL __stdcall
+
+#define THREAD_EVENT_CREATE()    CreateEvent(NULL, TRUE, FALSE, NULL)
+#define THREAD_MUTEX_CREATE()    CreateMutex(NULL, TRUE, NULL)
+
+#define THREAD_EVENT_DESTROY(ev) CloseHandle(ev)
+#define THREAD_EVENT_RAISE(ev)   SetEvent(ev)
+#define THREAD_EVENT_COPY(ev)    _copy_handle(ev)
+#define THREAD_EVENT_TRYWAIT(ev, mu, ms) _lock_and_wait_ms(ev, mu, ms)
+#define THREAD_EVENT_WAIT(ev, mu) (WaitForSingleObject(ev, INFINITE) == WAIT_OBJECT_0)
+
+#define THREAD_MUTEX_DESTROY(mu) CloseHandle(mu)
+#define THREAD_MUTEX_UNLOCK(mu)  ReleaseMutex(mu)
+#define THREAD_MUTEX_LOCK(mu)    (WaitForSingleObject(mu, INFINITE) == WAIT_OBJECT_0)
+#define THREAD_MUTEX_TRYLOCK(mu) (WaitForSingleObject(mu, 0) == WAIT_OBJECT_0)
+#define THREAD_MUTEX_COPY(mu)    _copy_handle(mu)
+
+#ifdef _WIN32_WCE
+#define THREAD_CREATE(func, arg) (CreateThread(NULL, 0, func, arg, 0, NULL)
+#else
+#define THREAD_CREATE(func, arg) (HANDLE)(_beginthreadex(NULL, 0, func, arg, 0, NULL)
+#endif
+#define THREAD_DESTROY(th)       CloseHandle(th)
+
+static int
+_lock_and_wait_ms(thread_event ev, thread_mutex mu, DWORD ms)
+{
+   /* Wait indefinitely to lock the mutex. */
+   if (WaitForSingleObject(mu, INFINITE) != WAIT_OBJECT_0) {
+      return FALSE;
+   }
+
+   return (WaitForSingleObject(ev, ms) == WAIT_OBJECT_0);
+}
+
+static HANDLE
+_copy_handle(HANDLE m)
+{
+   HANDLE curr_proc = GetCurrentProcess();
+   HANDLE n = NULL;
+
+   if(!DuplicateHandle(curr_proc, m,
+                       curr_proc, &n, 0, FALSE,
+                       DUPLICATE_SAME_ACCESS)) {
+      return NULL;
+   }
+
+   return n;
+}
+
+#else
+typedef pthread_t thread_handle;
+typedef pthread_mutex_t *thread_mutex;
+typedef pthread_cond_t *thread_event;
+typedef unsigned int thread_status;
+
+#define STDCALL
+
+/* We need a function here so we can malloc. */
+#define THREAD_EVENT_CREATE()    _new_pthread_cond()
+#define THREAD_MUTEX_CREATE()    _new_pthread_mutex()
+
+#define THREAD_EVENT_DESTROY(ev) { pthread_cond_destroy(ev); free(ev); }
+#define THREAD_EVENT_RAISE(ev)   pthread_cond_broadcast(ev)
+#define THREAD_EVENT_COPY(ev)    _copy_pthread_cond(ev)
+#define THREAD_EVENT_TRYWAIT(ev, mu, ms) _pthread_timedwait_ms(ev, mu, ms)
+#define THREAD_EVENT_WAIT(ev, mu) pthread_cond_wait(ev, mu)
+
+static int
+_pthread_timedwait_ms(thread_event ev, thread_mutex mu, uint32_t ms)
+{
+   struct timespec t;
+   struct timeval tv;
+   int i;
+
+   /* Fill with the current time, then add to it */
+   gettimeofday(&tv, NULL);
+
+   /* Convert milliseconds to timespec */
+   t.tv_sec  = tv.tv_sec + (ms / 1000);
+   t.tv_nsec = (tv.tv_usec * 1000) + ((ms % 1000) * 1000000);
+
+   i = pthread_cond_timedwait(ev, mu, &t);
+   return (i == 0);
+}
+
+#define THREAD_MUTEX_DESTROY(mu) { pthread_mutex_destroy(mu); free(mu); }
+#define THREAD_MUTEX_UNLOCK(mu)  pthread_mutex_unlock(mu)
+#define THREAD_MUTEX_LOCK(mu)    _lock_pthread_mutex_safe(mu)
+#define THREAD_MUTEX_TRYLOCK(mu) (pthread_mutex_trylock(mu) == 0)
+#define THREAD_MUTEX_COPY(mu)    _copy_pthread_mutex(mu)
+
+#define THREAD_CREATE(func, arg) _new_pthread(func, arg)
+#define THREAD_DESTROY(th)       do { } while (0)
+
+static int
+_lock_pthread_mutex_safe(thread_mutex mu)
+{
+   /*
+    * The Windows semantics are that locking an already locked mutex
+    * is a no-op. Simulate that here.
+    */
+   int i = pthread_mutex_lock(mu);
+   return (i == EDEADLK || i == 0);
+}
+
+static thread_handle
+_new_pthread(void *(*func) (void*), void *arg)
+{
+   thread_handle t = 0;
+   pthread_create(&t, NULL, func, arg);
+   return t;
+}
+
+static thread_mutex
+_new_pthread_mutex(void)
+{
+   pthread_mutexattr_t attr;
+   thread_mutex m = malloc(sizeof(*m));
+   if (!m) return NULL;
+   pthread_mutexattr_init(&attr);
+   /* This allows us to lock from the same thread twice. */
+   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+   pthread_mutex_init(m, &attr);
+   /* CreateMutex locks by default */
+   pthread_mutex_lock(m);
+   return m;
+}
+
+static thread_event
+_new_pthread_cond(void)
+{
+   thread_event e = malloc(sizeof(*e));
+   if (!e) return NULL;
+   pthread_cond_init(e, NULL);
+   return e;
+}
+
+static thread_mutex
+_copy_pthread_mutex(thread_mutex m)
+{
+   thread_mutex n = malloc(sizeof(*n));
+   memcpy(n, m, sizeof(*n));
+   return n;
+}
+
+static thread_event
+_copy_pthread_cond(thread_event m)
+{
+   thread_event n = malloc(sizeof(*n));
+   memcpy(n, m, sizeof(*n));
+   return n;
+}
+
 #endif
 
 struct thread_data {
-  HANDLE thread_hnd;
-  unsigned thread_id;
-  DWORD  thread_status;
-  curl_socket_t dummy_sock;   /* dummy for Curl_resolv_fdset() */
-  HANDLE mutex_waiting;  /* marks that we are still waiting for a resolve */
-  HANDLE event_resolved; /* marks that the thread obtained the information */
-  HANDLE event_thread_started; /* marks that the thread has initialized and
-                                  started */
-  HANDLE mutex_terminate; /* serializes access to flag_terminate */
-  HANDLE event_terminate; /* flag for thread to terminate instead of calling
-                             callbacks */
+  thread_handle thread_hnd;
+  thread_status  status;
+  /* dummy for Curl_resolv_fdset() */
+  curl_socket_t dummy_sock;
+  /* mutex we use when we don't care about synchronization */
+  thread_mutex mutex_dummy;
+  /* marks that we are still waiting for a resolve */
+  thread_mutex mutex_waiting;
+  /* mutex to guard event_resolved */
+  thread_mutex mutex_resolved;
+  /* marks that the thread obtained the information */
+  thread_event event_resolved;
+  /* marks that the thread has initialized and started */
+  thread_event event_thread_started;
+  /* mutex to guard event_resolved */
+  thread_mutex mutex_thread_started;
+  /* flag we use to track that the thread started */
+  int thread_started;
+  /* serializes access to flag_terminate */
+  thread_mutex mutex_terminate;
+  /* flag for thread to terminate instead of calling callbacks */
+  thread_event event_terminate;
 #ifdef CURLRES_IPV6
   struct addrinfo hints;
 #endif
@@ -119,11 +305,10 @@
 
 /* Data for synchronization between resolver thread and its parent */
 struct thread_sync_data {
-  HANDLE mutex_waiting;   /* thread_data.mutex_waiting duplicate */
-  HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
-  HANDLE event_terminate; /* thread_data.event_terminate duplicate */
-  char * hostname;        /* hostname to resolve, Curl_async.hostname
-                             duplicate */
+  thread_mutex mutex_waiting;   /* thread_data.mutex_waiting duplicate */
+  thread_mutex mutex_terminate; /* thread_data.mutex_terminate duplicate */
+  thread_event event_terminate; /* thread_data.event_terminate duplicate */
+  char * hostname;      /* hostname to resolve, Curl_async.hostname duplicate */
 };
 
 /* Destroy resolver thread synchronization data */
@@ -133,40 +318,36 @@
   if(tsd->hostname)
     free(tsd->hostname);
   if(tsd->event_terminate)
-    CloseHandle(tsd->event_terminate);
+    THREAD_EVENT_DESTROY(tsd->event_terminate);
   if(tsd->mutex_terminate)
-    CloseHandle(tsd->mutex_terminate);
+    THREAD_MUTEX_DESTROY(tsd->mutex_terminate);
   if(tsd->mutex_waiting)
-    CloseHandle(tsd->mutex_waiting);
+    THREAD_MUTEX_DESTROY(tsd->mutex_waiting);
   memset(tsd,0,sizeof(*tsd));
 }
 
 /* Initialize resolver thread synchronization data */
 static
-BOOL init_thread_sync_data(struct thread_data * td,
-                           const char * hostname,
-                           struct thread_sync_data * tsd)
+int init_thread_sync_data(struct thread_data * td,
+                          const char * hostname,
+                          struct thread_sync_data * tsd)
 {
-  HANDLE curr_proc = GetCurrentProcess();
-
   memset(tsd, 0, sizeof(*tsd));
-  if(!DuplicateHandle(curr_proc, td->mutex_waiting,
-                       curr_proc, &tsd->mutex_waiting, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS)) {
+
+  tsd->mutex_waiting = THREAD_MUTEX_COPY(td->mutex_waiting);
+  if (tsd->mutex_waiting == NULL) {
     /* failed to duplicate the mutex, no point in continuing */
     destroy_thread_sync_data(tsd);
     return FALSE;
   }
-  if(!DuplicateHandle(curr_proc, td->mutex_terminate,
-                       curr_proc, &tsd->mutex_terminate, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS)) {
+  tsd->mutex_terminate = THREAD_MUTEX_COPY(td->mutex_terminate);
+  if (tsd->mutex_terminate == NULL) {
     /* failed to duplicate the mutex, no point in continuing */
     destroy_thread_sync_data(tsd);
     return FALSE;
   }
-  if(!DuplicateHandle(curr_proc, td->event_terminate,
-                       curr_proc, &tsd->event_terminate, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS)) {
+  tsd->event_terminate = THREAD_EVENT_COPY(td->event_terminate);
+  if(tsd->event_terminate == NULL) {
     /* failed to duplicate the event, no point in continuing */
     destroy_thread_sync_data(tsd);
     return FALSE;
@@ -185,26 +366,21 @@
 
 /* acquire resolver thread synchronization */
 static
-BOOL acquire_thread_sync(struct thread_sync_data * tsd)
+int acquire_thread_sync(struct thread_sync_data * tsd)
 {
   /* is the thread initiator still waiting for us ? */
-  if(WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
-    /* yes, it is */
-
-    /* Waiting access to event_terminate */
-    if(WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
-      /* Something went wrong - now just ignoring */
-    }
-    else {
-      if(WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
-        /* Parent thread signaled us to terminate.
-         * This means that all data in conn->async is now destroyed
-         * and we cannot use it.
-         */
-      }
-      else {
-        return TRUE;
-      }
+  if(!THREAD_MUTEX_TRYLOCK(tsd->mutex_waiting)) {
+    /*
+     * Yes, it is - then wait on the event. This implicitly locks the mutex and
+     * checks to see if the event is signaled.
+     */
+    if (THREAD_EVENT_TRYWAIT(tsd->event_terminate, tsd->mutex_terminate, 0)) {
+      /* Parent thread signaled us to terminate.
+       * This means that all data in conn->async is now destroyed
+       * and we cannot use it.
+       */
+    } else {
+      return TRUE;
     }
   }
   return FALSE;
@@ -214,7 +390,7 @@
 static
 void release_thread_sync(struct thread_sync_data * tsd)
 {
-  ReleaseMutex(tsd->mutex_terminate);
+  THREAD_MUTEX_UNLOCK(tsd->mutex_terminate);
 }
 
 #if defined(CURLRES_IPV4)
@@ -225,7 +401,7 @@
  * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
  * it.
  */
-static unsigned __stdcall gethostbyname_thread (void *arg)
+static unsigned STDCALL gethostbyname_thread (void *arg)
 {
   struct connectdata *conn = (struct connectdata*) arg;
   struct thread_data *td = (struct thread_data*) conn->async.os_specific;
@@ -246,23 +422,40 @@
   conn->async.status = NO_DATA;  /* pending status */
   SET_SOCKERRNO(conn->async.status);
 
+  /*
+   * First, lock the mutex. This ensures that the parent thread is now
+   * listening for us properly.
+   */
+  THREAD_MUTEX_LOCK(td->mutex_thread_started);
+  td->thread_started = 1;
+  THREAD_MUTEX_UNLOCK(td->mutex_thread_started);
+
   /* Signaling that we have initialized all copies of data and handles we
      need */
-  SetEvent(td->event_thread_started);
+  THREAD_EVENT_RAISE(td->event_thread_started);
 
   he = gethostbyname (tsd.hostname);
 
   /* is parent thread waiting for us and are we able to access conn members? */
   if(acquire_thread_sync(&tsd)) {
-    /* Mark that we have obtained the information, and that we are calling
-     * back with it. */
-    SetEvent(td->event_resolved);
+    /*
+     * First, lock the mutex. This ensures that the parent thread is now
+     * waiting for us properly.
+     */
+    THREAD_MUTEX_LOCK(td->mutex_resolved);
+
     if(he) {
       rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
     }
     else {
       rc = Curl_addrinfo4_callback(conn, SOCKERRNO, NULL);
     }
+
+    /* Mark that we have obtained the information, and that we are calling
+     * back with it. */
+    THREAD_MUTEX_UNLOCK(td->mutex_resolved);
+    THREAD_EVENT_RAISE(td->event_resolved);
+
     release_thread_sync(&tsd);
   }
 
@@ -282,7 +475,7 @@
  * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
  * and wait on it.
  */
-static unsigned __stdcall getaddrinfo_thread (void *arg)
+static unsigned STDCALL getaddrinfo_thread (void *arg)
 {
   struct connectdata *conn = (struct connectdata*) arg;
   struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
@@ -295,29 +488,39 @@
    * This allows us to use it even after the container gets destroyed
    * due to a resolver timeout.
    */
-  struct thread_sync_data tsd = { 0,0,0,NULL };
+  struct thread_sync_data tsd = { 0,0,0, NULL };
 
   if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
     /* thread synchronization data initialization failed */
     return -1;
   }
 
-  itoa(conn->async.port, service, 10);
+  snprintf(service, sizeof(service), "%d", conn->async.port);
 
   conn->async.status = NO_DATA;  /* pending status */
   SET_SOCKERRNO(conn->async.status);
 
+  /*
+   * First, lock the mutex. This ensures that the parent thread is now
+   * listening for us properly.
+   */
+  THREAD_MUTEX_LOCK(td->mutex_thread_started);
+  td->thread_started = 1;
+  THREAD_MUTEX_UNLOCK(td->mutex_thread_started);
+
   /* Signaling that we have initialized all copies of data and handles we
      need */
-  SetEvent(td->event_thread_started);
+  THREAD_EVENT_RAISE(td->event_thread_started);
 
   rc = Curl_getaddrinfo_ex(tsd.hostname, service, &hints, &res);
 
   /* is parent thread waiting for us and are we able to access conn members? */
   if(acquire_thread_sync(&tsd)) {
-    /* Mark that we have obtained the information, and that we are calling
-       back with it. */
-    SetEvent(td->event_resolved);
+    /*
+     * First, lock the mutex. This ensures that the parent thread is now
+     * waiting for us properly.
+     */
+    THREAD_MUTEX_LOCK(td->mutex_resolved);
 
     if(rc == 0) {
       rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
@@ -325,6 +528,12 @@
     else {
       rc = Curl_addrinfo6_callback(conn, SOCKERRNO, NULL);
     }
+
+    /* Mark that we have obtained the information, and that we are calling
+       back with it. */
+    THREAD_MUTEX_UNLOCK(td->mutex_resolved);
+    THREAD_EVENT_RAISE(td->event_resolved);
+
     release_thread_sync(&tsd);
   }
 
@@ -351,9 +560,9 @@
 
     if(td->mutex_terminate && td->event_terminate) {
       /* Signaling resolver thread to terminate */
-      if(WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
-        SetEvent(td->event_terminate);
-        ReleaseMutex(td->mutex_terminate);
+      if(THREAD_MUTEX_LOCK(td->mutex_terminate)) {
+        THREAD_EVENT_RAISE(td->event_terminate);
+        THREAD_MUTEX_UNLOCK(td->mutex_terminate);
       }
       else {
         /* Something went wrong - just ignoring it */
@@ -361,24 +570,29 @@
     }
 
     if(td->mutex_terminate)
-      CloseHandle(td->mutex_terminate);
+      THREAD_MUTEX_DESTROY(td->mutex_terminate);
     if(td->event_terminate)
-      CloseHandle(td->event_terminate);
+      THREAD_EVENT_DESTROY(td->event_terminate);
     if(td->event_thread_started)
-      CloseHandle(td->event_thread_started);
+      THREAD_EVENT_DESTROY(td->event_thread_started);
 
     if(sock != CURL_SOCKET_BAD)
       sclose(sock);
 
     /* destroy the synchronization objects */
     if(td->mutex_waiting)
-      CloseHandle(td->mutex_waiting);
+      THREAD_MUTEX_DESTROY(td->mutex_waiting);
     td->mutex_waiting = NULL;
     if(td->event_resolved)
-      CloseHandle(td->event_resolved);
+      THREAD_EVENT_DESTROY(td->event_resolved);
+    if(td->mutex_resolved)
+      THREAD_MUTEX_DESTROY(td->mutex_resolved);
+    if(td->mutex_thread_started)
+      THREAD_MUTEX_DESTROY(td->mutex_thread_started);
+    td->mutex_thread_started = NULL;
 
     if(td->thread_hnd)
-      CloseHandle(td->thread_hnd);
+      THREAD_DESTROY(td->thread_hnd);
 
     free(async->os_specific);
   }
@@ -397,7 +611,6 @@
                                  const struct addrinfo *hints)
 {
   struct thread_data *td = calloc(sizeof(*td), 1);
-  HANDLE thread_and_event[2] = {0};
 
   if(!td) {
     SET_ERRNO(ENOMEM);
@@ -422,17 +635,27 @@
   /* Create the mutex used to inform the resolver thread that we're
    * still waiting, and take initial ownership.
    */
-  td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
+  td->mutex_waiting = THREAD_MUTEX_CREATE();
   if(td->mutex_waiting == NULL) {
     Curl_destroy_thread_data(&conn->async);
     SET_ERRNO(EAGAIN);
     return FALSE;
   }
 
+  /* Create a dummy mutex that is only used for THREAD_EVENT_WAIT
+   * when we're not interested in synchronization.
+   */
+  td->mutex_dummy = THREAD_MUTEX_CREATE();
+  if(td->mutex_dummy == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SET_ERRNO(EAGAIN);
+    return FALSE;
+  }
+
   /* Create the event that the thread uses to inform us that it's
    * done resolving. Do not signal it.
    */
-  td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
+  td->event_resolved = THREAD_EVENT_CREATE();
   if(td->event_resolved == NULL) {
     Curl_destroy_thread_data(&conn->async);
     SET_ERRNO(EAGAIN);
@@ -441,15 +664,27 @@
   /* Create the mutex used to serialize access to event_terminated
    * between us and resolver thread.
    */
-  td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
+  td->mutex_terminate = THREAD_MUTEX_CREATE();
   if(td->mutex_terminate == NULL) {
     Curl_destroy_thread_data(&conn->async);
     SET_ERRNO(EAGAIN);
     return FALSE;
   }
+  td->mutex_resolved = THREAD_MUTEX_CREATE();
+  if(td->mutex_resolved == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SET_ERRNO(EAGAIN);
+    return FALSE;
+  }
+  td->mutex_thread_started = THREAD_MUTEX_CREATE();
+  if(td->mutex_thread_started == NULL) {
+    Curl_destroy_thread_data(&conn->async);
+    SET_ERRNO(EAGAIN);
+    return FALSE;
+  }
   /* Create the event used to signal thread that it should terminate.
    */
-  td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
+  td->event_terminate = THREAD_EVENT_CREATE();
   if(td->event_terminate == NULL) {
     Curl_destroy_thread_data(&conn->async);
     SET_ERRNO(EAGAIN);
@@ -457,21 +692,18 @@
   }
   /* Create the event used by thread to inform it has initialized its own data.
    */
-  td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
+  td->event_thread_started = THREAD_EVENT_CREATE();
   if(td->event_thread_started == NULL) {
     Curl_destroy_thread_data(&conn->async);
     SET_ERRNO(EAGAIN);
     return FALSE;
   }
 
-#ifdef _WIN32_WCE
-  td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
-                                         (LPTHREAD_START_ROUTINE) THREAD_FUNC,
-                                         conn, 0, &td->thread_id);
-#else
-  td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
-                                           conn, 0, &td->thread_id);
-#endif
+  /*
+   * Note: The return value type is mangled here. pthreads expects a void*
+   * return, but we give an unsigned. XXX
+   */
+  td->thread_hnd = THREAD_CREATE(THREAD_FUNC, conn);
 
 #ifdef CURLRES_IPV6
   DEBUGASSERT(hints);
@@ -487,18 +719,12 @@
      Curl_destroy_thread_data(&conn->async);
      return FALSE;
   }
-  /* Waiting until the thread will initialize its data or it will exit due errors.
-   */
-  thread_and_event[0] = td->thread_hnd;
-  thread_and_event[1] = td->event_thread_started;
-  if(WaitForMultipleObjects(sizeof(thread_and_event) /
-                             sizeof(thread_and_event[0]),
-                             (const HANDLE*)thread_and_event, FALSE,
-                             INFINITE) == WAIT_FAILED) {
-    /* The resolver thread has been created,
-     * most probably it works now - ignoring this "minor" error
-     */
+
+  /* XXX: Do we actually need this? */
+  while (td->thread_started == 0) {
+    THREAD_EVENT_WAIT(td->event_thread_started, td->mutex_thread_started);
   }
+
   /* This socket is only to keep Curl_resolv_fdset() and select() happy;
    * should never become signalled for read/write since it's unbound but
    * Windows needs atleast 1 socket in select().
@@ -521,8 +747,9 @@
 {
   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
   struct SessionHandle *data = conn->data;
+  struct timeval start, now;
   long   timeout;
-  DWORD  status;
+  int    status;
   CURLcode rc;
 
   DEBUGASSERT(conn && td);
@@ -534,27 +761,59 @@
     conn->data->set.timeout ? conn->data->set.timeout :
     CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
 
-  /* wait for the thread to resolve the name */
-  status = WaitForSingleObject(td->event_resolved, timeout);
+  /* Figure out when we started ... */
+  gettimeofday(&start, NULL);
+
+  /*
+   * wait for the thread to resolve the name.
+   * The thread is responsible for setting conn->async.done whenever it
+   * finishes, for better or worse.
+   */
+  while (!conn->async.done && timeout > 0) {
+     status = THREAD_EVENT_TRYWAIT(td->event_resolved,
+                                   td->mutex_resolved,
+                                   timeout);
+
+     /* It's possible that we got a spurious wakeup. Adjust the timeout. */
+     gettimeofday(&now, NULL);
+     timeout -= ((now.tv_sec - start.tv_sec) * 1000) +
+                ((now.tv_usec - start.tv_usec) / 1000);
+  }
 
   /* mark that we are now done waiting */
-  ReleaseMutex(td->mutex_waiting);
+  THREAD_MUTEX_UNLOCK(td->mutex_waiting);
 
   /* close our handle to the mutex, no point in hanging on to it */
-  CloseHandle(td->mutex_waiting);
+  THREAD_MUTEX_DESTROY(td->mutex_waiting);
   td->mutex_waiting = NULL;
 
   /* close the event handle, it's useless now */
-  CloseHandle(td->event_resolved);
+  THREAD_EVENT_DESTROY(td->event_resolved);
   td->event_resolved = NULL;
 
   /* has the resolver thread succeeded in resolving our query ? */
-  if(status == WAIT_OBJECT_0) {
-    /* wait for the thread to exit, it's in the callback sequence */
+  if(status) {
+    /*
+     * The only part of the code not explicitly abstracted by macros,
+     * because there is no standardized pthread_timedjoin function. With
+     * pthreads, just join it and cross your fingers.
+     */
+#ifndef _WIN32
+    thread_status thr_status = 0;
+    if (pthread_join(td->thread_hnd, (void**)&thr_status) == 0) {
+      SET_SOCKERRNO(conn->async.status);
+      td->status = thr_status;
+    } else {
+      /* Something went wrong, let's just abandon ship. */
+      conn->async.done = TRUE;
+      td->status = (thread_status)-1;
+    }
+#else
+    /* The thread should exit within 5 seconds, but if not, just nuke it. */
     if(WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
       TerminateThread(td->thread_hnd, 0);
       conn->async.done = TRUE;
-      td->thread_status = (DWORD)-1;
+      td->status = (thread_status)-1;
     }
     else {
       /* Thread finished before timeout; propagate Winsock error to this
@@ -562,12 +821,13 @@
        * Curl_addrinfo4/6_callback().
        */
       SET_SOCKERRNO(conn->async.status);
-      GetExitCodeThread(td->thread_hnd, &td->thread_status);
+      GetExitCodeThread(td->thread_hnd, &td->status);
     }
+#endif
   }
   else {
     conn->async.done = TRUE;
-    td->thread_status = (DWORD)-1;
+    td->status = (thread_status)-1;
   }
 
   if(entry)
@@ -577,7 +837,7 @@
 
   if(!conn->async.dns) {
     /* a name was not resolved */
-    if(td->thread_status == CURLE_OUT_OF_MEMORY) {
+    if(td->status == CURLE_OUT_OF_MEMORY) {
       rc = CURLE_OUT_OF_MEMORY;
       failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
     }
@@ -593,7 +853,7 @@
         rc = CURLE_COULDNT_RESOLVE_HOST;
       }
     }
-    else if(td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
+    else if(td->status == (thread_status)-1 || conn->async.status == NO_DATA) {
       failf(data, "Resolving host timed out: %s", conn->host.name);
       rc = CURLE_OPERATION_TIMEDOUT;
     }
@@ -618,9 +878,18 @@
                           struct Curl_dns_entry **entry)
 {
   struct SessionHandle *data = conn->data;
+  const struct thread_data *td =
+    (const struct thread_data *) conn->async.os_specific;
 
   *entry = NULL;
 
+  /*
+   * If we are calling this, we need to unlock the mutex since we
+   * aren't blocking on the event_resolved signal. The thread will
+   * lock it in order to ensure it has exclusive access to the conn.
+   */
+  THREAD_MUTEX_UNLOCK(td->mutex_resolved);
+
   if(conn->async.done) {
     /* we're done */
     Curl_destroy_thread_data(&conn->async);
@@ -748,7 +1017,7 @@
 #if 0 /* removed nov 8 2005 before 7.15.1 */
   hints.ai_flags = AI_CANONNAME;
 #endif
-  itoa(port, sbuf, 10);
+  snprintf(sbuf, sizeof(sbuf), "%d", port);
 
   /* fire up a new resolver thread! */
   if(init_resolve_thread(conn, hostname, port, &hints)) {
Index: lib/setup.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/setup.h,v
retrieving revision 1.167
diff -u -r1.167 setup.h
--- lib/setup.h	14 Jul 2009 13:25:14 -0000	1.167
+++ lib/setup.h	27 Aug 2009 18:21:04 -0000
@@ -390,7 +390,26 @@
 
 #endif /* WIN32 */
 
+#if !defined(WIN32) && defined(HAVE_PTHREAD) && \
+    !defined(USE_ARES) && !defined(DISABLE_THREADED_RESOLVE)
+/*
+ * We prefer to use a threaded getaddrinfo() on Mac because that is the
+ * most reliable source of name resolution. Using resolv.conf and our
+ * usual tricks means that the DNS view of the world for c-ares does not
+ * match the rest of the system.
+ *
+ * This is available on POSIX at large as well, to provide an alternative
+ * to c-ares (in case you want asynch resolve with fewer library dependencies.)
+ */
+#ifdef ENABLE_IPV6
+#define USE_THREADING_GETADDRINFO
+#else
+#define USE_THREADING_GETHOSTBYNAME
+#endif
+#endif
+
 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
+    !defined(DISABLE_THREADED_RESOLVE) && \
     !defined(__LCC__)  /* lcc-win32 doesn't have _beginthreadex() */
 #ifdef ENABLE_IPV6
 #define USE_THREADING_GETADDRINFO
--- /dev/null	2009-06-18 03:46:17.502891380 -0700
+++ m4/acx_pthread.m4	2008-05-20 11:43:25.000000000 -0700
@@ -0,0 +1,256 @@
+dnl
+dnl NOTE: This file was modified for Xerces-C++. See the comments
+dnl starting with 'XERCES' for more information.
+dnl
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl        LIBS="$PTHREAD_LIBS $LIBS"
+dnl        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl        CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+# XERCES: On GNU/Linux with gcc both -pthread and -lpthread are valid.
+# However, libtool links libraries with -nostdlib which results in 
+# -pthread being stripped from the linker command line. To resolve
+# this we move pthread from after -mthreads to after pthreads.
+#
+acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+	
+        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+        ;;		
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+		pthread-config)
+		AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+		if test x"$acx_pthread_config" = xno; then continue; fi
+		PTHREAD_CFLAGS="`pthread-config --cflags`"
+		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+		;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+	
+	# XERCES: Add tests for pthread_mutexattr_init and 
+	# pthread_mutexattr_destroy.
+	#
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0);
+		     pthread_mutexattr_init(0); pthread_mutexattr_destroy(0);],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+	AC_MSG_CHECKING([for joinable pthread attribute])
+	attr_name=unknown
+	for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+	    AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+                        [attr_name=$attr; break])
+	done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+	if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+	fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
