diff --git a/configure.ac b/configure.ac
index 6cb81e4..2dbcd58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -127,7 +127,7 @@ dnl initialize all the info variables
    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)"
@@ -2295,7 +2295,7 @@ AC_HELP_STRING([--disable-ares],[Disable c-ares for name lookups]),
        dnl substitute HAVE_ARES for curl-config and similar
        HAVE_ARES="1"
        AC_SUBST(HAVE_ARES)
-       curl_ares_msg="enabled"
+       curl_asynch_msg="yes     (c-ares)"
 
        LIBS="-lcares $LIBS"
 
@@ -2350,6 +2350,54 @@ AC_HELP_STRING([--disable-ares],[Disable c-ares for name lookups]),
 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 **********************************************************************
+THREADED_RESOLVE_CHECK_PASS=no
+if test x$HAVE_ARES != x1; then
+   dnl Check for threading libraries and headers.
+   if test x$ac_cv_native_windows = xyes; then
+      # if you have a working Win32 SDK, you have threads.
+      curl_asynch_msg="yes     (Windows threads)"
+      THREADED_RESOLVE_CHECK_PASS=yes
+   else
+      # Test for POSIX threads
+      ACX_PTHREAD
+
+      if test x$ac_cv_func_getaddrinfo_threadsafe = xyes; then
+         have_threadsafe_resolver=yes
+      fi
+
+      if test x$have_threadsafe_resolver = xyes && \
+         test x$acx_pthread_ok = xyes; then
+         curl_asynch_msg="yes     (pthreads)"
+         THREADED_RESOLVE_CHECK_PASS=yes
+      fi
+   fi
+fi
+
+
+USE_THREADED_RESOLVE=no
+AC_MSG_CHECKING([whether to enable threaded resolve])
+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)
+       ;;
+  *)   if test x$THREADED_RESOLVE_CHECK_PASS != xyes; then
+          AC_MSG_ERROR([Threaded resolver enabled but unclear if platform is threadsafe])
+       fi
+       AC_MSG_RESULT(yes)
+       AC_DEFINE(USE_THREADED_RESOLVE, 1, [use threaded resolver])
+       USE_THREADED_RESOLVE=yes
+       ;;
+  esac ],
+       AC_MSG_RESULT(no)
+)
+
+
 dnl ************************************************************
 dnl disable verbose text strings
 dnl
@@ -2682,7 +2730,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
   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}
diff --git a/lib/config-win32.h b/lib/config-win32.h
index f1276d3..09f4055 100644
--- a/lib/config-win32.h
+++ b/lib/config-win32.h
@@ -552,4 +552,12 @@
 #  define ENABLE_IPV6 1
 #endif
 
+/* Don't use getaddrinfo() on Windows unless we have to - maximum
+   compatibility with Win2k */
+#if defined(HAVE_GETADDRINFO) && !defined(ENABLE_IPV6)
+#undef HAVE_GETADDRINFO
+#undef HAVE_GETNAMEINFO
+#undef HAVE_FREEADDRINFO
+#endif
+
 #endif /* __LIB_CONFIG_WIN32_H */
diff --git a/lib/hostip.h b/lib/hostip.h
index 4dfac64..f7cf89f 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -165,6 +165,9 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
                        int line, const char *source);
 #endif
 
+/* Synchronous IPv4 resolve - tries hard to use a thread-safe API */
+Curl_addrinfo * Curl_ipv4_resolve(const char * hostname, int port);
+
 /*
  * Curl_addrinfo_callback() is used when we build with any asynch specialty.
  * Handles end of async request processing. Inserts ai into hostcache when
diff --git a/lib/hostip4.c b/lib/hostip4.c
index 56e43e9..5a62e98 100644
--- a/lib/hostip4.c
+++ b/lib/hostip4.c
@@ -86,11 +86,10 @@ bool Curl_ipvalid(struct SessionHandle *data)
 
   return TRUE; /* OK, proceed */
 }
