11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci#include "ares.h"
281cb0ef41Sopenharmony_ci#include "ares_private.h"
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#ifdef CARES_THREADS
311cb0ef41Sopenharmony_ci#  ifdef _WIN32
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_cistruct ares__thread_mutex {
341cb0ef41Sopenharmony_ci  CRITICAL_SECTION mutex;
351cb0ef41Sopenharmony_ci};
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciares__thread_mutex_t *ares__thread_mutex_create(void)
381cb0ef41Sopenharmony_ci{
391cb0ef41Sopenharmony_ci  ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
401cb0ef41Sopenharmony_ci  if (mut == NULL) {
411cb0ef41Sopenharmony_ci    return NULL;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  InitializeCriticalSection(&mut->mutex);
451cb0ef41Sopenharmony_ci  return mut;
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_civoid ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
491cb0ef41Sopenharmony_ci{
501cb0ef41Sopenharmony_ci  if (mut == NULL) {
511cb0ef41Sopenharmony_ci    return;
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci  DeleteCriticalSection(&mut->mutex);
541cb0ef41Sopenharmony_ci  ares_free(mut);
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_civoid ares__thread_mutex_lock(ares__thread_mutex_t *mut)
581cb0ef41Sopenharmony_ci{
591cb0ef41Sopenharmony_ci  if (mut == NULL) {
601cb0ef41Sopenharmony_ci    return;
611cb0ef41Sopenharmony_ci  }
621cb0ef41Sopenharmony_ci  EnterCriticalSection(&mut->mutex);
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_civoid ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci  if (mut == NULL) {
681cb0ef41Sopenharmony_ci    return;
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci  LeaveCriticalSection(&mut->mutex);
711cb0ef41Sopenharmony_ci}
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cistruct ares__thread_cond {
741cb0ef41Sopenharmony_ci  CONDITION_VARIABLE cond;
751cb0ef41Sopenharmony_ci};
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciares__thread_cond_t *ares__thread_cond_create(void)
781cb0ef41Sopenharmony_ci{
791cb0ef41Sopenharmony_ci  ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
801cb0ef41Sopenharmony_ci  if (cond == NULL) {
811cb0ef41Sopenharmony_ci    return NULL;
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci  InitializeConditionVariable(&cond->cond);
841cb0ef41Sopenharmony_ci  return cond;
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_civoid ares__thread_cond_destroy(ares__thread_cond_t *cond)
881cb0ef41Sopenharmony_ci{
891cb0ef41Sopenharmony_ci  if (cond == NULL) {
901cb0ef41Sopenharmony_ci    return;
911cb0ef41Sopenharmony_ci  }
921cb0ef41Sopenharmony_ci  ares_free(cond);
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_civoid ares__thread_cond_signal(ares__thread_cond_t *cond)
961cb0ef41Sopenharmony_ci{
971cb0ef41Sopenharmony_ci  if (cond == NULL) {
981cb0ef41Sopenharmony_ci    return;
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci  WakeConditionVariable(&cond->cond);
1011cb0ef41Sopenharmony_ci}
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_civoid ares__thread_cond_broadcast(ares__thread_cond_t *cond)
1041cb0ef41Sopenharmony_ci{
1051cb0ef41Sopenharmony_ci  if (cond == NULL) {
1061cb0ef41Sopenharmony_ci    return;
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci  WakeAllConditionVariable(&cond->cond);
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_wait(ares__thread_cond_t  *cond,
1121cb0ef41Sopenharmony_ci                                     ares__thread_mutex_t *mut)
1131cb0ef41Sopenharmony_ci{
1141cb0ef41Sopenharmony_ci  if (cond == NULL || mut == NULL) {
1151cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  SleepConditionVariableCS(&cond->cond, &mut->mutex, INFINITE);
1191cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
1201cb0ef41Sopenharmony_ci}
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_timedwait(ares__thread_cond_t  *cond,
1231cb0ef41Sopenharmony_ci                                          ares__thread_mutex_t *mut,
1241cb0ef41Sopenharmony_ci                                          unsigned long         timeout_ms)
1251cb0ef41Sopenharmony_ci{
1261cb0ef41Sopenharmony_ci  if (cond == NULL || mut == NULL) {
1271cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1281cb0ef41Sopenharmony_ci  }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, timeout_ms)) {
1311cb0ef41Sopenharmony_ci    return ARES_ETIMEOUT;
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_cistruct ares__thread {
1381cb0ef41Sopenharmony_ci  HANDLE thread;
1391cb0ef41Sopenharmony_ci  DWORD  id;
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  void  *(*func)(void *arg);
1421cb0ef41Sopenharmony_ci  void  *arg;
1431cb0ef41Sopenharmony_ci  void  *rv;
1441cb0ef41Sopenharmony_ci};
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci/* Wrap for pthread compatibility */
1471cb0ef41Sopenharmony_cistatic DWORD WINAPI ares__thread_func(LPVOID lpParameter)
1481cb0ef41Sopenharmony_ci{
1491cb0ef41Sopenharmony_ci  ares__thread_t *thread = lpParameter;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  thread->rv = thread->func(thread->arg);
1521cb0ef41Sopenharmony_ci  return 0;
1531cb0ef41Sopenharmony_ci}
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ciares_status_t ares__thread_create(ares__thread_t    **thread,
1561cb0ef41Sopenharmony_ci                                  ares__thread_func_t func, void *arg)
1571cb0ef41Sopenharmony_ci{
1581cb0ef41Sopenharmony_ci  ares__thread_t *thr = NULL;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  if (func == NULL || thread == NULL) {
1611cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  thr = ares_malloc_zero(sizeof(*thr));
1651cb0ef41Sopenharmony_ci  if (thr == NULL) {
1661cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  thr->func   = func;
1701cb0ef41Sopenharmony_ci  thr->arg    = arg;
1711cb0ef41Sopenharmony_ci  thr->thread = CreateThread(NULL, 0, ares__thread_func, thr, 0, &thr->id);
1721cb0ef41Sopenharmony_ci  if (thr->thread == NULL) {
1731cb0ef41Sopenharmony_ci    ares_free(thr);
1741cb0ef41Sopenharmony_ci    return ARES_ESERVFAIL;
1751cb0ef41Sopenharmony_ci  }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  *thread = thr;
1781cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
1791cb0ef41Sopenharmony_ci}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ciares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
1821cb0ef41Sopenharmony_ci{
1831cb0ef41Sopenharmony_ci  ares_status_t status = ARES_SUCCESS;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  if (thread == NULL) {
1861cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1871cb0ef41Sopenharmony_ci  }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) {
1901cb0ef41Sopenharmony_ci    status = ARES_ENOTFOUND;
1911cb0ef41Sopenharmony_ci  } else {
1921cb0ef41Sopenharmony_ci    CloseHandle(thread->thread);
1931cb0ef41Sopenharmony_ci  }
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS && rv != NULL) {
1961cb0ef41Sopenharmony_ci    *rv = thread->rv;
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci  ares_free(thread);
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  return status;
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci#  else /* !WIN32 == PTHREAD */
2041cb0ef41Sopenharmony_ci#    include <pthread.h>
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci/* for clock_gettime() */
2071cb0ef41Sopenharmony_ci#    ifdef HAVE_TIME_H
2081cb0ef41Sopenharmony_ci#      include <time.h>
2091cb0ef41Sopenharmony_ci#    endif
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci/* for gettimeofday() */
2121cb0ef41Sopenharmony_ci#    ifdef HAVE_SYS_TIME_H
2131cb0ef41Sopenharmony_ci#      include <sys/time.h>
2141cb0ef41Sopenharmony_ci#    endif
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_cistruct ares__thread_mutex {
2171cb0ef41Sopenharmony_ci  pthread_mutex_t mutex;
2181cb0ef41Sopenharmony_ci};
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ciares__thread_mutex_t *ares__thread_mutex_create(void)
2211cb0ef41Sopenharmony_ci{
2221cb0ef41Sopenharmony_ci  pthread_mutexattr_t   attr;
2231cb0ef41Sopenharmony_ci  ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
2241cb0ef41Sopenharmony_ci  if (mut == NULL) {
2251cb0ef41Sopenharmony_ci    return NULL;
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  if (pthread_mutexattr_init(&attr) != 0) {
2291cb0ef41Sopenharmony_ci    ares_free(mut);
2301cb0ef41Sopenharmony_ci    return NULL;
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
2341cb0ef41Sopenharmony_ci    goto fail;
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  if (pthread_mutex_init(&mut->mutex, &attr) != 0) {
2381cb0ef41Sopenharmony_ci    goto fail;
2391cb0ef41Sopenharmony_ci  }
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  pthread_mutexattr_destroy(&attr);
2421cb0ef41Sopenharmony_ci  return mut;
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_cifail:
2451cb0ef41Sopenharmony_ci  pthread_mutexattr_destroy(&attr);
2461cb0ef41Sopenharmony_ci  ares_free(mut);
2471cb0ef41Sopenharmony_ci  return NULL;
2481cb0ef41Sopenharmony_ci}
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_civoid ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
2511cb0ef41Sopenharmony_ci{
2521cb0ef41Sopenharmony_ci  if (mut == NULL) {
2531cb0ef41Sopenharmony_ci    return;
2541cb0ef41Sopenharmony_ci  }
2551cb0ef41Sopenharmony_ci  pthread_mutex_destroy(&mut->mutex);
2561cb0ef41Sopenharmony_ci  ares_free(mut);
2571cb0ef41Sopenharmony_ci}
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_civoid ares__thread_mutex_lock(ares__thread_mutex_t *mut)
2601cb0ef41Sopenharmony_ci{
2611cb0ef41Sopenharmony_ci  if (mut == NULL) {
2621cb0ef41Sopenharmony_ci    return;
2631cb0ef41Sopenharmony_ci  }
2641cb0ef41Sopenharmony_ci  pthread_mutex_lock(&mut->mutex);
2651cb0ef41Sopenharmony_ci}
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_civoid ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
2681cb0ef41Sopenharmony_ci{
2691cb0ef41Sopenharmony_ci  if (mut == NULL) {
2701cb0ef41Sopenharmony_ci    return;
2711cb0ef41Sopenharmony_ci  }
2721cb0ef41Sopenharmony_ci  pthread_mutex_unlock(&mut->mutex);
2731cb0ef41Sopenharmony_ci}
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_cistruct ares__thread_cond {
2761cb0ef41Sopenharmony_ci  pthread_cond_t cond;
2771cb0ef41Sopenharmony_ci};
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ciares__thread_cond_t *ares__thread_cond_create(void)
2801cb0ef41Sopenharmony_ci{
2811cb0ef41Sopenharmony_ci  ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
2821cb0ef41Sopenharmony_ci  if (cond == NULL) {
2831cb0ef41Sopenharmony_ci    return NULL;
2841cb0ef41Sopenharmony_ci  }
2851cb0ef41Sopenharmony_ci  pthread_cond_init(&cond->cond, NULL);
2861cb0ef41Sopenharmony_ci  return cond;
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_civoid ares__thread_cond_destroy(ares__thread_cond_t *cond)
2901cb0ef41Sopenharmony_ci{
2911cb0ef41Sopenharmony_ci  if (cond == NULL) {
2921cb0ef41Sopenharmony_ci    return;
2931cb0ef41Sopenharmony_ci  }
2941cb0ef41Sopenharmony_ci  pthread_cond_destroy(&cond->cond);
2951cb0ef41Sopenharmony_ci  ares_free(cond);
2961cb0ef41Sopenharmony_ci}
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_civoid ares__thread_cond_signal(ares__thread_cond_t *cond)
2991cb0ef41Sopenharmony_ci{
3001cb0ef41Sopenharmony_ci  if (cond == NULL) {
3011cb0ef41Sopenharmony_ci    return;
3021cb0ef41Sopenharmony_ci  }
3031cb0ef41Sopenharmony_ci  pthread_cond_signal(&cond->cond);
3041cb0ef41Sopenharmony_ci}
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_civoid ares__thread_cond_broadcast(ares__thread_cond_t *cond)
3071cb0ef41Sopenharmony_ci{
3081cb0ef41Sopenharmony_ci  if (cond == NULL) {
3091cb0ef41Sopenharmony_ci    return;
3101cb0ef41Sopenharmony_ci  }
3111cb0ef41Sopenharmony_ci  pthread_cond_broadcast(&cond->cond);
3121cb0ef41Sopenharmony_ci}
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_wait(ares__thread_cond_t  *cond,
3151cb0ef41Sopenharmony_ci                                     ares__thread_mutex_t *mut)
3161cb0ef41Sopenharmony_ci{
3171cb0ef41Sopenharmony_ci  if (cond == NULL || mut == NULL) {
3181cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  pthread_cond_wait(&cond->cond, &mut->mutex);
3221cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3231cb0ef41Sopenharmony_ci}
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_cistatic void ares__timespec_timeout(struct timespec *ts, unsigned long add_ms)
3261cb0ef41Sopenharmony_ci{
3271cb0ef41Sopenharmony_ci#    if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
3281cb0ef41Sopenharmony_ci  clock_gettime(CLOCK_REALTIME, ts);
3291cb0ef41Sopenharmony_ci#    elif defined(HAVE_GETTIMEOFDAY)
3301cb0ef41Sopenharmony_ci  struct timeval tv;
3311cb0ef41Sopenharmony_ci  gettimeofday(&tv, NULL);
3321cb0ef41Sopenharmony_ci  ts->tv_sec  = tv.tv_sec;
3331cb0ef41Sopenharmony_ci  ts->tv_nsec = tv.tv_usec * 1000;
3341cb0ef41Sopenharmony_ci#    else
3351cb0ef41Sopenharmony_ci#      error cannot determine current system time
3361cb0ef41Sopenharmony_ci#    endif
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  ts->tv_sec  += add_ms / 1000;
3391cb0ef41Sopenharmony_ci  ts->tv_nsec += (add_ms % 1000) * 1000000;
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci  /* Normalize if needed */
3421cb0ef41Sopenharmony_ci  if (ts->tv_nsec >= 1000000000) {
3431cb0ef41Sopenharmony_ci    ts->tv_sec  += ts->tv_nsec / 1000000000;
3441cb0ef41Sopenharmony_ci    ts->tv_nsec %= 1000000000;
3451cb0ef41Sopenharmony_ci  }
3461cb0ef41Sopenharmony_ci}
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_timedwait(ares__thread_cond_t  *cond,
3491cb0ef41Sopenharmony_ci                                          ares__thread_mutex_t *mut,
3501cb0ef41Sopenharmony_ci                                          unsigned long         timeout_ms)
3511cb0ef41Sopenharmony_ci{
3521cb0ef41Sopenharmony_ci  struct timespec ts;
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci  if (cond == NULL || mut == NULL) {
3551cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  ares__timespec_timeout(&ts, timeout_ms);
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  if (pthread_cond_timedwait(&cond->cond, &mut->mutex, &ts) != 0) {
3611cb0ef41Sopenharmony_ci    return ARES_ETIMEOUT;
3621cb0ef41Sopenharmony_ci  }
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3651cb0ef41Sopenharmony_ci}
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_cistruct ares__thread {
3681cb0ef41Sopenharmony_ci  pthread_t thread;
3691cb0ef41Sopenharmony_ci};
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ciares_status_t ares__thread_create(ares__thread_t    **thread,
3721cb0ef41Sopenharmony_ci                                  ares__thread_func_t func, void *arg)
3731cb0ef41Sopenharmony_ci{
3741cb0ef41Sopenharmony_ci  ares__thread_t *thr = NULL;
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci  if (func == NULL || thread == NULL) {
3771cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
3781cb0ef41Sopenharmony_ci  }
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci  thr = ares_malloc_zero(sizeof(*thr));
3811cb0ef41Sopenharmony_ci  if (thr == NULL) {
3821cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci  if (pthread_create(&thr->thread, NULL, func, arg) != 0) {
3851cb0ef41Sopenharmony_ci    ares_free(thr);
3861cb0ef41Sopenharmony_ci    return ARES_ESERVFAIL;
3871cb0ef41Sopenharmony_ci  }
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  *thread = thr;
3901cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3911cb0ef41Sopenharmony_ci}
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ciares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
3941cb0ef41Sopenharmony_ci{
3951cb0ef41Sopenharmony_ci  void         *ret    = NULL;
3961cb0ef41Sopenharmony_ci  ares_status_t status = ARES_SUCCESS;
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  if (thread == NULL) {
3991cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4001cb0ef41Sopenharmony_ci  }
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci  if (pthread_join(thread->thread, &ret) != 0) {
4031cb0ef41Sopenharmony_ci    status = ARES_ENOTFOUND;
4041cb0ef41Sopenharmony_ci  }
4051cb0ef41Sopenharmony_ci  ares_free(thread);
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS && rv != NULL) {
4081cb0ef41Sopenharmony_ci    *rv = ret;
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci  return status;
4111cb0ef41Sopenharmony_ci}
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci#  endif
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ciares_bool_t ares_threadsafety(void)
4161cb0ef41Sopenharmony_ci{
4171cb0ef41Sopenharmony_ci  return ARES_TRUE;
4181cb0ef41Sopenharmony_ci}
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci#else /* !CARES_THREADS */
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci/* NoOp */
4231cb0ef41Sopenharmony_ciares__thread_mutex_t *ares__thread_mutex_create(void)
4241cb0ef41Sopenharmony_ci{
4251cb0ef41Sopenharmony_ci  return NULL;
4261cb0ef41Sopenharmony_ci}
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_civoid ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
4291cb0ef41Sopenharmony_ci{
4301cb0ef41Sopenharmony_ci  (void)mut;
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_civoid ares__thread_mutex_lock(ares__thread_mutex_t *mut)
4341cb0ef41Sopenharmony_ci{
4351cb0ef41Sopenharmony_ci  (void)mut;
4361cb0ef41Sopenharmony_ci}
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_civoid ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
4391cb0ef41Sopenharmony_ci{
4401cb0ef41Sopenharmony_ci  (void)mut;
4411cb0ef41Sopenharmony_ci}
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ciares__thread_cond_t *ares__thread_cond_create(void)
4441cb0ef41Sopenharmony_ci{
4451cb0ef41Sopenharmony_ci  return NULL;
4461cb0ef41Sopenharmony_ci}
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_civoid ares__thread_cond_destroy(ares__thread_cond_t *cond)
4491cb0ef41Sopenharmony_ci{
4501cb0ef41Sopenharmony_ci  (void)cond;
4511cb0ef41Sopenharmony_ci}
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_civoid ares__thread_cond_signal(ares__thread_cond_t *cond)
4541cb0ef41Sopenharmony_ci{
4551cb0ef41Sopenharmony_ci  (void)cond;
4561cb0ef41Sopenharmony_ci}
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_civoid ares__thread_cond_broadcast(ares__thread_cond_t *cond)
4591cb0ef41Sopenharmony_ci{
4601cb0ef41Sopenharmony_ci  (void)cond;
4611cb0ef41Sopenharmony_ci}
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_wait(ares__thread_cond_t  *cond,
4641cb0ef41Sopenharmony_ci                                     ares__thread_mutex_t *mut)
4651cb0ef41Sopenharmony_ci{
4661cb0ef41Sopenharmony_ci  (void)cond;
4671cb0ef41Sopenharmony_ci  (void)mut;
4681cb0ef41Sopenharmony_ci  return ARES_ENOTIMP;
4691cb0ef41Sopenharmony_ci}
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ciares_status_t ares__thread_cond_timedwait(ares__thread_cond_t  *cond,
4721cb0ef41Sopenharmony_ci                                          ares__thread_mutex_t *mut,
4731cb0ef41Sopenharmony_ci                                          unsigned long         timeout_ms)
4741cb0ef41Sopenharmony_ci{
4751cb0ef41Sopenharmony_ci  (void)cond;
4761cb0ef41Sopenharmony_ci  (void)mut;
4771cb0ef41Sopenharmony_ci  (void)timeout_ms;
4781cb0ef41Sopenharmony_ci  return ARES_ENOTIMP;
4791cb0ef41Sopenharmony_ci}
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ciares_status_t ares__thread_create(ares__thread_t    **thread,
4821cb0ef41Sopenharmony_ci                                  ares__thread_func_t func, void *arg)
4831cb0ef41Sopenharmony_ci{
4841cb0ef41Sopenharmony_ci  (void)thread;
4851cb0ef41Sopenharmony_ci  (void)func;
4861cb0ef41Sopenharmony_ci  (void)arg;
4871cb0ef41Sopenharmony_ci  return ARES_ENOTIMP;
4881cb0ef41Sopenharmony_ci}
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ciares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
4911cb0ef41Sopenharmony_ci{
4921cb0ef41Sopenharmony_ci  (void)thread;
4931cb0ef41Sopenharmony_ci  (void)rv;
4941cb0ef41Sopenharmony_ci  return ARES_ENOTIMP;
4951cb0ef41Sopenharmony_ci}
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ciares_bool_t ares_threadsafety(void)
4981cb0ef41Sopenharmony_ci{
4991cb0ef41Sopenharmony_ci  return ARES_FALSE;
5001cb0ef41Sopenharmony_ci}
5011cb0ef41Sopenharmony_ci#endif
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_ciares_status_t ares__channel_threading_init(ares_channel_t *channel)
5051cb0ef41Sopenharmony_ci{
5061cb0ef41Sopenharmony_ci  ares_status_t status = ARES_SUCCESS;
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci  /* Threading is optional! */
5091cb0ef41Sopenharmony_ci  if (!ares_threadsafety()) {
5101cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
5111cb0ef41Sopenharmony_ci  }
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci  channel->lock = ares__thread_mutex_create();
5141cb0ef41Sopenharmony_ci  if (channel->lock == NULL) {
5151cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
5161cb0ef41Sopenharmony_ci    goto done;
5171cb0ef41Sopenharmony_ci  }
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ci  channel->cond_empty = ares__thread_cond_create();
5201cb0ef41Sopenharmony_ci  if (channel->cond_empty == NULL) {
5211cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
5221cb0ef41Sopenharmony_ci    goto done;
5231cb0ef41Sopenharmony_ci  }
5241cb0ef41Sopenharmony_ci
5251cb0ef41Sopenharmony_cidone:
5261cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
5271cb0ef41Sopenharmony_ci    ares__channel_threading_destroy(channel);
5281cb0ef41Sopenharmony_ci  }
5291cb0ef41Sopenharmony_ci  return status;
5301cb0ef41Sopenharmony_ci}
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_civoid ares__channel_threading_destroy(ares_channel_t *channel)
5331cb0ef41Sopenharmony_ci{
5341cb0ef41Sopenharmony_ci  ares__thread_mutex_destroy(channel->lock);
5351cb0ef41Sopenharmony_ci  channel->lock = NULL;
5361cb0ef41Sopenharmony_ci  ares__thread_cond_destroy(channel->cond_empty);
5371cb0ef41Sopenharmony_ci  channel->cond_empty = NULL;
5381cb0ef41Sopenharmony_ci}
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_civoid ares__channel_lock(ares_channel_t *channel)
5411cb0ef41Sopenharmony_ci{
5421cb0ef41Sopenharmony_ci  ares__thread_mutex_lock(channel->lock);
5431cb0ef41Sopenharmony_ci}
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_civoid ares__channel_unlock(ares_channel_t *channel)
5461cb0ef41Sopenharmony_ci{
5471cb0ef41Sopenharmony_ci  ares__thread_mutex_unlock(channel->lock);
5481cb0ef41Sopenharmony_ci}
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci/* Must not be holding a channel lock already, public function only */
5511cb0ef41Sopenharmony_ciares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms)
5521cb0ef41Sopenharmony_ci{
5531cb0ef41Sopenharmony_ci  ares_status_t  status = ARES_SUCCESS;
5541cb0ef41Sopenharmony_ci  struct timeval tout;
5551cb0ef41Sopenharmony_ci
5561cb0ef41Sopenharmony_ci  if (!ares_threadsafety()) {
5571cb0ef41Sopenharmony_ci    return ARES_ENOTIMP;
5581cb0ef41Sopenharmony_ci  }
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ci  if (channel == NULL) {
5611cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
5621cb0ef41Sopenharmony_ci  }
5631cb0ef41Sopenharmony_ci
5641cb0ef41Sopenharmony_ci  if (timeout_ms >= 0) {
5651cb0ef41Sopenharmony_ci    tout          = ares__tvnow();
5661cb0ef41Sopenharmony_ci    tout.tv_sec  += timeout_ms / 1000;
5671cb0ef41Sopenharmony_ci    tout.tv_usec += (timeout_ms % 1000) * 1000;
5681cb0ef41Sopenharmony_ci  }
5691cb0ef41Sopenharmony_ci
5701cb0ef41Sopenharmony_ci  ares__thread_mutex_lock(channel->lock);
5711cb0ef41Sopenharmony_ci  while (ares__llist_len(channel->all_queries)) {
5721cb0ef41Sopenharmony_ci    if (timeout_ms < 0) {
5731cb0ef41Sopenharmony_ci      ares__thread_cond_wait(channel->cond_empty, channel->lock);
5741cb0ef41Sopenharmony_ci    } else {
5751cb0ef41Sopenharmony_ci      struct timeval tv_remaining;
5761cb0ef41Sopenharmony_ci      struct timeval tv_now = ares__tvnow();
5771cb0ef41Sopenharmony_ci      unsigned long  tms;
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci      ares__timeval_remaining(&tv_remaining, &tv_now, &tout);
5801cb0ef41Sopenharmony_ci      tms = (unsigned long)((tv_remaining.tv_sec * 1000) +
5811cb0ef41Sopenharmony_ci                            (tv_remaining.tv_usec / 1000));
5821cb0ef41Sopenharmony_ci      if (tms == 0) {
5831cb0ef41Sopenharmony_ci        status = ARES_ETIMEOUT;
5841cb0ef41Sopenharmony_ci      } else {
5851cb0ef41Sopenharmony_ci        status =
5861cb0ef41Sopenharmony_ci          ares__thread_cond_timedwait(channel->cond_empty, channel->lock, tms);
5871cb0ef41Sopenharmony_ci      }
5881cb0ef41Sopenharmony_ci    }
5891cb0ef41Sopenharmony_ci  }
5901cb0ef41Sopenharmony_ci  ares__thread_mutex_unlock(channel->lock);
5911cb0ef41Sopenharmony_ci  return status;
5921cb0ef41Sopenharmony_ci}
5931cb0ef41Sopenharmony_ci
5941cb0ef41Sopenharmony_civoid ares_queue_notify_empty(ares_channel_t *channel)
5951cb0ef41Sopenharmony_ci{
5961cb0ef41Sopenharmony_ci  if (channel == NULL) {
5971cb0ef41Sopenharmony_ci    return;
5981cb0ef41Sopenharmony_ci  }
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_ci  /* We are guaranteed to be holding a channel lock already */
6011cb0ef41Sopenharmony_ci  if (ares__llist_len(channel->all_queries)) {
6021cb0ef41Sopenharmony_ci    return;
6031cb0ef41Sopenharmony_ci  }
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  /* Notify all waiters of the conditional */
6061cb0ef41Sopenharmony_ci  ares__thread_cond_broadcast(channel->cond_empty);
6071cb0ef41Sopenharmony_ci}
608