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