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 33struct ares__thread_mutex { 34 CRITICAL_SECTION mutex; 35}; 36 37ares__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 48void 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 57void ares__thread_mutex_lock(ares__thread_mutex_t *mut) 58{ 59 if (mut == NULL) { 60 return; 61 } 62 EnterCriticalSection(&mut->mutex); 63} 64 65void ares__thread_mutex_unlock(ares__thread_mutex_t *mut) 66{ 67 if (mut == NULL) { 68 return; 69 } 70 LeaveCriticalSection(&mut->mutex); 71} 72 73struct ares__thread_cond { 74 CONDITION_VARIABLE cond; 75}; 76 77ares__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 87void ares__thread_cond_destroy(ares__thread_cond_t *cond) 88{ 89 if (cond == NULL) { 90 return; 91 } 92 ares_free(cond); 93} 94 95void ares__thread_cond_signal(ares__thread_cond_t *cond) 96{ 97 if (cond == NULL) { 98 return; 99 } 100 WakeConditionVariable(&cond->cond); 101} 102 103void ares__thread_cond_broadcast(ares__thread_cond_t *cond) 104{ 105 if (cond == NULL) { 106 return; 107 } 108 WakeAllConditionVariable(&cond->cond); 109} 110 111ares_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 122ares_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 137struct 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 */ 147static 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 155ares_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 181ares_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 216struct ares__thread_mutex { 217 pthread_mutex_t mutex; 218}; 219 220ares__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 244fail: 245 pthread_mutexattr_destroy(&attr); 246 ares_free(mut); 247 return NULL; 248} 249 250void 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 259void 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 267void 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 275struct ares__thread_cond { 276 pthread_cond_t cond; 277}; 278 279ares__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 289void 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 298void 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 306void 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 314ares_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 325static 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 348ares_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 367struct ares__thread { 368 pthread_t thread; 369}; 370 371ares_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 393ares_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 415ares_bool_t ares_threadsafety(void) 416{ 417 return ARES_TRUE; 418} 419 420#else /* !CARES_THREADS */ 421 422/* NoOp */ 423ares__thread_mutex_t *ares__thread_mutex_create(void) 424{ 425 return NULL; 426} 427 428void ares__thread_mutex_destroy(ares__thread_mutex_t *mut) 429{ 430 (void)mut; 431} 432 433void ares__thread_mutex_lock(ares__thread_mutex_t *mut) 434{ 435 (void)mut; 436} 437 438void ares__thread_mutex_unlock(ares__thread_mutex_t *mut) 439{ 440 (void)mut; 441} 442 443ares__thread_cond_t *ares__thread_cond_create(void) 444{ 445 return NULL; 446} 447 448void ares__thread_cond_destroy(ares__thread_cond_t *cond) 449{ 450 (void)cond; 451} 452 453void ares__thread_cond_signal(ares__thread_cond_t *cond) 454{ 455 (void)cond; 456} 457 458void ares__thread_cond_broadcast(ares__thread_cond_t *cond) 459{ 460 (void)cond; 461} 462 463ares_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 471ares_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 481ares_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 490ares_status_t ares__thread_join(ares__thread_t *thread, void **rv) 491{ 492 (void)thread; 493 (void)rv; 494 return ARES_ENOTIMP; 495} 496 497ares_bool_t ares_threadsafety(void) 498{ 499 return ARES_FALSE; 500} 501#endif 502 503 504ares_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 525done: 526 if (status != ARES_SUCCESS) { 527 ares__channel_threading_destroy(channel); 528 } 529 return status; 530} 531 532void 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 540void ares__channel_lock(ares_channel_t *channel) 541{ 542 ares__thread_mutex_lock(channel->lock); 543} 544 545void 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 */ 551ares_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 594void 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