-
-#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
+#endif /* CURLRES_IPV4 */
 
 /*
- * Curl_getaddrinfo() - the ipv4 synchronous version.
+ * Curl_ipv4_resolve() - the ipv4 synchronous version.
  *
  * The original code to this function was from the Dancer source code, written
  * by Bjorn Reese, it has since been patched and modified considerably.
@@ -105,10 +104,8 @@ bool Curl_ipvalid(struct SessionHandle *data)
  * flavours have thread-safe versions of the plain gethostbyname() etc.
  *
  */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
-                                const char *hostname,
-                                int port,
-                                int *waitp)
+Curl_addrinfo *Curl_ipv4_resolve(const char *hostname,
+                                int port)
 {
 #if defined(HAVE_GETHOSTBYNAME_R_3)
   int res;
@@ -118,17 +115,28 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   struct in_addr in;
   struct hostent *buf = NULL;
 
-#ifdef CURL_DISABLE_VERBOSE_STRINGS
-  (void)conn;
-#endif
-
-  *waitp = 0; /* don't wait, we act synchronously */
-
   if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
     /* This is a dotted IP address 123.123.123.123-style */
     return Curl_ip2addr(AF_INET, &in, hostname, port);
 
-#if defined(HAVE_GETHOSTBYNAME_R)
+/* !defined(_WIN32) to maximize Windows 2000 comaptibility */
+#if defined(HAVE_GETADDRINFO_THREADSAFE) && !defined(_WIN32)
+  else { 
+    struct addrinfo hints;
+    char sbuf[NI_MAXSERV];
+    char *sbufptr = NULL;
+    int error;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    if (port) {
+      snprintf(sbuf, sizeof(sbuf), "%d", port);
+      sbufptr = sbuf;
+    }
+    hints.ai_flags = AI_CANONNAME;
+    error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
+#elif defined(HAVE_GETHOSTBYNAME_R)
   /*
    * gethostbyname_r() is the preferred resolve function for many platforms.
    * Since there are three different versions of it, the following code is
@@ -260,8 +268,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
     }
     else
 #endif /* HAVE_GETHOSTBYNAME_R_3 */
-      {
-      infof(conn->data, "gethostbyname_r(2) failed for %s\n", hostname);
+    {
       h = NULL; /* set return code to NULL */
       free(buf);
     }
@@ -276,8 +283,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 #else
     h = gethostbyname(hostname);
 #endif
-    if(!h)
-      infof(conn->data, "gethostbyname(2) failed for %s\n", hostname);
 #endif /*HAVE_GETHOSTBYNAME_R */
   }
 
@@ -291,6 +296,20 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   return ai;
 }
 
-#endif /* CURLRES_SYNCH */
-#endif /* CURLRES_IPV4 */
+#if defined(CURLRES_SYNCH) && defined(CURLRES_IPV4)
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  Curl_addrinfo *ai = Curl_ipv4_resolve(hostname, port);
 
+  (void)conn;
+  *waitp = 0;
+
+  if(!ai)
+    infof(conn->data, "Curl_ipv4_resolve failed for %s\n", hostname);
+
+  return ai;  
+}
+#endif
diff --git a/lib/hostip6.c b/lib/hostip6.c
index 5fa28ff..165289e 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -126,7 +126,7 @@ bool Curl_ipvalid(struct SessionHandle *data)
   return TRUE;
 }
 
-#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES)
+#if !defined(CURLRES_ASYNCH)
 
 #ifdef DEBUG_ADDRINFO
 static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
@@ -234,6 +234,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
   return res;
 }
-#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */
+#endif /* CURLRES_ASYNCH */
 #endif /* CURLRES_IPV6 */
 
diff --git a/lib/hostthre.c b/lib/hostthre.c
index 8eb2c9f..5947340 100644
--- a/lib/hostthre.c
+++ b/lib/hostthre.c
@@ -50,6 +50,10 @@
 #include <stdlib.h>
 #endif
 
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
 #ifdef HAVE_PROCESS_H
 #include <process.h>
 #endif
