[port] Windows XP: try to support threading and event subsystems (#960)

continuation of PR #958

This brings forward Threading and Event Subsystem support by doing a few
additional ifdefs and falling back for functions that were not part of
Windows XP.

I don't know how likely this is to work on a real XP system, but at
least targeting XP while compiling and running through test cases on the
CI/CD system works as expected (CI/CD runs a recent Windows Server
version) .

Signed-off-by: Brad House (@bradh352)
pull/961/head
Brad House 3 months ago committed by GitHub
parent 0518d404ec
commit 9a0d4aed65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      CMakeLists.txt
  2. 4
      appveyor.yml
  3. 5
      configure.ac
  4. 12
      src/lib/ares_config.h.cmake
  5. 29
      src/lib/config-win32.h
  6. 53
      src/lib/event/ares_event_win32.c
  7. 10
      src/lib/event/ares_event_win32.h
  8. 227
      src/lib/util/ares_threads.c
  9. 4
      src/lib/util/ares_threads.h

@ -389,7 +389,7 @@ CARES_TYPE_EXISTS ("struct in6_addr" HAVE_STRUCT_IN6_ADDR)
CARES_TYPE_EXISTS ("struct sockaddr_in6" HAVE_STRUCT_SOCKADDR_IN6)
CARES_TYPE_EXISTS ("struct sockaddr_storage" HAVE_STRUCT_SOCKADDR_STORAGE)
CARES_TYPE_EXISTS ("struct timeval" HAVE_STRUCT_TIMEVAL)
CARES_TYPE_EXISTS ("OVERLAPPED_ENTRY" HAVE_OVERLAPPED_ENTRY)
# Check for preprocessor defines
CHECK_SYMBOL_EXISTS (AF_INET6 "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_AF_INET6)
@ -429,10 +429,13 @@ CHECK_SYMBOL_EXISTS (gettimeofday "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETTIME
CHECK_SYMBOL_EXISTS (if_indextoname "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_IF_INDEXTONAME)
CHECK_SYMBOL_EXISTS (if_nametoindex "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_IF_NAMETOINDEX)
CHECK_SYMBOL_EXISTS (GetBestRoute2 "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETBESTROUTE2)
CHECK_SYMBOL_EXISTS (WSAIoctl "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_WSAIOCTL)
CHECK_SYMBOL_EXISTS (GetQueuedCompletionStatusEx "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_GETQUEUEDCOMPLETIONSTATUSEX)
CHECK_SYMBOL_EXISTS (ConvertInterfaceIndexToLuid "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_CONVERTINTERFACEINDEXTOLUID)
CHECK_SYMBOL_EXISTS (ConvertInterfaceLuidToNameA "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_CONVERTINTERFACELUIDTONAMEA)
CHECK_SYMBOL_EXISTS (NotifyIpInterfaceChange "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_NOTIFYIPINTERFACECHANGE)
CHECK_SYMBOL_EXISTS (RegisterWaitForSingleObject "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_REGISTERWAITFORSINGLEOBJECT)
CHECK_SYMBOL_EXISTS (SetFileCompletionNotificationModes "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_SETFILECOMPLETIONNOTIFICATIONMODES)
CHECK_SYMBOL_EXISTS (inet_net_pton "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_INET_NET_PTON)

@ -30,7 +30,7 @@ environment:
SKIP_TESTS: no
MSVC_SETUP_ARG: x86
MSVC_SETUP_PATH: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat
CMAKE_EXTRA_OPTIONS: -GNinja -DCARES_BUILD_TESTS=ON -DGTEST_ROOT=C:\projects\googletest -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL -DCARES_THREADS=OFF -DCMAKE_C_FLAGS="-D_WIN32_WINNT=0x0501" -DCMAKE_CXX_FLAGS="-D_WIN32_WINNT=0x0501"
CMAKE_EXTRA_OPTIONS: -GNinja -DCARES_BUILD_TESTS=ON -DGTEST_ROOT=C:\projects\googletest -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebugDLL -DCMAKE_C_FLAGS="-D_WIN32_WINNT=0x0501" -DCMAKE_CXX_FLAGS="-D_WIN32_WINNT=0x0501"
TOOLSDIR: ./build/bin
TESTDIR: ./build/bin
BUILD_GOOGLETEST: yes
@ -82,7 +82,7 @@ environment:
TOOLSDIR: ./build/bin
TESTDIR: ./build/bin
PATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;%PATH%
CMAKE_EXTRA_OPTIONS: -DCARES_SHARED=OFF -GNinja -DCARES_BUILD_TESTS=ON -DGTEST_ROOT=C:\projects\googletest -DCARES_THREADS=OFF -DCMAKE_C_FLAGS="-D_WIN32_WINNT=0x0501" -DCMAKE_CXX_FLAGS="-D_WIN32_WINNT=0x0501"
CMAKE_EXTRA_OPTIONS: -DCARES_SHARED=OFF -GNinja -DCARES_BUILD_TESTS=ON -DGTEST_ROOT=C:\projects\googletest -DCMAKE_C_FLAGS="-D_WIN32_WINNT=0x0501" -DCMAKE_CXX_FLAGS="-D_WIN32_WINNT=0x0501"
BUILD_GOOGLETEST: yes
# Disabled until AppVeyor updates their Visual Studio with this patch:

@ -535,6 +535,8 @@ AC_CHECK_TYPE(socklen_t,
AC_CHECK_TYPE(SOCKET, [], [], $cares_all_includes)
AC_CHECK_TYPE(OVERLAPPED_ENTRY, [AC_DEFINE([HAVE_OVERLAPPED_ENTRY], 1, [Define to 1 if you have `OVERLAPPED_ENTRY`] )], [], $cares_all_includes)
dnl ###############################################################################
dnl clock_gettime might require an external library
@ -595,11 +597,14 @@ AC_CHECK_DECL(pipe2, [AC_DEFINE([HAVE_PIPE2], 1, [Define t
AC_CHECK_DECL(kqueue, [AC_DEFINE([HAVE_KQUEUE], 1, [Define to 1 if you have `kqueue`] )], [], $cares_all_includes)
AC_CHECK_DECL(epoll_create1, [AC_DEFINE([HAVE_EPOLL], 1, [Define to 1 if you have `epoll_{create1,ctl,wait}`])], [], $cares_all_includes)
AC_CHECK_DECL(GetBestRoute2, [AC_DEFINE([HAVE_GETBESTROUTE2], 1, [Define to 1 if you have `GetBestRoute2`] )], [], $cares_all_includes)
AC_CHECK_DECL(GetQueuedCompletionStatusEx, [AC_DEFINE([HAVE_GETQUEUEDCOMPLETIONSTATUSEX], 1, [Define to 1 if you have `GetQueuedCompletionStatusEx`])], [], $cares_all_includes)
AC_CHECK_DECL(ConvertInterfaceIndexToLuid, [AC_DEFINE([HAVE_CONVERTINTERFACEINDEXTOLUID], 1, [Define to 1 if you have `ConvertInterfaceIndexToLuid`])], [], $cares_all_includes)
AC_CHECK_DECL(ConvertInterfaceLuidToNameA, [AC_DEFINE([HAVE_CONVERTINTERFACELUIDTONAMEA], 1, [Define to 1 if you have `ConvertInterfaceLuidToNameA`])], [], $cares_all_includes)
AC_CHECK_DECL(NotifyIpInterfaceChange, [AC_DEFINE([HAVE_NOTIFYIPINTERFACECHANGE], 1, [Define to 1 if you have `NotifyIpInterfaceChange`] )], [], $cares_all_includes)
AC_CHECK_DECL(RegisterWaitForSingleObject, [AC_DEFINE([HAVE_REGISTERWAITFORSINGLEOBJECT], 1, [Define to 1 if you have `RegisterWaitForSingleObject`])], [], $cares_all_includes)
AC_CHECK_DECL(__system_property_get, [AC_DEFINE([HAVE___SYSTEM_PROPERTY_GET], 1, [Define to 1 if you have `__system_property_get`] )], [], $cares_all_includes)
AC_CHECK_DECL(SetFileCompletionNotificationModes, [AC_DEFINE([HAVE_SETFILECOMPLETIONNOTIFICATIONMODES], 1, [Define to 1 if you have `SetFileCompletionNotificationModes`])], [], $cares_all_includes)
AC_CHECK_DECL(WSAIoctl, [AC_DEFINE([HAVE_WSAIoctl], 1, [Define to 1 if you have `WSAIoctl`])], [], $cares_all_includes)
dnl ###############################################################################

@ -148,6 +148,15 @@
/* Define to 1 if you have the `GetBestRoute2' function. */
#cmakedefine HAVE_GETBESTROUTE2 1
/* Define to 1 if you have the `WSAIoctl' function. */
#cmakedefine HAVE_WSAIOCTL 1
/* Define to 1 if you have the `OVERLAPPED_ENTRY' data type. */
#cmakedefine HAVE_OVERLAPPED_ENTRY 1
/* Define to 1 if you have the `GetQueuedCompletionStatusEx' function. */
#cmakedefine HAVE_GETQUEUEDCOMPLETIONSTATUSEX 1
/* Define to 1 if you have the `ConvertInterfaceIndexToLuid' function. */
#cmakedefine HAVE_CONVERTINTERFACEINDEXTOLUID 1
@ -160,6 +169,9 @@
/* Define to 1 if you have the `RegisterWaitForSingleObject' function. */
#cmakedefine HAVE_REGISTERWAITFORSINGLEOBJECT 1
/* Define to 1 if you have the `SetFileCompletionNotificationModes' function. */
#cmakedefine HAVE_SETFILECOMPLETIONNOTIFICATIONMODES 1
/* Define to 1 if you have a IPv6 capable working inet_net_pton function. */
#cmakedefine HAVE_INET_NET_PTON 1

@ -237,10 +237,8 @@
# undef HAVE_NETIOAPI_H
#endif
/* Threading support enabled for Vista+ */
#if !defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x0600
# define CARES_THREADS 1
#endif
/* Threading support enabled on Windows always (really XP+ only). */
#define CARES_THREADS 1
/* ---------------------------------------------------------------- */
/* TYPEDEF REPLACEMENTS */
@ -360,6 +358,29 @@
/* Define to 1 if you have the `RegisterWaitForSingleObject' function. */
#define HAVE_REGISTERWAITFORSINGLEOBJECT 1
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
/* Define to 1 if you have the `SetFileCompletionNotificationModes' function. */
# define HAVE_SETFILECOMPLETIONNOTIFICATIONMODES 1
/* Define to 1 if you have the `WSAIoctl' function. */
# define HAVE_WSAIOCTL 1
/* Define to 1 if you have the `GetQueuedCompletionStatusEx' function. */
# define HAVE_GETQUEUEDCOMPLETIONSTATUSEX 1
#endif
/* OVERLAPPED_ENTRY was introduced with Windows Vista for use by
* GetQueuedCompletionStatusEx(). We define it if it doesn't exist as we
* re-implement GetQueuedCompletionStatusEx() for compatibility with XP.
* However, OVERLAPPED_ENTRY is *always* defined when using a Vista or Later
* SDK even when _WIN32_WINNT is set to < 0x0600. So we're assuming anyone
* trying to support older windows versions is still probably compiling with a
* newer SDK.
* We have no way to detect the existence at compile time since we're not using
* autotools or cmake, so assume it is defined. If someone is using something
* ancient like VC6 with the Windows Platform SDK for XP, then they'll need to
* modify this define.
*/
#define HAVE_OVERLAPPED_ENTRY 1
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && \
!defined(__WATCOMC__) && !defined(WATT32)
/* Define if you have if_nametoindex() */

@ -404,10 +404,12 @@ static ares_slist_node_t *ares_afd_handle_create(ares_evsys_win32_t *ew)
goto fail;
}
#ifdef HAVE_SETFILECOMPLETIONNOTIFICATIONMODES
if (!SetFileCompletionNotificationModes(afd->afd_handle,
FILE_SKIP_SET_EVENT_ON_HANDLE)) {
goto fail;
}
#endif
node = ares_slist_insert(ew->afd_handles, afd);
if (node == NULL) {
@ -521,6 +523,11 @@ fail:
static ares_socket_t ares_evsys_win32_basesocket(ares_socket_t socket)
{
#ifndef HAVE_WSAIOCTL
/* Assume we don't have an LSP and return the provided socket as the base
* socket. WSAIoctl() isn't supported on Windows XP or below */
return socket;
#else
while (1) {
DWORD bytes; /* Not used */
ares_socket_t base_socket = ARES_SOCKET_BAD;
@ -558,6 +565,7 @@ static ares_socket_t ares_evsys_win32_basesocket(ares_socket_t socket)
}
return socket;
#endif
}
static ares_bool_t ares_evsys_win32_afd_enqueue(ares_event_t *event,
@ -906,6 +914,46 @@ static ares_bool_t ares_evsys_win32_process_socket_event(
return ARES_TRUE;
}
static BOOL ares_GetQueuedCompletionStatusEx(
HANDLE CompletionPort,
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
ULONG ulCount,
PULONG ulNumEntriesRemoved,
DWORD dwMilliseconds,
BOOL fAlertable)
{
#ifdef HAVE_GETQUEUEDCOMPLETIONSTATUSEX
return GetQueuedCompletionStatusEx(CompletionPort, lpCompletionPortEntries,
ulCount, ulNumEntriesRemoved, dwMilliseconds, fAlertable);
#else
ULONG i;
(void)fAlertable;
memset(lpCompletionPortEntries, 0,
ulCount * sizeof(*lpCompletionPortEntries));
(*ulNumEntriesRemoved) = 0;
for (i=0; i<ulCount; i++) {
if (!GetQueuedCompletionStatus(CompletionPort,
&lpCompletionPortEntries[i].dwNumberOfBytesTransferred,
&lpCompletionPortEntries[i].lpCompletionKey,
&lpCompletionPortEntries[i].lpOverlapped,
(i == 0)?dwMilliseconds:0)) {
break;
}
(*ulNumEntriesRemoved)++;
}
if (*ulNumEntriesRemoved > 0) {
return TRUE;
}
return FALSE;
#endif
}
static size_t ares_evsys_win32_wait(ares_event_thread_t *e,
unsigned long timeout_ms)
{
@ -923,8 +971,9 @@ static size_t ares_evsys_win32_wait(ares_event_thread_t *e,
* on subsequent attempts, ensure the timeout is 0 */
do {
nentries = maxentries;
status = GetQueuedCompletionStatusEx(ew->iocp_handle, entries, nentries,
&nentries, tout, FALSE);
status = ares_GetQueuedCompletionStatusEx(ew->iocp_handle, entries,
nentries, &nentries, tout,
FALSE);
/* Next loop around, we want to return instantly if there are no events to
* be processed */

@ -156,6 +156,16 @@ typedef NTSTATUS(NTAPI *NtCreateFile_t)(
# define HANDLE_FLAG_INHERIT 0x00000001
# endif
# ifndef HAVE_OVERLAPPED_ENTRY
typedef struct _OVERLAPPED_ENTRY {
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
ULONG_PTR Internal;
DWORD dwNumberOfBytesTransferred;
} OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
# endif
#endif /* _WIN32 */
#endif /* __ARES_EVENT_WIN32_H */

@ -24,6 +24,9 @@
* SPDX-License-Identifier: MIT
*/
#include "ares_private.h"
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef CARES_THREADS
# ifdef _WIN32
@ -68,6 +71,8 @@ void ares_thread_mutex_unlock(ares_thread_mutex_t *mut)
LeaveCriticalSection(&mut->mutex);
}
# if _WIN32_WINNT >= 0x0600 /* Vista */
struct ares_thread_cond {
CONDITION_VARIABLE cond;
};
@ -119,19 +124,227 @@ ares_status_t ares_thread_cond_wait(ares_thread_cond_t *cond,
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut,
unsigned long timeout_ms)
size_t timeout_ms)
{
DWORD tout;
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
if (timeout_ms == SIZE_MAX) {
tout = INFINITE;
} else {
tout = (DWORD)timeout_ms;
}
if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, tout)) {
return ARES_ETIMEOUT;
}
return ARES_SUCCESS;
}
# else
typedef enum {
ARES_W32_COND_SIGNAL = 0,
ARES_W32_COND_BROADCAST,
ARES_W32_COND_EVMAX,
ARES_W32_COND_NONE = ARES_W32_COND_EVMAX
} ares_w32_cond_event_t;
struct ares_thread_cond {
HANDLE events[2];
HANDLE gate;
CRITICAL_SECTION mutex;
size_t waiters;
ares_w32_cond_event_t event;
};
ares_thread_cond_t *ares_thread_cond_create(void)
{
ares_thread_cond_t *cond;
cond = ares_malloc_zero(sizeof(*cond));
if (cond == NULL) {
return NULL;
}
cond->events[ARES_W32_COND_SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
if (cond->events[ARES_W32_COND_SIGNAL] == NULL) {
goto fail;
}
cond->events[ARES_W32_COND_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
if (cond->events[ARES_W32_COND_BROADCAST] == NULL) {
goto fail;
}
/* Use a semaphore as a gate so we don't lose signals */
cond->gate = CreateSemaphore(NULL, 1, 1, NULL);
if (cond->gate == NULL) {
goto fail;
}
InitializeCriticalSection(&cond->mutex);
cond->waiters = 0;
cond->event = ARES_W32_COND_NONE;
return cond;
fail:
ares_thread_cond_destroy(cond);
return NULL;
}
void ares_thread_cond_destroy(ares_thread_cond_t *cond)
{
if (cond == NULL)
return;
if (cond->events[ARES_W32_COND_SIGNAL]) {
CloseHandle(cond->events[ARES_W32_COND_SIGNAL]);
}
if (cond->events[ARES_W32_COND_BROADCAST]) {
CloseHandle(cond->events[ARES_W32_COND_BROADCAST]);
}
if (cond->gate) {
CloseHandle(cond->gate);
}
DeleteCriticalSection(&cond->mutex);
ares_free(cond);
}
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut,
size_t timeout_ms)
{
DWORD rv;
DWORD dwMilliseconds;
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, timeout_ms)) {
/* We may only enter when no wakeups active this will prevent the lost
* wakeup */
WaitForSingleObject(cond->gate, INFINITE);
EnterCriticalSection(&cond->mutex);
/* count waiters passing through */
cond->waiters++;
LeaveCriticalSection(&cond->mutex);
/* Open Gate */
ReleaseSemaphore(cond->gate, 1, NULL);
/* Release passed in mutex */
ares_thread_mutex_unlock(mut);
if (timeout_ms == SIZE_MAX) {
dwMilliseconds = INFINITE;
} else {
dwMilliseconds = (DWORD)timeout_ms;
}
rv = WaitForMultipleObjects(ARES_W32_COND_EVMAX, cond->events, FALSE,
dwMilliseconds);
/* We go into a critical section to make sure cond->waiters isn't checked
* while we decrement. This is especially important for a timeout since the
* gate may not be closed. We need to check to see if a broadcast/signal was
* pending as this thread could have been preempted prior to
* EnterCriticalSection but after WaitForMultipleObjects() so we may be
* responsible for resetting the event and closing the gate */
EnterCriticalSection(&cond->mutex);
cond->waiters--;
if (cond->event != ARES_W32_COND_NONE && cond->waiters == 0) {
/* Last waiter needs to reset the event on(as a broadcast event is not
* automatic) and also re-open the gate */
if (cond->event == ARES_W32_COND_BROADCAST) {
ResetEvent(cond->events[ARES_W32_COND_BROADCAST]);
}
/* Open Gate (closed by ares_thread_cond_broadcast()) since there are no
* more waiters for the event */
ReleaseSemaphore(cond->gate, 1, NULL);
cond->event = ARES_W32_COND_NONE;
} else if (rv == WAIT_OBJECT_0 + ARES_W32_COND_SIGNAL) {
/* If specifically, this thread was signalled and there are more waiting,
* re-open the gate and reset the event */
ReleaseSemaphore(cond->gate, 1, NULL);
cond->event = ARES_W32_COND_NONE;
} else {
/* This could be a standard timeout with more waiters, don't do anything */
}
LeaveCriticalSection(&cond->mutex);
/* re-lock the passed in mutex */
ares_thread_mutex_lock(mut);
if (rv == WAIT_TIMEOUT) {
return ARES_ETIMEOUT;
}
return ARES_SUCCESS;
}
ares_status_t ares_thread_cond_wait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut)
{
return ares_thread_cond_timedwait(cond, mut, SIZE_MAX);
}
void ares_thread_cond_broadcast(ares_thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
/* close gate to prevent more waiters while broadcasting */
WaitForSingleObject(cond->gate, INFINITE);
/* If there are waiters, send a broadcast event,
* otherwise, just reopen the gate */
EnterCriticalSection(&cond->mutex);
cond->event = ARES_W32_COND_BROADCAST;
if (cond->waiters) {
/* wake all waiters */
SetEvent(cond->events[ARES_W32_COND_BROADCAST]);
} else {
/* if no waiters just reopen gate */
ReleaseSemaphore(cond->gate, 1, NULL);
}
LeaveCriticalSection(&cond->mutex);
}
void ares_thread_cond_signal(ares_thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
/* close gate to prevent more waiters while signalling */
WaitForSingleObject(cond->gate, INFINITE);
EnterCriticalSection(&cond->mutex);
cond->event = ARES_W32_COND_SIGNAL;
if (cond->waiters) {
/* wake one waiter */
SetEvent(cond->events[ARES_W32_COND_SIGNAL]);
} else {
/* no waiters, just reopen the gate */
ReleaseSemaphore(cond->gate, 1, NULL);
}
LeaveCriticalSection(&cond->mutex);
}
# endif
struct ares_thread {
HANDLE thread;
DWORD id;
@ -322,7 +535,7 @@ ares_status_t ares_thread_cond_wait(ares_thread_cond_t *cond,
return ARES_SUCCESS;
}
static void ares_timespec_timeout(struct timespec *ts, unsigned long add_ms)
static void ares_timespec_timeout(struct timespec *ts, size_t add_ms)
{
# if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
clock_gettime(CLOCK_REALTIME, ts);
@ -347,7 +560,7 @@ static void ares_timespec_timeout(struct timespec *ts, unsigned long add_ms)
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut,
unsigned long timeout_ms)
size_t timeout_ms)
{
struct timespec ts;
@ -355,6 +568,10 @@ ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
return ARES_EFORMERR;
}
if (timeout_ms == SIZE_MAX) {
return ares_thread_cond_wait(cond, mut);
}
ares_timespec_timeout(&ts, timeout_ms);
if (pthread_cond_timedwait(&cond->cond, &mut->mutex, &ts) != 0) {
@ -470,7 +687,7 @@ ares_status_t ares_thread_cond_wait(ares_thread_cond_t *cond,
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut,
unsigned long timeout_ms)
size_t timeout_ms)
{
(void)cond;
(void)mut;

@ -44,9 +44,11 @@ void ares_thread_cond_signal(ares_thread_cond_t *cond);
void ares_thread_cond_broadcast(ares_thread_cond_t *cond);
ares_status_t ares_thread_cond_wait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut);
/* NOTE: value of SIZE_MAX for timeout_ms means infinite */
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t *cond,
ares_thread_mutex_t *mut,
unsigned long timeout_ms);
size_t timeout_ms);
struct ares_thread;

Loading…
Cancel
Save