• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

c-ares / c-ares / 12749958868

13 Jan 2025 03:00PM UTC coverage: 91.502% (+0.004%) from 91.498%
12749958868

Pull #960

github

web-flow
Merge e617dd6da into 0518d404e
Pull Request #960: [port] Windows XP: try to support threading and event subsystems

0 of 3 new or added lines in 1 file covered. (0.0%)

3 existing lines in 3 files now uncovered.

22406 of 24487 relevant lines covered (91.5%)

12070.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.27
/src/lib/util/ares_threads.c
1
/* MIT License
2
 *
3
 * Copyright (c) 2023 Brad House
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining a copy
6
 * of this software and associated documentation files (the "Software"), to deal
7
 * in the Software without restriction, including without limitation the rights
8
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the Software is
10
 * furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice (including the next
13
 * paragraph) shall be included in all copies or substantial portions of the
14
 * Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 *
24
 * SPDX-License-Identifier: MIT
25
 */
26
#include "ares_private.h"
27
#ifdef HAVE_STDINT_H
28
#  include <stdint.h>
29
#endif
30

31
#ifdef CARES_THREADS
32
#  ifdef _WIN32
33

34
struct ares_thread_mutex {
35
  CRITICAL_SECTION mutex;
36
};
37

38
ares_thread_mutex_t *ares_thread_mutex_create(void)
39
{
40
  ares_thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
41
  if (mut == NULL) {
42
    return NULL;
43
  }
44

45
  InitializeCriticalSection(&mut->mutex);
46
  return mut;
47
}
48

49
void ares_thread_mutex_destroy(ares_thread_mutex_t *mut)
50
{
51
  if (mut == NULL) {
52
    return;
53
  }
54
  DeleteCriticalSection(&mut->mutex);
55
  ares_free(mut);
56
}
57

58
void ares_thread_mutex_lock(ares_thread_mutex_t *mut)
59
{
60
  if (mut == NULL) {
61
    return;
62
  }
63
  EnterCriticalSection(&mut->mutex);
64
}
65

66
void ares_thread_mutex_unlock(ares_thread_mutex_t *mut)
67
{
68
  if (mut == NULL) {
69
    return;
70
  }
71
  LeaveCriticalSection(&mut->mutex);
72
}
73

74
#    if _WIN32_WINNT >= 0x0600 /* Vista */
75

76
struct ares_thread_cond {
77
  CONDITION_VARIABLE cond;
78
};
79

80
ares_thread_cond_t *ares_thread_cond_create(void)
81
{
82
  ares_thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
83
  if (cond == NULL) {
84
    return NULL;
85
  }
86
  InitializeConditionVariable(&cond->cond);
87
  return cond;
88
}
89

90
void ares_thread_cond_destroy(ares_thread_cond_t *cond)
91
{
92
  if (cond == NULL) {
93
    return;
94
  }
95
  ares_free(cond);
96
}
97

98
void ares_thread_cond_signal(ares_thread_cond_t *cond)
99
{
100
  if (cond == NULL) {
101
    return;
102
  }
103
  WakeConditionVariable(&cond->cond);
104
}
105

106
void ares_thread_cond_broadcast(ares_thread_cond_t *cond)
107
{
108
  if (cond == NULL) {
109
    return;
110
  }
111
  WakeAllConditionVariable(&cond->cond);
112
}
113

114
ares_status_t ares_thread_cond_wait(ares_thread_cond_t  *cond,
115
                                    ares_thread_mutex_t *mut)
116
{
117
  if (cond == NULL || mut == NULL) {
118
    return ARES_EFORMERR;
119
  }
120

121
  SleepConditionVariableCS(&cond->cond, &mut->mutex, INFINITE);
122
  return ARES_SUCCESS;
123
}
124

125
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t  *cond,
126
                                         ares_thread_mutex_t *mut,
127
                                         size_t               timeout_ms)