@@ -83,7 +87,7 @@
 #endif
 
 /***********************************************************************
- * Only for Windows threaded name resolves builds
+ * Only for Windows and Mac threaded name resolves builds
  **********************************************************************/
 #ifdef CURLRES_THREADED
 
@@ -92,250 +96,298 @@ static bool init_resolve_thread(struct connectdata *conn,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints);
 
-#ifdef CURLRES_IPV4
-  #define THREAD_FUNC  gethostbyname_thread
-  #define THREAD_NAME "gethostbyname_thread"
+/* Here's where we abstract everything out. */
+#ifdef _WIN32
+typedef HANDLE curl_thread_t;
+typedef CRITICAL_SECTION curl_mutex_t;
+
+static curl_thread_t curl_thread_t_null = NULL;
+
+#define CURL_STDCALL __stdcall
+
+static curl_thread_t curl_thread_create(unsigned int (__stdcall *func) (void*), void *arg)
+{
+#ifdef _WIN32_WCE
+  return CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
-  #define THREAD_FUNC  getaddrinfo_thread
-  #define THREAD_NAME "getaddrinfo_thread"
+  return (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
 #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 */
-#ifdef CURLRES_IPV6
-  struct addrinfo hints;
-#endif
+static void curl_thread_destroy(curl_thread_t hnd)
+{
+  CloseHandle(hnd);
+}
+
+
+static int curl_thread_join(curl_thread_t * hnd)
+{
+  int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
+
+  curl_thread_destroy(*hnd);
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+static void curl_mutex_init(curl_mutex_t * mtx)
+{
+  InitializeCriticalSection(mtx);
+}
+
+static void curl_mutex_acquire(curl_mutex_t * mtx)
+{
+  EnterCriticalSection(mtx);
+}
+
+static void curl_mutex_release(curl_mutex_t * mtx)
+{
+  LeaveCriticalSection(mtx);
+}
+
+static void curl_mutex_destroy(curl_mutex_t * mtx)
+{
+  DeleteCriticalSection(mtx);
+}
+
+#else
+typedef pthread_t curl_thread_t;
+typedef pthread_mutex_t curl_mutex_t;
+
+struct curl_actual_call {
+  unsigned int (*func)(void *);
+  void *arg;  
 };
 
+static void * curl_thread_create_thunk(void *arg)
+{
+  struct curl_actual_call * ac = arg;
+  unsigned int (*func)(void *) = ac->func;
+  void *real_arg = ac->arg;
+
+  free(ac);
+
+  (*func)(real_arg);
+
+  return 0;
+}
+
+/* XXX - can a pthread_t ever be null */
+static curl_thread_t curl_thread_t_null = 0;
+
+#define CURL_STDCALL
+
+static curl_thread_t curl_thread_create(unsigned int (*func) (void*), void *arg)
+{
+  curl_thread_t t;
+  struct curl_actual_call * ac = malloc(sizeof(struct curl_actual_call));
+  if(!ac)
+    return curl_thread_t_null;
+
+  ac->func = func;
+  ac->arg = arg;
+
+  if (pthread_create(&t, NULL, curl_thread_create_thunk, ac) != 0) {
+    free(ac);
+    return curl_thread_t_null;
+  }
+
+  return t;
+}
+
+static int curl_thread_join(curl_thread_t *hnd)
+{
+  int ret = (pthread_join(*hnd, NULL) == 0);
+
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+static void curl_thread_destroy(curl_thread_t hnd)
+{
+  if (hnd != curl_thread_t_null) {
+    pthread_detach(hnd);
+  } 
+}
+
+
+static void curl_mutex_init(curl_mutex_t * mtx)
+{
+  pthread_mutex_init(mtx, NULL);
+}
+
+static void curl_mutex_acquire(curl_mutex_t * mtx)
+{
+  pthread_mutex_lock(mtx);
+}
+
+static void curl_mutex_release(curl_mutex_t * mtx)
+{
+  pthread_mutex_unlock(mtx);
+}
+
+static void curl_mutex_destroy(curl_mutex_t * mtx)
+{
+  pthread_mutex_destroy(mtx);
+}
+
+#endif
+
 /* 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 */
+  curl_mutex_t * mtx;
+  int done;
+
   char * hostname;        /* hostname to resolve, Curl_async.hostname
                              duplicate */
+  int port;
+  int sock_error;
+  Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+};
+
+struct thread_data {
+  curl_thread_t thread_hnd;
+  curl_socket_t dummy_sock;
+  unsigned int poll_interval;
+  int interval_end;
+  struct thread_sync_data tsd;
 };
 
+static struct thread_sync_data * conn_thread_sync_data(struct connectdata *conn)
+{
+  return &(((struct thread_data *)conn->async.os_specific)->tsd);
+}
+
+#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
+
 /* Destroy resolver thread synchronization data */
 static
 void destroy_thread_sync_data(struct thread_sync_data * tsd)
 {
+  if (tsd->mtx) {
+    curl_mutex_destroy(tsd->mtx);
+    free(tsd->mtx);
+  }
+
   if(tsd->hostname)
     free(tsd->hostname);
-  if(tsd->event_terminate)
-    CloseHandle(tsd->event_terminate);
-  if(tsd->mutex_terminate)
-    CloseHandle(tsd->mutex_terminate);
-  if(tsd->mutex_waiting)
-    CloseHandle(tsd->mutex_waiting);
+  
+  if (tsd->res)
+    Curl_freeaddrinfo(tsd->res);
+
   memset(tsd,0,sizeof(*tsd));
 }
 
 /* Initialize resolver thread synchronization data */
 static
-BOOL init_thread_sync_data(struct thread_data * td,
+int init_thread_sync_data(struct thread_sync_data * tsd,
                            const char * hostname,
-                           struct thread_sync_data * tsd)
+			   int port,
+			   const struct addrinfo *hints)
 {
-  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)) {
-    /* 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)) {
-    /* 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)) {
-    /* failed to duplicate the event, no point in continuing */
-    destroy_thread_sync_data(tsd);
-    return FALSE;
-  }
+
+  tsd->port = port;
+#ifdef CURLRES_IPV6
+  DEBUGASSERT(hints);
+  tsd->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  tsd->mtx = malloc(sizeof(curl_mutex_t));
+  if (tsd->mtx == NULL) goto err_exit;
+
+  curl_mutex_init(tsd->mtx);
+
+  tsd->sock_error = CURL_ASYNC_SUCCESS;
+
   /* Copying hostname string because original can be destroyed by parent
    * thread during gethostbyname execution.
    */
   tsd->hostname = strdup(hostname);
-  if(!tsd->hostname) {
-    /* Memory allocation failed */
-    destroy_thread_sync_data(tsd);
-    return FALSE;
-  }
-  return TRUE;
-}
-
-/* acquire resolver thread synchronization */
-static
-BOOL 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 */
+  if (!tsd->hostname) goto err_exit;
 
-    /* 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;
-      }
-    }
-  }
-  return FALSE;
-}
+  return 1;
 
-/* release resolver thread synchronization */
-static
-void release_thread_sync(struct thread_sync_data * tsd)
-{
-  ReleaseMutex(tsd->mutex_terminate);
+ err_exit:
+  /* Memory allocation failed */
+  destroy_thread_sync_data(tsd);
+  return 0;
 }
 
-#if defined(CURLRES_IPV4)
 /*
- * gethostbyname_thread() resolves a name, calls the Curl_addrinfo_callback
- * and then exits.
- *
- * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
- * it.
+ * gethostbyname_thread() resolves a name and then exits.
  */
-static unsigned __stdcall gethostbyname_thread (void *arg)
+static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
 {
-  struct connectdata *conn = (struct connectdata*) arg;
-  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
-  struct hostent *he;
-  int    rc = 0;
-
-  /* Duplicate the passed mutex and event handles.
-   * 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 };
-
-  if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
-    /* thread synchronization data initialization failed */
-    return (unsigned)-1;
-  }
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
 
-  conn->async.status = NO_DATA;  /* pending status */
-  SET_SOCKERRNO(conn->async.status);
+  tsd->res = Curl_ipv4_resolve(tsd->hostname, tsd->port);
 
-  /* Signaling that we have initialized all copies of data and handles we
-     need */
-  SetEvent(td->event_thread_started);
+  if (!tsd->res) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
+  } 
 
