%PDF- %PDF-
| Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/cares/src/lib/ |
| Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/cares/src/lib/ares__threads.c |
/* MIT License
*
* Copyright (c) 2023 Brad House
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* SPDX-License-Identifier: MIT
*/
#include "ares_setup.h"
#include "ares.h"
#include "ares_private.h"
#ifdef CARES_THREADS
# ifdef _WIN32
struct ares__thread_mutex {
CRITICAL_SECTION mutex;
};
ares__thread_mutex_t *ares__thread_mutex_create(void)
{
ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
if (mut == NULL) {
return NULL;
}
InitializeCriticalSection(&mut->mutex);
return mut;
}
void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
DeleteCriticalSection(&mut->mutex);
ares_free(mut);
}
void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
EnterCriticalSection(&mut->mutex);
}
void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
LeaveCriticalSection(&mut->mutex);
}
struct ares__thread_cond {
CONDITION_VARIABLE cond;
};
ares__thread_cond_t *ares__thread_cond_create(void)
{
ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
if (cond == NULL) {
return NULL;
}
InitializeConditionVariable(&cond->cond);
return cond;
}
void ares__thread_cond_destroy(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
ares_free(cond);
}
void ares__thread_cond_signal(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
WakeConditionVariable(&cond->cond);
}
void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
WakeAllConditionVariable(&cond->cond);
}
ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut)
{
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
SleepConditionVariableCS(&cond->cond, &mut->mutex, INFINITE);
return ARES_SUCCESS;
}
ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut,
unsigned long timeout_ms)
{
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
if (!SleepConditionVariableCS(&cond->cond, &mut->mutex, timeout_ms)) {
return ARES_ETIMEOUT;
}
return ARES_SUCCESS;
}
struct ares__thread {
HANDLE thread;
DWORD id;
void *(*func)(void *arg);
void *arg;
void *rv;
};
/* Wrap for pthread compatibility */
static DWORD WINAPI ares__thread_func(LPVOID lpParameter)
{
ares__thread_t *thread = lpParameter;
thread->rv = thread->func(thread->arg);
return 0;
}
ares_status_t ares__thread_create(ares__thread_t **thread,
ares__thread_func_t func, void *arg)
{
ares__thread_t *thr = NULL;
if (func == NULL || thread == NULL) {
return ARES_EFORMERR;
}
thr = ares_malloc_zero(sizeof(*thr));
if (thr == NULL) {
return ARES_ENOMEM;
}
thr->func = func;
thr->arg = arg;
thr->thread = CreateThread(NULL, 0, ares__thread_func, thr, 0, &thr->id);
if (thr->thread == NULL) {
ares_free(thr);
return ARES_ESERVFAIL;
}
*thread = thr;
return ARES_SUCCESS;
}
ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
{
ares_status_t status = ARES_SUCCESS;
if (thread == NULL) {
return ARES_EFORMERR;
}
if (WaitForSingleObject(thread->thread, INFINITE) != WAIT_OBJECT_0) {
status = ARES_ENOTFOUND;
} else {
CloseHandle(thread->thread);
}
if (status == ARES_SUCCESS && rv != NULL) {
*rv = thread->rv;
}
ares_free(thread);
return status;
}
# else /* !WIN32 == PTHREAD */
# include <pthread.h>
/* for clock_gettime() */
# ifdef HAVE_TIME_H
# include <time.h>
# endif
/* for gettimeofday() */
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
struct ares__thread_mutex {
pthread_mutex_t mutex;
};
ares__thread_mutex_t *ares__thread_mutex_create(void)
{
pthread_mutexattr_t attr;
ares__thread_mutex_t *mut = ares_malloc_zero(sizeof(*mut));
if (mut == NULL) {
return NULL;
}
if (pthread_mutexattr_init(&attr) != 0) {
ares_free(mut);
return NULL;
}
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
goto fail;
}
if (pthread_mutex_init(&mut->mutex, &attr) != 0) {
goto fail;
}
pthread_mutexattr_destroy(&attr);
return mut;
fail:
pthread_mutexattr_destroy(&attr);
ares_free(mut);
return NULL;
}
void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
pthread_mutex_destroy(&mut->mutex);
ares_free(mut);
}
void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
pthread_mutex_lock(&mut->mutex);
}
void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
{
if (mut == NULL) {
return;
}
pthread_mutex_unlock(&mut->mutex);
}
struct ares__thread_cond {
pthread_cond_t cond;
};
ares__thread_cond_t *ares__thread_cond_create(void)
{
ares__thread_cond_t *cond = ares_malloc_zero(sizeof(*cond));
if (cond == NULL) {
return NULL;
}
pthread_cond_init(&cond->cond, NULL);
return cond;
}
void ares__thread_cond_destroy(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
pthread_cond_destroy(&cond->cond);
ares_free(cond);
}
void ares__thread_cond_signal(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
pthread_cond_signal(&cond->cond);
}
void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
{
if (cond == NULL) {
return;
}
pthread_cond_broadcast(&cond->cond);
}
ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut)
{
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
pthread_cond_wait(&cond->cond, &mut->mutex);
return ARES_SUCCESS;
}
static void ares__timespec_timeout(struct timespec *ts, unsigned long add_ms)
{
# if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
clock_gettime(CLOCK_REALTIME, ts);
# elif defined(HAVE_GETTIMEOFDAY)
struct timeval tv;
gettimeofday(&tv, NULL);
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec * 1000;
# else
# error cannot determine current system time
# endif
ts->tv_sec += add_ms / 1000;
ts->tv_nsec += (add_ms % 1000) * 1000000;
/* Normalize if needed */
if (ts->tv_nsec >= 1000000000) {
ts->tv_sec += ts->tv_nsec / 1000000000;
ts->tv_nsec %= 1000000000;
}
}
ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut,
unsigned long timeout_ms)
{
struct timespec ts;
if (cond == NULL || mut == NULL) {
return ARES_EFORMERR;
}
ares__timespec_timeout(&ts, timeout_ms);
if (pthread_cond_timedwait(&cond->cond, &mut->mutex, &ts) != 0) {
return ARES_ETIMEOUT;
}
return ARES_SUCCESS;
}
struct ares__thread {
pthread_t thread;
};
ares_status_t ares__thread_create(ares__thread_t **thread,
ares__thread_func_t func, void *arg)
{
ares__thread_t *thr = NULL;
if (func == NULL || thread == NULL) {
return ARES_EFORMERR;
}
thr = ares_malloc_zero(sizeof(*thr));
if (thr == NULL) {
return ARES_ENOMEM;
}
if (pthread_create(&thr->thread, NULL, func, arg) != 0) {
ares_free(thr);
return ARES_ESERVFAIL;
}
*thread = thr;
return ARES_SUCCESS;
}
ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
{
void *ret = NULL;
ares_status_t status = ARES_SUCCESS;
if (thread == NULL) {
return ARES_EFORMERR;
}
if (pthread_join(thread->thread, &ret) != 0) {
status = ARES_ENOTFOUND;
}
ares_free(thread);
if (status == ARES_SUCCESS && rv != NULL) {
*rv = ret;
}
return status;
}
# endif
ares_bool_t ares_threadsafety(void)
{
return ARES_TRUE;
}
#else /* !CARES_THREADS */
/* NoOp */
ares__thread_mutex_t *ares__thread_mutex_create(void)
{
return NULL;
}
void ares__thread_mutex_destroy(ares__thread_mutex_t *mut)
{
(void)mut;
}
void ares__thread_mutex_lock(ares__thread_mutex_t *mut)
{
(void)mut;
}
void ares__thread_mutex_unlock(ares__thread_mutex_t *mut)
{
(void)mut;
}
ares__thread_cond_t *ares__thread_cond_create(void)
{
return NULL;
}
void ares__thread_cond_destroy(ares__thread_cond_t *cond)
{
(void)cond;
}
void ares__thread_cond_signal(ares__thread_cond_t *cond)
{
(void)cond;
}
void ares__thread_cond_broadcast(ares__thread_cond_t *cond)
{
(void)cond;
}
ares_status_t ares__thread_cond_wait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut)
{
(void)cond;
(void)mut;
return ARES_ENOTIMP;
}
ares_status_t ares__thread_cond_timedwait(ares__thread_cond_t *cond,
ares__thread_mutex_t *mut,
unsigned long timeout_ms)
{
(void)cond;
(void)mut;
(void)timeout_ms;
return ARES_ENOTIMP;
}
ares_status_t ares__thread_create(ares__thread_t **thread,
ares__thread_func_t func, void *arg)
{
(void)thread;
(void)func;
(void)arg;
return ARES_ENOTIMP;
}
ares_status_t ares__thread_join(ares__thread_t *thread, void **rv)
{
(void)thread;
(void)rv;
return ARES_ENOTIMP;
}
ares_bool_t ares_threadsafety(void)
{
return ARES_FALSE;
}
#endif
ares_status_t ares__channel_threading_init(ares_channel_t *channel)
{
ares_status_t status = ARES_SUCCESS;
/* Threading is optional! */
if (!ares_threadsafety()) {
return ARES_SUCCESS;
}
channel->lock = ares__thread_mutex_create();
if (channel->lock == NULL) {
status = ARES_ENOMEM;
goto done;
}
channel->cond_empty = ares__thread_cond_create();
if (channel->cond_empty == NULL) {
status = ARES_ENOMEM;
goto done;
}
done:
if (status != ARES_SUCCESS) {
ares__channel_threading_destroy(channel);
}
return status;
}
void ares__channel_threading_destroy(ares_channel_t *channel)
{
ares__thread_mutex_destroy(channel->lock);
channel->lock = NULL;
ares__thread_cond_destroy(channel->cond_empty);
channel->cond_empty = NULL;
}
void ares__channel_lock(ares_channel_t *channel)
{
ares__thread_mutex_lock(channel->lock);
}
void ares__channel_unlock(ares_channel_t *channel)
{
ares__thread_mutex_unlock(channel->lock);
}
/* Must not be holding a channel lock already, public function only */
ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms)
{
ares_status_t status = ARES_SUCCESS;
struct timeval tout;
if (!ares_threadsafety()) {
return ARES_ENOTIMP;
}
if (channel == NULL) {
return ARES_EFORMERR;
}
if (timeout_ms >= 0) {
tout = ares__tvnow();
tout.tv_sec += timeout_ms / 1000;
tout.tv_usec += (timeout_ms % 1000) * 1000;
}
ares__thread_mutex_lock(channel->lock);
while (ares__llist_len(channel->all_queries)) {
if (timeout_ms < 0) {
ares__thread_cond_wait(channel->cond_empty, channel->lock);
} else {
struct timeval tv_remaining;
struct timeval tv_now = ares__tvnow();
unsigned long tms;
ares__timeval_remaining(&tv_remaining, &tv_now, &tout);
tms = (unsigned long)((tv_remaining.tv_sec * 1000) +
(tv_remaining.tv_usec / 1000));
if (tms == 0) {
status = ARES_ETIMEOUT;
} else {
status =
ares__thread_cond_timedwait(channel->cond_empty, channel->lock, tms);
}
}
}
ares__thread_mutex_unlock(channel->lock);
return status;
}
void ares_queue_notify_empty(ares_channel_t *channel)
{
if (channel == NULL) {
return;
}
/* We are guaranteed to be holding a channel lock already */
if (ares__llist_len(channel->all_queries)) {
return;
}
/* Notify all waiters of the conditional */
ares__thread_cond_broadcast(channel->cond_empty);
}