openssl/ssl/quic/quic_thread_assist.c
Hugo Landau 62cb7c810e THREADING: Make CRYPTO_MUTEX and CRYPTO_CONDVAR typesafe
There was really no need for this to be void and it made bugs very easy
to introduce accidentally, especially given that the free functions
needed to be passed a pointer to the pointer.

Also fix some bugs in the QUIC code detected immediately by this change.

.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23519)
2024-02-09 14:10:17 +01:00

158 lines
4.0 KiB
C

/*
* Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/macros.h>
#include "quic_local.h"
#include "internal/time.h"
#include "internal/thread.h"
#include "internal/thread_arch.h"
#include "internal/quic_thread_assist.h"
#if !defined(OPENSSL_NO_QUIC_THREAD_ASSIST)
/* Main loop for the QUIC assist thread. */
static unsigned int assist_thread_main(void *arg)
{
QUIC_THREAD_ASSIST *qta = arg;
CRYPTO_MUTEX *m = ossl_quic_channel_get_mutex(qta->ch);
QUIC_REACTOR *rtor;
ossl_crypto_mutex_lock(m);
rtor = ossl_quic_channel_get_reactor(qta->ch);
for (;;) {
OSSL_TIME deadline;
if (qta->teardown)
break;
deadline = ossl_quic_reactor_get_tick_deadline(rtor);
if (qta->now_cb != NULL
&& !ossl_time_is_zero(deadline)
&& !ossl_time_is_infinite(deadline)) {
/*
* ossl_crypto_condvar_wait_timeout needs to use real time for the
* deadline
*/
deadline = ossl_time_add(ossl_time_subtract(deadline,
qta->now_cb(qta->now_cb_arg)),
ossl_time_now());
}
ossl_crypto_condvar_wait_timeout(qta->cv, m, deadline);
/*
* We have now been woken up. This can be for one of the following
* reasons:
*
* - We have been asked to teardown (qta->teardown is set);
* - The tick deadline has passed.
* - The tick deadline has changed.
*
* For robustness, this loop also handles spurious wakeups correctly
* (which does not require any extra code).
*/
if (qta->teardown)
break;
ossl_quic_reactor_tick(rtor, QUIC_REACTOR_TICK_FLAG_CHANNEL_ONLY);
}
ossl_crypto_mutex_unlock(m);
return 1;
}
int ossl_quic_thread_assist_init_start(QUIC_THREAD_ASSIST *qta,
QUIC_CHANNEL *ch,
OSSL_TIME (*now_cb)(void *arg),
void *now_cb_arg)
{
CRYPTO_MUTEX *mutex = ossl_quic_channel_get_mutex(ch);
if (mutex == NULL)
return 0;
qta->ch = ch;
qta->teardown = 0;
qta->joined = 0;
qta->now_cb = now_cb;
qta->now_cb_arg = now_cb_arg;
qta->cv = ossl_crypto_condvar_new();
if (qta->cv == NULL)
return 0;
qta->t = ossl_crypto_thread_native_start(assist_thread_main,
qta, /*joinable=*/1);
if (qta->t == NULL) {
ossl_crypto_condvar_free(&qta->cv);
return 0;
}
return 1;
}
int ossl_quic_thread_assist_stop_async(QUIC_THREAD_ASSIST *qta)
{
if (!qta->teardown) {
qta->teardown = 1;
ossl_crypto_condvar_signal(qta->cv);
}
return 1;
}
int ossl_quic_thread_assist_wait_stopped(QUIC_THREAD_ASSIST *qta)
{
CRYPTO_THREAD_RETVAL rv;
CRYPTO_MUTEX *m = ossl_quic_channel_get_mutex(qta->ch);
if (qta->joined)
return 1;
if (!ossl_quic_thread_assist_stop_async(qta))
return 0;
ossl_crypto_mutex_unlock(m);
if (!ossl_crypto_thread_native_join(qta->t, &rv)) {
ossl_crypto_mutex_lock(m);
return 0;
}
qta->joined = 1;
ossl_crypto_mutex_lock(m);
return 1;
}
int ossl_quic_thread_assist_cleanup(QUIC_THREAD_ASSIST *qta)
{
if (!ossl_assert(qta->joined))
return 0;
ossl_crypto_condvar_free(&qta->cv);
ossl_crypto_thread_native_clean(qta->t);
qta->ch = NULL;
qta->t = NULL;
return 1;
}
int ossl_quic_thread_assist_notify_deadline_changed(QUIC_THREAD_ASSIST *qta)
{
if (qta->teardown)
return 0;
ossl_crypto_condvar_signal(qta->cv);
return 1;
}
#endif