-  he = gethostbyname (tsd.hostname);
+  curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  curl_mutex_release(tsd->mtx);
 
-  /* is parent thread waiting for us and are we able to access conn members? */
-  if(acquire_thread_sync(&tsd)) {
-    Curl_addrinfo *ai = Curl_he2ai(he, conn->async.port);
+  return 0;
+}
 
-    /* Mark that we have obtained the information, and that we are calling
-     * back with it. */
-    SetEvent(td->event_resolved);
-    if(ai) {
-      rc = Curl_addrinfo_callback(conn, CURL_ASYNC_SUCCESS, ai);
-    }
-    else {
-      rc = Curl_addrinfo_callback(conn, SOCKERRNO, NULL);
-    }
-    release_thread_sync(&tsd);
-  }
+static int getaddrinfo_complete(struct connectdata *conn)
+{
+  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+  int rc;
 
-  /* clean up */
-  destroy_thread_sync_data(&tsd);
+  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res); 
+  /* The tsd->res structure has been copied to async.dns and perhaps the DNS cache.
+     Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+   */
+  tsd->res = NULL;
 
-  return (rc);
-  /* An implicit _endthreadex() here */
+  return rc;
 }
 
-#elif defined(CURLRES_IPV6)
+
+#if defined(HAVE_GETADDRINFO)
 
 /*
- * getaddrinfo_thread() resolves a name, calls Curl_addrinfo_callback and then
- * exits.
+ * getaddrinfo_thread() resolves a name and then exits.
  *
  * 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 int CURL_STDCALL getaddrinfo_thread (void *arg)
 {
-  struct connectdata *conn = (struct connectdata*) arg;
-  struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
-  Curl_addrinfo      *res;
+  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
   char   service [NI_MAXSERV];
-  int    rc;
-  struct addrinfo hints = td->hints;
-
-  /* Duplicate the passed mutex handle.
-   * 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 };
-
-  if(!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
-    /* thread synchronization data initialization failed */
-    return -1;
-  }
-
-  itoa(conn->async.port, service, 10);
+  int rc;
 