128
{
129
  DWORD tout;
130

131
  if (cond == NULL || mut == NULL) {
132
    return ARES_EFORMERR;
133
  }
134

135
  if (timeout_ms == SIZE_MAX) {
136
    tout = INFINITE;
137
  } else {
138
    tout = (DWORD)timeout_ms;
139
  }
140

141
  if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, tout)) {
142
    return ARES_ETIMEOUT;
143
  }
144

145
  return ARES_SUCCESS;
146
}
147

148
#    else
149

150
typedef enum {
151
  ARES_W32_COND_SIGNAL    = 0,
152
  ARES_W32_COND_BROADCAST,
153
  ARES_W32_COND_EVMAX,
154
  ARES_W32_COND_NONE = ARES_W32_COND_EVMAX
155
} ares_w32_cond_event_t;
156

157
struct ares_thread_cond {
158
  HANDLE                events[2];
159
  HANDLE                gate;
160
  CRITICAL_SECTION      mutex;
161
  size_t                waiters;
162
  ares_w32_cond_event_t event;
163
};
164

165
ares_thread_cond_t *ares_thread_cond_create(void)
166
{
167
  ares_thread_cond_t *cond;
168

169
  cond = ares_alloc_zero(sizeof(*cond));
170
  if (cond == NULL) {
171
    return NULL;
172
  }
173

174
  cond->events[ARES_W32_COND_SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
175
  if (cond->events[ARES_W32_COND_SIGNAL] == NULL) {
176
    goto fail;
177
  }
178

179
  cond->events[ARES_W32_COND_BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
180
  if (cond->events[ARES_W32_COND_BROADCAST] == NULL) {
181
    goto fail;
182
  }
183

184
  /* Use a semaphore as a gate so we don't lose signals */
185
  cond->gate = CreateSemaphore(NULL, 1, 1, NULL);
186
  if (cond->gate == NULL) {
187
    goto fail;
188
  }
189

190
  InitializeCriticalSection(&cond->mutex);
191
  cond->waiters = 0;
192
  cond->event   = ARES_W32_COND_NONE;
193

194
  return cond;
195

196
fail:
197
  ares_thread_cond_destroy(cond);
198
  return NULL;
199
}
200

201
void ares_thread_cond_destroy(ares_thread_cond_t *cond)
202
{
203
  if (cond == NULL)
204
    return;
205

206
  if (cond->events[ARES_W32_COND_SIGNAL]) {
207
    CloseHandle(cond->events[ARES_W32_COND_SIGNAL]);
208
  }
209
  if (cond->events[ARES_W32_COND_BROADCAST]) {
210
    CloseHandle(cond->events[ARES_W32_COND_BROADCAST]);
211
  }
212
  if (cond->gate) {
213
    CloseHandle(cond->gate);
214
  }
215
  DeleteCriticalSection(&cond->mutex);
216

217
  ares_free(cond);
218
}
219

220
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t  *cond,
221
                                         ares_thread_mutex_t *mut,
222
                                         size_t               timeout_ms)
223
{
224
  DWORD rv;
225
  DWORD wMilliseconds;
226

227
  if (cond == NULL || mutex == NULL) {
228
    return ARES_EFORMERR;
229
  }
230

231
  /* We may only enter when no wakeups active this will prevent the lost
232
   * wakeup */
233
  WaitForSingleObject(cond->gate, INFINITE);
234

235
  EnterCriticalSection(&cond->mutex);
236
  /* count waiters passing through */
237
  cond->waiters++;
238
  LeaveCriticalSection(&cond->mutex);
239

240
  /* Open Gate */
241
  ReleaseSemaphore(cond->gate, 1, NULL);
242

243
  /* Release passed in mutex */
244
  ares_thread_mutex_unlock(mut);
245

246
  if (timeout_ms == SIZE_MAX) {
247
    dwMilliseconds = INFINITE;
248
  } else {
249
    dwMilliseconds = (DWORD)timeout_ms;
250
  }
251
  rv = WaitForMultipleObjects(ARES_W32_COND_EVMAX, cond->events, FALSE,
252
                              dwMilliseconds);
253

254
  /* We go into a critical section to make sure cond->waiters isn't checked
255
   * while we decrement.  This is especially important for a timeout since the
256
   * gate may not be closed. We need to check to see if a broadcast/signal was
257
   * pending as this thread could have been preempted prior to
258
   * EnterCriticalSection but after WaitForMultipleObjects() so we may be
259
   * responsible for reseting the event and closing the gate */
260
  EnterCriticalSection(&cond->mutex);
261
  cond->waiters--;
262

263
  if (cond->event != ARES_W32_COND_NONE && cond->waiters == 0) {
264
    /* Last waiter needs to reset the event on(as a broadcast event is not
265
     * automatic) and also re-open the gate */
266
    if (cond->event == ARES_W32_COND_BROADCAST)
267
      ResetEvent(cond->events[ARES_W32_COND_BROADCAST]);
268

269
    /* Open Gate (closed by ares_thread_cond_broadcast()) since there are no
270
     * more waiters for the event */
271
    ReleaseSemaphore(cond->gate, 1, NULL);
272
    cond->event = ARES_W32_COND_NONE;
273
  } else if (retval == WAIT_OBJECT_0 + ARES_W32_COND_SIGNAL) {
274
    /* If specifically, this thread was signalled and there are more waiting,
275
     * re-open the gate and reset the event */
276
    ReleaseSemaphore(cond->gate, 1, NULL);
277
    cond->event = ARES_W32_COND_NONE;
278
  } else {
279
    /* This could be a standard timeout with more waiters, don't do anything */
280
  }
281
  LeaveCriticalSection(&cond->mutex);
282

283
  /* re-lock the passed in mutex */
284
  ares_thread_mutex_lock(mut);
285

286
  if (retval == WAIT_TIMEOUT) {
287
    return ARES_ETIMEOUT;
288
  }
289

290
  return ARES_SUCCESS;
291
}
292

293
ares_status_t ares_thread_cond_wait(ares_thread_cond_t  *cond,
294
                                    ares_thread_mutex_t *mut)
295
{
296
  return ares_thread_cond_timedwait(cond, mut, SIZE_MAX);
297
}
298

299
void ares_thread_cond_broadcast(ares_thread_cond_t *cond);
300
{
301
  if (cond == NULL)
302
    return;
303

304
  /* close gate to prevent more waiters while broadcasting */
305
  WaitForSingleObject(cond->gate, INFINITE);
306

307
  /* If there are waiters, send a broadcast event,
308
   * otherwise, just reopen the gate */
309
  EnterCriticalSection(&cond->mutex);
310

311
  cond->event = ARES_W32_COND_BROADCAST;
312
  if (cond->waiters) {
313
    /* wake all waiters */
314
    SetEvent(cond->events[ARES_W32_COND_BROADCAST]);
315
  } else {
316
    /* if no waiters just reopen gate */
317
    ReleaseSemaphore(cond->gate, 1, NULL);
318
  }
319

320
  LeaveCriticalSection(&cond->mutex);
321
}
322

323
void ares_thread_cond_signal(ares_thread_cond_t *cond);
324
{
325
  if (cond == NULL)
326
    return;
327

328
  /* close gate to prevent more waiters while signalling */
329
  WaitForSingleObject(cond->gate, INFINITE);
330

331

332
  EnterCriticalSection(&cond->mutex);
333
  cond->event = ARES_W32_COND_SIGNAL;
334
  if (cond->waiters) {
335
    /* wake one waiter */
336
    SetEvent(cond->events[ARES_W32_COND_SIGNAL]);
337
  } else {
338
    /* no waiters, just reopen the gate */
339
    ReleaseSemaphore(cond->gate, 1, NULL);
340
  }
341
  LeaveCriticalSection(&cond->mutex);
342
}
343

344
#    endif
345

346
struct ares_thread {
347
  HANDLE thread;
348
  DWORD  id;
349

350
  void *(*func)(void *arg);
351
  void *arg;
352
  void *rv;
353
};
354

355
/* Wrap for pthread compatibility */
356
static DWORD WINAPI ares_thread_func(LPVOID lpParameter)
357
{
358
  ares_thread_t *thread = lpParameter;
359

360
  thread->rv = thread->func(thread->arg);
361
  return 0;
362
}
363

364
ares_status_t ares_thread_create(ares_thread_t    **thread,
365
                                 ares_thread_func_t func, void *arg)
366
{
367
  ares_thread_t *thr = NULL;
368

369
  if (func == NULL || thread == NULL) {
370
    return ARES_EFORMERR;
371
  }
372

373
  thr = ares_malloc_zero(sizeof(*thr));
374
  if (thr == NULL) {
375
    return ARES_ENOMEM;
376
  }
377

378
  thr->func   = func;
379
  thr->arg    = arg;
380
  thr->thread = CreateThread(NULL, 0, ares_thread_func, thr, 0, &thr->id);
381
  if (thr->thread == NULL) {
382
    ares_free(thr);
383
    return ARES_ESERVFAIL;
384
  }
385

386
  *thread = thr;
387
  return ARES_SUCCESS;
388
}
389

390
ares_status_t ares_thread_join(ares_thread_t *thread, void **rv)
391
{
392
  ares_status_t status = ARES_SUCCESS;
393

394
  if (thread == NULL) {
395
    return ARES_EFORMERR;
396
  }
397

398
  if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) {
399
    status = ARES_ENOTFOUND;
400
  } else {
401
    CloseHandle(thread->thread);
402
  }
403

404
  if (status == ARES_SUCCESS && rv != NULL) {
405
    *rv = thread->rv;
406
  }
407
  ares_free(thread);
408

409
  return status;
410
}
411

