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_setup.h"
27 #include "ares.h"
28 #include "ares_private.h"
29
30 #ifdef CARES_THREADS
31 # ifdef _WIN32
32
33 struct ares__thread_mutex {
34 CRITICAL_SECTION mutex;
35 };
36
ares__thread_mutex_create(void)37 ares__thread_mutex_t *ares__thread_mutex_create(void)
38 {
39 ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
40 if (mut == NULL) {
41 return NULL;
42 }
43
44 InitializeCriticalSection(&mut->mutex);
45 return mut;
46 }
47
ares__thread_mutex_destroy(ares__thread_mutex_t * mut)48 void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
49 {
50 if (mut == NULL) {
51 return;
52 }
53 DeleteCriticalSection(&mut->mutex);
54 ares_free(mut);
55 }
56
ares__thread_mutex_lock(ares__thread_mutex_t * mut)57 void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
58 {
59 if (mut == NULL) {
60 return;
61 }
62 EnterCriticalSection(&mut->mutex);
63 }
64
ares__thread_mutex_unlock(ares__thread_mutex_t * mut)65 void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
66 {
67 if (mut == NULL) {
68 return;
69 }
70 LeaveCriticalSection(&mut->mutex);
71 }
72
73 struct ares__thread_cond {
74 CONDITION_VARIABLE cond;
75 };
76
ares__thread_cond_create(void)77 ares__thread_cond_t *ares__thread_cond_create(void)
78 {
79 ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
80 if (cond == NULL) {
81 return NULL;
82 }
83 InitializeConditionVariable(&cond->cond);
84 return cond;
85 }
86
ares__thread_cond_destroy(ares__thread_cond_t * cond)87 void ares__thread_cond_destroy(ares__thread_cond_t *cond)
88 {
89 if (cond == NULL) {
90 return;
91 }
92 ares_free(cond);
93 }
94
ares__thread_cond_signal(ares__thread_cond_t * cond)95 void ares__thread_cond_signal(ares__thread_cond_t *cond)
96 {
97 if (cond == NULL) {
98 return;
99 }
100 WakeConditionVariable(&cond->cond);
101 }
102
ares__thread_cond_broadcast(ares__thread_cond_t * cond)103 void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
104 {
105 if (cond == NULL) {
106 return;
107 }
108 WakeAllConditionVariable(&cond->cond);
109 }
110
ares__thread_cond_wait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut)111 ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
112 ares__thread_mutex_t *mut)
113 {
114 if (cond == NULL || mut == NULL) {
115 return ARES_EFORMERR;
116 }
117
118 SleepConditionVariableCS(&cond->cond, &mut->mutex, INFINITE);
119 return ARES_SUCCESS;
120 }
121
ares__thread_cond_timedwait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut,unsigned long timeout_ms)122 ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
123 ares__thread_mutex_t *mut,
124 unsigned long timeout_ms)
125 {
126 if (cond == NULL || mut == NULL) {
127 return ARES_EFORMERR;
128 }
129
130 if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, timeout_ms)) {
131 return ARES_ETIMEOUT;
132 }
133
134 return ARES_SUCCESS;
135 }
136
137 struct ares__thread {
138 HANDLE thread;
139 DWORD id;
140
141 void *(*func)(void *arg);
142 void *arg;
143 void *rv;
144 };
145
146 /* Wrap for pthread compatibility */
ares__thread_func(LPVOID lpParameter)147 static DWORD WINAPI ares__thread_func(LPVOID lpParameter)
148 {
149 ares__thread_t *thread = lpParameter;
150
151 thread->rv = thread->func(thread->arg);
152 return 0;
153 }
154
ares__thread_create(ares__thread_t ** thread,ares__thread_func_t func,void * arg)155 ares_status_t ares__thread_create(ares__thread_t **thread,
156 ares__thread_func_t func, void *arg)
157 {
158 ares__thread_t *thr = NULL;
159
160 if (func == NULL || thread == NULL) {
161 return ARES_EFORMERR;
162 }
163
164 thr = ares_malloc_zero(sizeof(*thr));
165 if (thr == NULL) {
166 return ARES_ENOMEM;
167 }
168
169 thr->func = func;
170 thr->arg = arg;
171 thr->thread = CreateThread(NULL, 0, ares__thread_func, thr, 0, &thr->id);
172 if (thr->thread == NULL) {
173 ares_free(thr);
174 return ARES_ESERVFAIL;
175 }
176
177 *thread = thr;
178 return ARES_SUCCESS;
179 }
180
ares__thread_join(ares__thread_t * thread,void ** rv)181 ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
182 {
183 ares_status_t status = ARES_SUCCESS;
184
185 if (thread == NULL) {
186 return ARES_EFORMERR;
187 }
188
189 if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) {
190 status = ARES_ENOTFOUND;
191 } else {
192 CloseHandle(thread->thread);
193 }
194
195 if (status == ARES_SUCCESS && rv != NULL) {
196 *rv = thread->rv;
197 }
198 ares_free(thread);
199
200 return status;
201 }
202
203 # else /* !WIN32 == PTHREAD */
204 # include <pthread.h>
205
206 /* for clock_gettime() */
207 # ifdef HAVE_TIME_H
208 # include <time.h>
209 # endif
210
211 /* for gettimeofday() */
212 # ifdef HAVE_SYS_TIME_H
213 # include <sys/time.h>
214 # endif
215
216 struct ares__thread_mutex {
217 pthread_mutex_t mutex;
218 };
219
ares__thread_mutex_create(void)220 ares__thread_mutex_t *ares__thread_mutex_create(void)
221 {
222 pthread_mutexattr_t attr;
223 ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
224 if (mut == NULL) {
225 return NULL;
226 }
227
228 if (pthread_mutexattr_init(&attr) != 0) {
229 ares_free(mut);
230 return NULL;
231 }
232
233 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
234 goto fail;
235 }
236
237 if (pthread_mutex_init(&mut->mutex, &attr) != 0) {
238 goto fail;
239 }
240
241 pthread_mutexattr_destroy(&attr);
242 return mut;
243
244 fail:
245 pthread_mutexattr_destroy(&attr);
246 ares_free(mut);
247 return NULL;
248 }
249
ares__thread_mutex_destroy(ares__thread_mutex_t * mut)250 void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
251 {
252 if (mut == NULL) {
253 return;
254 }
255 pthread_mutex_destroy(&mut->mutex);
256 ares_free(mut);
257 }
258
ares__thread_mutex_lock(ares__thread_mutex_t * mut)259 void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
260 {
261 if (mut == NULL) {
262 return;
263 }
264 pthread_mutex_lock(&mut->mutex);
265 }
266
ares__thread_mutex_unlock(ares__thread_mutex_t * mut)267 void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
268 {
269 if (mut == NULL) {
270 return;
271 }
272 pthread_mutex_unlock(&mut->mutex);
273 }
274
275 struct ares__thread_cond {
276 pthread_cond_t cond;
277 };
278
ares__thread_cond_create(void)279 ares__thread_cond_t *ares__thread_cond_create(void)
280 {
281 ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
282 if (cond == NULL) {
283 return NULL;
284 }
285 pthread_cond_init(&cond->cond, NULL);
286 return cond;
287 }
288
ares__thread_cond_destroy(ares__thread_cond_t * cond)289 void ares__thread_cond_destroy(ares__thread_cond_t *cond)
290 {
291 if (cond == NULL) {
292 return;
293 }
294 pthread_cond_destroy(&cond->cond);
295 ares_free(cond);
296 }
297
ares__thread_cond_signal(ares__thread_cond_t * cond)298 void ares__thread_cond_signal(ares__thread_cond_t *cond)
299 {
300 if (cond == NULL) {
301 return;
302 }
303 pthread_cond_signal(&cond->cond);
304 }
305
ares__thread_cond_broadcast(ares__thread_cond_t * cond)306 void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
307 {
308 if (cond == NULL) {
309 return;
310 }
311 pthread_cond_broadcast(&cond->cond);
312 }
313
ares__thread_cond_wait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut)314 ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
315 ares__thread_mutex_t *mut)
316 {
317 if (cond == NULL || mut == NULL) {
318 return ARES_EFORMERR;
319 }
320
321 pthread_cond_wait(&cond->cond, &mut->mutex);
322 return ARES_SUCCESS;
323 }
324
ares__timespec_timeout(struct timespec * ts,unsigned long add_ms)325 static void ares__timespec_timeout(struct timespec *ts, unsigned long add_ms)
326 {
327 # if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
328 clock_gettime(CLOCK_REALTIME, ts);
329 # elif defined(HAVE_GETTIMEOFDAY)
330 struct timeval tv;
331 gettimeofday(&tv, NULL);
332 ts->tv_sec = tv.tv_sec;
333 ts->tv_nsec = tv.tv_usec * 1000;
334 # else
335 # error cannot determine current system time
336 # endif
337
338 ts->tv_sec += add_ms / 1000;
339 ts->tv_nsec += (add_ms % 1000) * 1000000;
340
341 /* Normalize if needed */
342 if (ts->tv_nsec >= 1000000000) {
343 ts->tv_sec += ts->tv_nsec / 1000000000;
344 ts->tv_nsec %= 1000000000;
345 }
346 }
347
ares__thread_cond_timedwait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut,unsigned long timeout_ms)348 ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
349 ares__thread_mutex_t *mut,
350 unsigned long timeout_ms)
351 {
352 struct timespec ts;
353
354 if (cond == NULL || mut == NULL) {
355 return ARES_EFORMERR;
356 }
357
358 ares__timespec_timeout(&ts, timeout_ms);
359
360 if (pthread_cond_timedwait(&cond->cond, &mut->mutex, &ts) != 0) {
361 return ARES_ETIMEOUT;
362 }
363
364 return ARES_SUCCESS;
365 }
366
367 struct ares__thread {
368 pthread_t thread;
369 };
370
ares__thread_create(ares__thread_t ** thread,ares__thread_func_t func,void * arg)371 ares_status_t ares__thread_create(ares__thread_t **thread,
372 ares__thread_func_t func, void *arg)
373 {
374 ares__thread_t *thr = NULL;
375
376 if (func == NULL || thread == NULL) {
377 return ARES_EFORMERR;
378 }
379
380 thr = ares_malloc_zero(sizeof(*thr));
381 if (thr == NULL) {
382 return ARES_ENOMEM;
383 }
384 if (pthread_create(&thr->thread, NULL, func, arg) != 0) {
385 ares_free(thr);
386 return ARES_ESERVFAIL;
387 }
388
389 *thread = thr;
390 return ARES_SUCCESS;
391 }
392
ares__thread_join(ares__thread_t * thread,void ** rv)393 ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
394 {
395 void *ret = NULL;
396 ares_status_t status = ARES_SUCCESS;
397
398 if (thread == NULL) {
399 return ARES_EFORMERR;
400 }
401
402 if (pthread_join(thread->thread, &ret) != 0) {
403 status = ARES_ENOTFOUND;
404 }
405 ares_free(thread);
406
407 if (status == ARES_SUCCESS && rv != NULL) {
408 *rv = ret;
409 }
410 return status;
411 }
412
413 # endif
414
ares_threadsafety(void)415 ares_bool_t ares_threadsafety(void)
416 {
417 return ARES_TRUE;
418 }
419
420 #else /* !CARES_THREADS */
421
422 /* NoOp */
ares__thread_mutex_create(void)423 ares__thread_mutex_t *ares__thread_mutex_create(void)
424 {
425 return NULL;
426 }
427
ares__thread_mutex_destroy(ares__thread_mutex_t * mut)428 void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
429 {
430 (void)mut;
431 }
432
ares__thread_mutex_lock(ares__thread_mutex_t * mut)433 void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
434 {
435 (void)mut;
436 }
437
ares__thread_mutex_unlock(ares__thread_mutex_t * mut)438 void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
439 {
440 (void)mut;
441 }
442
ares__thread_cond_create(void)443 ares__thread_cond_t *ares__thread_cond_create(void)
444 {
445 return NULL;
446 }
447
ares__thread_cond_destroy(ares__thread_cond_t * cond)448 void ares__thread_cond_destroy(ares__thread_cond_t *cond)
449 {
450 (void)cond;
451 }
452
ares__thread_cond_signal(ares__thread_cond_t * cond)453 void ares__thread_cond_signal(ares__thread_cond_t *cond)
454 {
455 (void)cond;
456 }
457
ares__thread_cond_broadcast(ares__thread_cond_t * cond)458 void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
459 {
460 (void)cond;
461 }
462
ares__thread_cond_wait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut)463 ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
464 ares__thread_mutex_t *mut)
465 {
466 (void)cond;
467 (void)mut;
468 return ARES_ENOTIMP;
469 }
470
ares__thread_cond_timedwait(ares__thread_cond_t * cond,ares__thread_mutex_t * mut,unsigned long timeout_ms)471 ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
472 ares__thread_mutex_t *mut,
473 unsigned long timeout_ms)
474 {
475 (void)cond;
476 (void)mut;
477 (void)timeout_ms;
478 return ARES_ENOTIMP;
479 }
480
ares__thread_create(ares__thread_t ** thread,ares__thread_func_t func,void * arg)481 ares_status_t ares__thread_create(ares__thread_t **thread,
482 ares__thread_func_t func, void *arg)
483 {
484 (void)thread;
485 (void)func;
486 (void)arg;
487 return ARES_ENOTIMP;
488 }
489
ares__thread_join(ares__thread_t * thread,void ** rv)490 ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
491 {
492 (void)thread;
493 (void)rv;
494 return ARES_ENOTIMP;
495 }
496
ares_threadsafety(void)497 ares_bool_t ares_threadsafety(void)
498 {
499 return ARES_FALSE;
500 }
501 #endif
502
503
ares__channel_threading_init(ares_channel_t * channel)504 ares_status_t ares__channel_threading_init(ares_channel_t *channel)
505 {
506 ares_status_t status = ARES_SUCCESS;
507
508 /* Threading is optional! */
509 if (!ares_threadsafety()) {
510 return ARES_SUCCESS;
511 }
512
513 channel->lock = ares__thread_mutex_create();
514 if (channel->lock == NULL) {
515 status = ARES_ENOMEM;
516 goto done;
517 }
518
519 channel->cond_empty = ares__thread_cond_create();
520 if (channel->cond_empty == NULL) {
521 status = ARES_ENOMEM;
522 goto done;
523 }
524
525 done:
526 if (status != ARES_SUCCESS) {
527 ares__channel_threading_destroy(channel);
528 }
529 return status;
530 }
531
ares__channel_threading_destroy(ares_channel_t * channel)532 void ares__channel_threading_destroy(ares_channel_t *channel)
533 {
534 ares__thread_mutex_destroy(channel->lock);
535 channel->lock = NULL;
536 ares__thread_cond_destroy(channel->cond_empty);
537 channel->cond_empty = NULL;
538 }
539
ares__channel_lock(ares_channel_t * channel)540 void ares__channel_lock(ares_channel_t *channel)
541 {
542 ares__thread_mutex_lock(channel->lock);
543 }
544
ares__channel_unlock(ares_channel_t * channel)545 void ares__channel_unlock(ares_channel_t *channel)
546 {
547 ares__thread_mutex_unlock(channel->lock);
548 }
549
550 /* Must not be holding a channel lock already, public function only */
ares_queue_wait_empty(ares_channel_t * channel,int timeout_ms)551 ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms)
552 {
553 ares_status_t status = ARES_SUCCESS;
554 struct timeval tout;
555
556 if (!ares_threadsafety()) {
557 return ARES_ENOTIMP;
558 }
559
560 if (channel == NULL) {
561 return ARES_EFORMERR;
562 }
563
564 if (timeout_ms >= 0) {
565 tout = ares__tvnow();
566 tout.tv_sec += timeout_ms / 1000;
567 tout.tv_usec += (timeout_ms % 1000) * 1000;
568 }
569
570 ares__thread_mutex_lock(channel->lock);
571 while (ares__llist_len(channel->all_queries)) {
572 if (timeout_ms < 0) {
573 ares__thread_cond_wait(channel->cond_empty, channel->lock);
574 } else {
575 struct timeval tv_remaining;
576 struct timeval tv_now = ares__tvnow();
577 unsigned long tms;
578
579 ares__timeval_remaining(&tv_remaining, &tv_now, &tout);
580 tms = (unsigned long)((tv_remaining.tv_sec * 1000) +
581 (tv_remaining.tv_usec / 1000));
582 if (tms == 0) {
583 status = ARES_ETIMEOUT;
584 } else {
585 status =
586 ares__thread_cond_timedwait(channel->cond_empty, channel->lock, tms);
587 }
588 }
589 }
590 ares__thread_mutex_unlock(channel->lock);
591 return status;
592 }
593
ares_queue_notify_empty(ares_channel_t * channel)594 void ares_queue_notify_empty(ares_channel_t *channel)
595 {
596 if (channel == NULL) {
597 return;
598 }
599
600 /* We are guaranteed to be holding a channel lock already */
601 if (ares__llist_len(channel->all_queries)) {
602 return;
603 }
604
605 /* Notify all waiters of the conditional */
606 ares__thread_cond_broadcast(channel->cond_empty);
607 }
608