-  conn->async.status = NO_DATA;  /* pending status */
-  SET_SOCKERRNO(conn->async.status);
+  snprintf(service, sizeof(service), "%d", tsd->port);
 
-  /* Signaling that we have initialized all copies of data and handles we
-     need */
-  SetEvent(td->event_thread_started);
+  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
 
-  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);
-
-    if(rc == 0) {
-      rc = Curl_addrinfo_callback(conn, CURL_ASYNC_SUCCESS, res);
-    }
-    else {
-      rc = Curl_addrinfo_callback(conn, SOCKERRNO, NULL);
-    }
-    release_thread_sync(&tsd);
+  if (rc != 0) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
   }
 
-  /* clean up */
-  destroy_thread_sync_data(&tsd);
+  curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  curl_mutex_release(tsd->mtx);
 
-  return (rc);
-  /* An implicit _endthreadex() here */
+  return 0;
 }
+
 #endif
 
 /*
@@ -349,39 +401,15 @@ void Curl_destroy_thread_data (struct Curl_async *async)
 
   if(async->os_specific) {
     struct thread_data *td = (struct thread_data*) async->os_specific;
-    curl_socket_t sock = td->dummy_sock;
-
-    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);
-      }
-      else {
-        /* Something went wrong - just ignoring it */
-      }
-    }
-
-    if(td->mutex_terminate)
-      CloseHandle(td->mutex_terminate);
-    if(td->event_terminate)
-      CloseHandle(td->event_terminate);
-    if(td->event_thread_started)
-      CloseHandle(td->event_thread_started);
-
-    if(sock != CURL_SOCKET_BAD)
-      sclose(sock);
 