412
#  else /* !WIN32 == PTHREAD */
413
#    include <pthread.h>
414

415
/* for clock_gettime() */
416
#    ifdef HAVE_TIME_H
417
#      include <time.h>
418
#    endif
419

420
/* for gettimeofday() */
421
#    ifdef HAVE_SYS_TIME_H
422
#      include <sys/time.h>
423
#    endif
424

425
struct ares_thread_mutex {
426
  pthread_mutex_t mutex;
427
};
428

429
ares_thread_mutex_t *ares_thread_mutex_create(void)
1,634✔
430
{
431
  pthread_mutexattr_t  attr;
432
  ares_thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
1,634✔
433
  if (mut == NULL) {
1,634✔
434
    return NULL;
4✔
435
  }
436

437
  if (pthread_mutexattr_init(&attr) != 0) {
1,630✔
438
    ares_free(mut); /* LCOV_EXCL_LINE: UntestablePath */
439
    return NULL;    /* LCOV_EXCL_LINE: UntestablePath */
440
  }
441

442
  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
1,630✔
443
    goto fail; /* LCOV_EXCL_LINE: UntestablePath */
444
  }
445

446
  if (pthread_mutex_init(&mut->mutex, &attr) != 0) {
1,630✔
447
    goto fail; /* LCOV_EXCL_LINE: UntestablePath */
448
  }
