Home | History | Annotate | Line # | Download | only in quic
      1 /*
      2  * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include <openssl/macros.h>
     11 #include "quic_local.h"
     12 #include "internal/time.h"
     13 #include "internal/thread.h"
     14 #include "internal/thread_arch.h"
     15 #include "internal/quic_thread_assist.h"
     16 
     17 #if !defined(OPENSSL_NO_QUIC_THREAD_ASSIST)
     18 
     19 /* Main loop for the QUIC assist thread. */
     20 static unsigned int assist_thread_main(void *arg)
     21 {
     22     QUIC_THREAD_ASSIST *qta = arg;
     23     CRYPTO_MUTEX *m = ossl_quic_channel_get_mutex(qta->ch);
     24     QUIC_REACTOR *rtor;
     25     QUIC_ENGINE *eng = ossl_quic_channel_get0_engine(qta->ch);
     26 
     27     ossl_crypto_mutex_lock(m);
     28 
     29     rtor = ossl_quic_channel_get_reactor(qta->ch);
     30 
     31     for (;;) {
     32         OSSL_TIME deadline;
     33 
     34         if (qta->teardown)
     35             break;
     36 
     37         deadline = ossl_quic_reactor_get_tick_deadline(rtor);
     38         /*
     39          * ossl_crypto_condvar_wait_timeout needs to use real time for the
     40          * deadline
     41          */
     42         deadline = ossl_quic_engine_make_real_time(eng, deadline);
     43         ossl_crypto_condvar_wait_timeout(qta->cv, m, deadline);
     44 
     45         /*
     46          * We have now been woken up. This can be for one of the following
     47          * reasons:
     48          *
     49          *   - We have been asked to teardown (qta->teardown is set);
     50          *   - The tick deadline has passed.
     51          *   - The tick deadline has changed.
     52          *
     53          * For robustness, this loop also handles spurious wakeups correctly
     54          * (which does not require any extra code).
     55          */
     56         if (qta->teardown)
     57             break;
     58 
     59         ossl_quic_reactor_tick(rtor, QUIC_REACTOR_TICK_FLAG_CHANNEL_ONLY);
     60     }
     61 
     62     ossl_crypto_mutex_unlock(m);
     63     return 1;
     64 }
     65 
     66 int ossl_quic_thread_assist_init_start(QUIC_THREAD_ASSIST *qta,
     67     QUIC_CHANNEL *ch)
     68 {
     69     CRYPTO_MUTEX *mutex = ossl_quic_channel_get_mutex(ch);
     70 
     71     if (mutex == NULL)
     72         return 0;
     73 
     74     qta->ch = ch;
     75     qta->teardown = 0;
     76     qta->joined = 0;
     77 
     78     qta->cv = ossl_crypto_condvar_new();
     79     if (qta->cv == NULL)
     80         return 0;
     81 
     82     qta->t = ossl_crypto_thread_native_start(assist_thread_main,
     83         qta, /*joinable=*/1);
     84     if (qta->t == NULL) {
     85         ossl_crypto_condvar_free(&qta->cv);
     86         return 0;
     87     }
     88 
     89     return 1;
     90 }
     91 
     92 int ossl_quic_thread_assist_stop_async(QUIC_THREAD_ASSIST *qta)
     93 {
     94     if (!qta->teardown) {
     95         qta->teardown = 1;
     96         ossl_crypto_condvar_signal(qta->cv);
     97     }
     98 
     99     return 1;
    100 }
    101 
    102 int ossl_quic_thread_assist_wait_stopped(QUIC_THREAD_ASSIST *qta)
    103 {
    104     CRYPTO_THREAD_RETVAL rv;
    105     CRYPTO_MUTEX *m = ossl_quic_channel_get_mutex(qta->ch);
    106 
    107     if (qta->joined)
    108         return 1;
    109 
    110     if (!ossl_quic_thread_assist_stop_async(qta))
    111         return 0;
    112 
    113     ossl_crypto_mutex_unlock(m);
    114 
    115     if (!ossl_crypto_thread_native_join(qta->t, &rv)) {
    116         ossl_crypto_mutex_lock(m);
    117         return 0;
    118     }
    119 
    120     qta->joined = 1;
    121 
    122     ossl_crypto_mutex_lock(m);
    123     return 1;
    124 }
    125 
    126 int ossl_quic_thread_assist_cleanup(QUIC_THREAD_ASSIST *qta)
    127 {
    128     if (!ossl_assert(qta->joined))
    129         return 0;
    130 
    131     ossl_crypto_condvar_free(&qta->cv);
    132     ossl_crypto_thread_native_clean(qta->t);
    133 
    134     qta->ch = NULL;
    135     qta->t = NULL;
    136     return 1;
    137 }
    138 
    139 int ossl_quic_thread_assist_notify_deadline_changed(QUIC_THREAD_ASSIST *qta)
    140 {
    141     if (qta->teardown)
    142         return 0;
    143 
    144     ossl_crypto_condvar_signal(qta->cv);
    145     return 1;
    146 }
    147 
    148 #endif
    149