-    /* destroy the synchronization objects */
-    if(td->mutex_waiting)
-      CloseHandle(td->mutex_waiting);
-    td->mutex_waiting = NULL;
-    if(td->event_resolved)
-      CloseHandle(td->event_resolved);
-
-    if(td->thread_hnd)
-      CloseHandle(td->thread_hnd);
+    if (td->dummy_sock != CURL_SOCKET_BAD)
+      sclose(td->dummy_sock);
 
+    if (td->thread_hnd != curl_thread_t_null)
+      curl_thread_join(&td->thread_hnd);
+ 
+    destroy_thread_sync_data(&td->tsd);
+    
     free(async->os_specific);
   }
   async->hostname = NULL;
@@ -399,114 +427,58 @@ static bool init_resolve_thread (struct connectdata *conn,
                                  const struct addrinfo *hints)
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
-  HANDLE thread_and_event[2] = {0};
-
-  if(!td) {
-    SET_ERRNO(ENOMEM);
-    return FALSE;
-  }
+  int err = ENOMEM;
 
-  Curl_safefree(conn->async.hostname);
-  conn->async.hostname = strdup(hostname);
-  if(!conn->async.hostname) {
-    free(td);
-    SET_ERRNO(ENOMEM);
-    return FALSE;
-  }
+  conn->async.os_specific = (void*) td;
+  if(!td) 
+    goto err_exit;
 
   conn->async.port = port;
   conn->async.done = FALSE;
   conn->async.status = 0;
   conn->async.dns = NULL;
-  conn->async.os_specific = (void*) td;
   td->dummy_sock = CURL_SOCKET_BAD;
+  td->thread_hnd = curl_thread_t_null;
 
-  /* 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);
-  if(td->mutex_waiting == NULL) {
-    Curl_destroy_thread_data(&conn->async);
-    SET_ERRNO(EAGAIN);
-    return FALSE;
-  }
+  if (!init_thread_sync_data(&td->tsd, hostname, port, hints)) 
+    goto err_exit;
 
-  /* 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);
-  if(td->event_resolved == NULL) {
-    Curl_destroy_thread_data(&conn->async);
-    SET_ERRNO(EAGAIN);
-    return FALSE;
-  }
-  /* Create the mutex used to serialize access to event_terminated
-   * between us and resolver thread.
-   */
-  td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
-  if(td->mutex_terminate == 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);
-  if(td->event_terminate == NULL) {
-    Curl_destroy_thread_data(&conn->async);
-    SET_ERRNO(EAGAIN);
-    return FALSE;
-  }
-  /* Create the event used by thread to inform it has initialized its own data.
-   */
-  td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
-  if(td->event_thread_started == NULL) {
-    Curl_destroy_thread_data(&conn->async);
-    SET_ERRNO(EAGAIN);
-    return FALSE;
-  }
+  Curl_safefree(conn->async.hostname);
+  conn->async.hostname = strdup(hostname);
+  if(!conn->async.hostname)
+    goto err_exit;
 
-#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);
+#ifdef _WIN32
+  /* This socket is only to keep Curl_resolv_fdset() and select() happy;
+   * should never become signalled for read since it's unbound but
+   * Windows needs at least 1 socket in select().
+   */
+  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+  if (td->dummy_sock == CURL_SOCKET_BAD)
+    goto err_exit;
 #endif
 
-#ifdef CURLRES_IPV6
-  DEBUGASSERT(hints);
-  td->hints = *hints;
+#ifdef HAVE_GETADDRINFO
+  td->thread_hnd = curl_thread_create(getaddrinfo_thread, &td->tsd);
 #else
-  (void) hints;
+  td->thread_hnd = curl_thread_create(gethostbyname_thread, &td->tsd);
 #endif
 
   if(!td->thread_hnd) {
 #ifndef _WIN32_WCE
-     SET_ERRNO(errno);
+    err = errno;
 #endif
-     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
-     */
+    goto err_exit;
   }