449

450
  pthread_mutexattr_destroy(&attr);
1,630✔
451
  return mut;
1,630✔
452

453
/* LCOV_EXCL_START: UntestablePath */
454
fail:
455
  pthread_mutexattr_destroy(&attr);
456
  ares_free(mut);
457
  return NULL;
458
  /* LCOV_EXCL_STOP */
459
}
460

461
void ares_thread_mutex_destroy(ares_thread_mutex_t *mut)
1,641✔
462
{
463
  if (mut == NULL) {
1,641✔
464
    return;
12✔
465
  }
466
  pthread_mutex_destroy(&mut->mutex);
1,629✔
467
  ares_free(mut);
1,629✔
468
}
469

470
void ares_thread_mutex_lock(ares_thread_mutex_t *mut)
93,855✔
471
{
472
  if (mut == NULL) {
93,855✔
473
    return;
16✔
474
  }
475
  pthread_mutex_lock(&mut->mutex);
93,839✔
476
}
477

478
void ares_thread_mutex_unlock(ares_thread_mutex_t *mut)
93,856✔
479
{
480
  if (mut == NULL) {
93,856✔
481
    return;
16✔
482
  }
483
  pthread_mutex_unlock(&mut->mutex);
93,840✔
484
}
485

486
struct ares_thread_cond {
487
  pthread_cond_t cond;
488
};
489

