• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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