-  /* 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().
-   */
-  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+
   return TRUE;
+
+ err_exit:
+  Curl_destroy_thread_data(&conn->async);
+
+  SET_ERRNO(err);
+
+  return FALSE;
 }
 
 
@@ -523,84 +495,33 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
 {
   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
   struct SessionHandle *data = conn->data;
-  long   timeout;
-  DWORD  status;
   CURLcode rc;
 
   DEBUGASSERT(conn && td);
 
-  /* now, see if there's a connect timeout or a regular timeout to
-     use instead of the default one */
-  timeout =
-    conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
-    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);
-
-  /* mark that we are now done waiting */
-  ReleaseMutex(td->mutex_waiting);
-
-  /* close our handle to the mutex, no point in hanging on to it */
-  CloseHandle(td->mutex_waiting);
-  td->mutex_waiting = NULL;
-
-  /* close the event handle, it's useless now */
-  CloseHandle(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(WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
-      TerminateThread(td->thread_hnd, 0);
-      conn->async.done = TRUE;
-      td->thread_status = (DWORD)-1;
-    }
-    else {
-      /* Thread finished before timeout; propagate Winsock error to this
-       * thread.  'conn->async.done = TRUE' is set in
-       * Curl_addrinfo4/6_callback().
-       */
-      SET_SOCKERRNO(conn->async.status);
-      GetExitCodeThread(td->thread_hnd, &td->thread_status);
-    }
-  }
-  else {
-    conn->async.done = TRUE;
-    td->thread_status = (DWORD)-1;
+  if (curl_thread_join(&td->thread_hnd)) {
+    rc = getaddrinfo_complete(conn);
+  } else {
+    DEBUGASSERT(0);    
   }
 
+  conn->async.done = TRUE;
+    
   if(entry)
     *entry = conn->async.dns;
 
-  rc = CURLE_OK;
-
   if(!conn->async.dns) {
     /* a name was not resolved */
-    if(td->thread_status == CURLE_OUT_OF_MEMORY) {
-      rc = CURLE_OUT_OF_MEMORY;
-      failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
-    }
-    else if(conn->async.done) {
-      if(conn->bits.httpproxy) {
-        failf(data, "Could not resolve proxy: %s; %s",
-              conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
-        rc = CURLE_COULDNT_RESOLVE_PROXY;
-      }
-      else {
-        failf(data, "Could not resolve host: %s; %s",
-              conn->host.name, Curl_strerror(conn, conn->async.status));
-        rc = CURLE_COULDNT_RESOLVE_HOST;
-      }
-    }
-    else if(td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
-      failf(data, "Resolving host timed out: %s", conn->host.name);
-      rc = CURLE_OPERATION_TIMEDOUT;
+    if (conn->bits.httpproxy) {
+      failf(data, "Could not resolve proxy: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_PROXY;
+    } else {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_HOST;
     }
-    else
-      rc = CURLE_OPERATION_TIMEDOUT;
   }
 
   Curl_destroy_thread_data(&conn->async);
@@ -620,19 +541,57 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
                           struct Curl_dns_entry **entry)
 {
   struct SessionHandle *data = conn->data;
-
+  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  int done = 0;
+ 
   *entry = NULL;
 
-  if(conn->async.done) {
-    /* we're done */
+  if (!td) {
+    DEBUGASSERT(td);
+    return CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  curl_mutex_acquire(td->tsd.mtx);
+  done = td->tsd.done;
+  curl_mutex_release(td->tsd.mtx);
+
+  if (done) { 
+    getaddrinfo_complete(conn);
+    if (td->poll_interval != 0)
+        Curl_expire(conn->data, 0);
     Curl_destroy_thread_data(&conn->async);
+
     if(!conn->async.dns) {
       failf(data, "Could not resolve host: %s; %s",
             conn->host.name, Curl_strerror(conn, conn->async.status));
       return CURLE_COULDNT_RESOLVE_HOST;
     }
     *entry = conn->async.dns;
+  } else {
+    /* poll for name lookup done with exponential backoff up to 250ms */
+    int elapsed;
+
+    elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+    if (elapsed < 0) {
+      elapsed = 0;
+    }
+
+    if (td->poll_interval == 0) {
+      /* Start at 1ms poll interval */
+      td->poll_interval = 1;
+    } else if (elapsed >= td->interval_end) {
+      /* Back-off exponentially if last interval expired  */
+      td->poll_interval *= 2;
+    }
+
+    if (td->poll_interval > 250)
+      td->poll_interval = 250;
+
+    td->interval_end = elapsed + td->poll_interval;
+
+    Curl_expire(conn->data, td->poll_interval);
   }
+
   return CURLE_OK;
 }
 
@@ -645,18 +604,18 @@ int Curl_resolv_getsock(struct connectdata *conn,
 
   if(td && td->dummy_sock != CURL_SOCKET_BAD) {
     if(numsocks) {
-      /* return one socket waiting for writable, even though this is just
+      /* return one socket waiting for readable, even though this is just
          a dummy */
       socks[0] = td->dummy_sock;
-      return GETSOCK_WRITESOCK(0);
+      return GETSOCK_READSOCK(0);
     }
   }
   return 0;
 }
 
-#ifdef CURLRES_IPV4
+#ifndef HAVE_GETADDRINFO
 /*
- * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
+ * Curl_getaddrinfo() - for platforms w/o getaddrinfo (inc. W2k)
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
                                 const char *hostname,
@@ -680,22 +639,13 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   }
 
   /* fall-back to blocking version */
-  infof(data, "init_resolve_thread() failed for %s; %s\n",
-        hostname, Curl_strerror(conn, ERRNO));
-
-  h = gethostbyname(hostname);
-  if(!h) {
-    infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
-          hostname, port, Curl_strerror(conn, SOCKERRNO));
-    return NULL;
-  }
-  return Curl_he2ai(h, port);
+  return Curl_ipv4_resolve(hostname, port);
 }
-#endif /* CURLRES_IPV4 */
 
-#ifdef CURLRES_IPV6
+#else
+
 /*
- * Curl_getaddrinfo() - for Windows threading IPv6 enabled
+ * Curl_getaddrinfo() - for getaddrinfo
  */
 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
                                 const char *hostname,
@@ -706,11 +656,12 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   Curl_addrinfo *res;
   int error;
   char sbuf[NI_MAXSERV];
-  int pf;
+  int pf = PF_INET;
   struct SessionHandle *data = conn->data;
 
   *waitp = FALSE; /* default to synch response */
 
+#ifndef CURLRES_IPV4
   /*
    * Check if a limited name resolve has been requested.
    */
@@ -743,6 +694,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
       sclose(s);
     }
   }
+#endif
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
@@ -750,7 +702,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 #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)) {
@@ -770,5 +722,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   }
   return res;
 }
-#endif /* CURLRES_IPV6 */
+
+#endif /* HAVE_GETADDRINFO */
+
 #endif /* CURLRES_THREADED */
diff --git a/lib/setup.h b/lib/setup.h
index 5a0e4a1..628771f 100644
--- a/lib/setup.h
+++ b/lib/setup.h
@@ -430,18 +430,13 @@
 
 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
     !defined(__LCC__)  /* lcc-win32 doesn't have _beginthreadex() */
-#ifdef ENABLE_IPV6
-#define USE_THREADING_GETADDRINFO
-#else
-#define USE_THREADING_GETHOSTBYNAME  /* Cygwin uses alarm() function */
-#endif
+#define USE_THREADED_RESOLVE 1
 #endif
 
 /* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
    _beginthreadex() is not available */
 #if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES)
-#undef USE_THREADING_GETADDRINFO
-#undef USE_THREADING_GETHOSTBYNAME
+#undef USE_THREADED_RESOLVE
 #define CURL_NO__BEGINTHREADEX
 #endif
 
diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4
new file mode 100644
index 0000000..bb8d052
--- /dev/null
+++ b/m4/acx_pthread.m4
@@ -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