490
ares_thread_cond_t *ares_thread_cond_create(void)
1,108✔
491
{
492
  ares_thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
1,108✔
493
  if (cond == NULL) {
1,108✔
494
    return NULL;
4✔
495
  }
496
  pthread_cond_init(&cond->cond, NULL);
1,104✔
497
  return cond;
1,104✔
498
}
499

500
void ares_thread_cond_destroy(ares_thread_cond_t *cond)
1,119✔
501
{
502
  if (cond == NULL) {
1,119✔
503
    return;
16✔
504
  }
505
  pthread_cond_destroy(&cond->cond);
1,103✔
506
  ares_free(cond);
1,103✔
507
}
508

509
void ares_thread_cond_signal(ares_thread_cond_t *cond)
×
510
{
511
  if (cond == NULL) {
×
512
    return;
×
513
  }
514
  pthread_cond_signal(&cond->cond);
×
515
}
516

517
void ares_thread_cond_broadcast(ares_thread_cond_t *cond)
2,317✔
518
{
519
  if (cond == NULL) {
2,317✔
520
    return;
8✔
521
  }
522
  pthread_cond_broadcast(&cond->cond);
2,309✔
523
}
524

525
ares_status_t ares_thread_cond_wait(ares_thread_cond_t  *cond,
×
526
                                    ares_thread_mutex_t *mut)
527
{
528
  if (cond == NULL || mut == NULL) {
×
529
    return ARES_EFORMERR;
×
530
  }
531

532
  pthread_cond_wait(&cond->cond, &mut->mutex);
×
533
  return ARES_SUCCESS;
×
534
}
535

NEW
536
static void ares_timespec_timeout(struct timespec *ts, size_t add_ms)
×
537
{
538
#    if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
539
  clock_gettime(CLOCK_REALTIME, ts);
540
#    elif defined(HAVE_GETTIMEOFDAY)
541
  struct timeval tv;
542
  gettimeofday(&tv, NULL);
×
543
  ts->tv_sec  = tv.tv_sec;
×
544
  ts->tv_nsec = tv.tv_usec * 1000;
×
545
#    else
546
#      error cannot determine current system time
547
#    endif
548

549
  ts->tv_sec  += (time_t)(add_ms / 1000);
×
550
  ts->tv_nsec += (long)((add_ms % 1000) * 1000000);
×
551

552
  /* Normalize if needed */
553
  if (ts->tv_nsec >= 1000000000) {
×
554
    ts->tv_sec  += ts->tv_nsec / 1000000000;
×
555
    ts->tv_nsec %= 1000000000;
×
556
  }
557
}
×
558

559
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t  *cond,
×
560
                                         ares_thread_mutex_t *mut,
561
                                         size_t               timeout_ms)
562
{
563
  struct timespec ts;
564

565
  if (cond == NULL || mut == NULL) {
×
566
    return ARES_EFORMERR;
×
567
  }
568

NEW
569
  if (timeout_ms == SIZE_MAX) {
×
NEW
570
    return ares_thread_cond_wait(cond, mut);
×
571
  }
572

UNCOV
573
  ares_timespec_timeout(&ts, timeout_ms);
×
574

575
  if (pthread_cond_timedwait(&cond->cond, &mut->mutex, &ts) != 0) {
×
576
    return ARES_ETIMEOUT;
×
577
  }
578

579
  return ARES_SUCCESS;
×
580
}
581

582
struct ares_thread {
583
  pthread_t thread;
584
};
585

586
ares_status_t ares_thread_create(ares_thread_t    **thread,
582✔
587
                                 ares_thread_func_t func, void *arg)
588
{
589
  ares_thread_t *thr = NULL;
582✔
590

591
  if (func == NULL || thread == NULL) {
582✔
592
    return ARES_EFORMERR;
×
593
  }
594

595
  thr = ares_malloc_zero(sizeof(*thr));
582✔
596
  if (thr == NULL) {
582✔
597
    return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
598
  }
599
  if (pthread_create(&thr->thread, NULL, func, arg) != 0) {
582✔
600
    ares_free(thr);        /* LCOV_EXCL_LINE: UntestablePath */
601
    return ARES_ESERVFAIL; /* LCOV_EXCL_LINE: UntestablePath */
602
  }
603

604
  *thread = thr;
582✔
605
  return ARES_SUCCESS;
582✔
606
}
607

608
ares_status_t ares_thread_join(ares_thread_t *thread, void **rv)
582✔
609
{
610
  void         *ret    = NULL;
582✔
611
  ares_status_t status = ARES_SUCCESS;
582✔
612

613
  if (thread == NULL) {
582✔
614
    return ARES_EFORMERR;
×
615
  }
616

617
  if (pthread_join(thread->thread, &ret) != 0) {
582✔
618
    status = ARES_ENOTFOUND;
×
619
  }
620
  ares_free(thread);
582✔
621

622
  if (status == ARES_SUCCESS && rv != NULL) {
582✔
623
    *rv = ret;
582✔
624
  }
625
  return status;
582✔
626
}
627

628
#  endif
629

630
ares_bool_t ares_threadsafety(void)
1,694✔
631
{
632
  return ARES_TRUE;
1,694✔
633
}
634

635
#else /* !CARES_THREADS */
636

637
/* NoOp */
638
ares_thread_mutex_t *ares_thread_mutex_create(void)
639
{
640
  return NULL;
641
}
642

643
void ares_thread_mutex_destroy(ares_thread_mutex_t *mut)
644
{
645
  (void)mut;
646
}
647

648
void ares_thread_mutex_lock(ares_thread_mutex_t *mut)
649
{
650
  (void)mut;
651
}
652

653
void ares_thread_mutex_unlock(ares_thread_mutex_t *mut)
654
{
655
  (void)mut;
656
}
657

658
ares_thread_cond_t *ares_thread_cond_create(void)
659
{
660
  return NULL;
661
}
662

663
void ares_thread_cond_destroy(ares_thread_cond_t *cond)
664
{
665
  (void)cond;
666
}
667

668
void ares_thread_cond_signal(ares_thread_cond_t *cond)
669
{
670
  (void)cond;
671
}
672

673
void ares_thread_cond_broadcast(ares_thread_cond_t *cond)
674
{
675
  (void)cond;
676
}
677

678
ares_status_t ares_thread_cond_wait(ares_thread_cond_t  *cond,
679
                                    ares_thread_mutex_t *mut)
680
{
681
  (void)cond;
682
  (void)mut;
683
  return ARES_ENOTIMP;
684
}
685

686
ares_status_t ares_thread_cond_timedwait(ares_thread_cond_t  *cond,
687
                                         ares_thread_mutex_t *mut,
688
                                         size_t               timeout_ms)
689
{
690
  (void)cond;
691
  (void)mut;
692
  (void)timeout_ms;
693
  return ARES_ENOTIMP;
694
}
695

696
ares_status_t ares_thread_create(ares_thread_t    **thread,
697
                                 ares_thread_func_t func, void *arg)
698
{
699
  (void)thread;
700
  (void)func;
701
  (void)arg;
702
  return ARES_ENOTIMP;
703
}
704

705
ares_status_t ares_thread_join(ares_thread_t *thread, void **rv)
706
{
707
  (void)thread;
708
  (void)rv;
709
  return ARES_ENOTIMP;
710
}
711

712
ares_bool_t ares_threadsafety(void)
713
{
714
  return ARES_FALSE;
715
}
716
#endif
717

718

719
ares_status_t ares_channel_threading_init(ares_channel_t *channel)
1,112✔
720
{
721
  ares_status_t status = ARES_SUCCESS;
1,112✔
722

723
  /* Threading is optional! */
724
  if (!ares_threadsafety()) {
1,112✔
725
    return ARES_SUCCESS;
×
726
  }
727

728
  channel->lock = ares_thread_mutex_create();
1,112✔
729
  if (channel->lock == NULL) {
1,112✔
730
    status = ARES_ENOMEM;
4✔
731
    goto done;
4✔
732
  }
733

734
  channel->cond_empty = ares_thread_cond_create();
1,108✔
735
  if (channel->cond_empty == NULL) {
1,108✔
736
    status = ARES_ENOMEM;
4✔
737
    goto done;
4✔
738
  }
739

740
done:
1,104✔
741
  if (status != ARES_SUCCESS) {
1,112✔
742
    ares_channel_threading_destroy(channel);
8✔
743
  }
744
  return status;
1,112✔
745
}
746

747
void ares_channel_threading_destroy(ares_channel_t *channel)
1,119✔
748
{
749
  ares_thread_mutex_destroy(channel->lock);
1,119✔
750
  channel->lock = NULL;
1,119✔
751
  ares_thread_cond_destroy(channel->cond_empty);
1,119✔
752
  channel->cond_empty = NULL;
1,119✔
753
}
1,119✔
754

755
void ares_channel_lock(const ares_channel_t *channel)
73,896✔
756
{
757
  ares_thread_mutex_lock(channel->lock);
73,896✔
758
}
73,896✔
759

760
void ares_channel_unlock(const ares_channel_t *channel)
73,896✔
761
{
762
  ares_thread_mutex_unlock(channel->lock);
73,896✔
763
}
73,896✔
764

765
/* Must not be holding a channel lock already, public function only */
766
ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms)
×
767
{
768
  ares_status_t  status = ARES_SUCCESS;
×
769
  ares_timeval_t tout;
770

771
  if (!ares_threadsafety()) {
×
772
    return ARES_ENOTIMP;
×
773
  }
774

775
  if (channel == NULL) {
×
776
    return ARES_EFORMERR;
×
777
  }
778

779
  if (timeout_ms >= 0) {
×
780
    ares_tvnow(&tout);
×
781
    tout.sec  += (ares_int64_t)(timeout_ms / 1000);
×
782
    tout.usec += (unsigned int)(timeout_ms % 1000) * 1000;
×
783
  }
784

785
  ares_thread_mutex_lock(channel->lock);
×
786
  while (ares_llist_len(channel->all_queries)) {
×
787
    if (timeout_ms < 0) {
×
788
      ares_thread_cond_wait(channel->cond_empty, channel->lock);
×
789
    } else {
790
      ares_timeval_t tv_remaining;
791
      ares_timeval_t tv_now;
792
      unsigned long  tms;
793

794
      ares_tvnow(&tv_now);
×
795
      ares_timeval_remaining(&tv_remaining, &tv_now, &tout);
×
796
      tms =
×
797
        (unsigned long)((tv_remaining.sec * 1000) + (tv_remaining.usec / 1000));
×
798
      if (tms == 0) {
×
799
        status = ARES_ETIMEOUT;
×
800
      } else {
801
        status =
802
          ares_thread_cond_timedwait(channel->cond_empty, channel->lock, tms);
×
803
      }
804

805
      /* If there was a timeout, don't loop.  Otherwise, make sure this wasn't
806
       * a spurious wakeup by looping and checking the condition. */
807
      if (status == ARES_ETIMEOUT) {
×
808
        break;
×
809
      }
810
    }
811
  }
812
  ares_thread_mutex_unlock(channel->lock);
×
813
  return status;
×
814
}
815

816
void ares_queue_notify_empty(ares_channel_t *channel)
3,437✔
817
{
818
  if (channel == NULL) {
3,437✔
819
    return;
×
820
  }
821

822
  /* We are guaranteed to be holding a channel lock already */
823
  if (ares_llist_len(channel->all_queries)) {
3,437✔
824
    return;
1,120✔
825
  }
826

827
  /* Notify all waiters of the conditional */
828
  ares_thread_cond_broadcast(channel->cond_empty);
2,317✔
829
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc