Coverage Report

Created: 2025-06-13 06:57

/src/openssl/ssl/quic/quic_reactor.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2022-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
#include "internal/quic_reactor.h"
10
#include "internal/common.h"
11
#include "internal/thread_arch.h"
12
#include <assert.h>
13
14
/*
15
 * Core I/O Reactor Framework
16
 * ==========================
17
 */
18
static void rtor_notify_other_threads(QUIC_REACTOR *rtor);
19
20
int ossl_quic_reactor_init(QUIC_REACTOR *rtor,
21
                           void (*tick_cb)(QUIC_TICK_RESULT *res, void *arg,
22
                                           uint32_t flags),
23
                           void *tick_cb_arg,
24
                           CRYPTO_MUTEX *mutex,
25
                           OSSL_TIME initial_tick_deadline,
26
                           uint64_t flags)
27
0
{
28
0
    rtor->poll_r.type       = BIO_POLL_DESCRIPTOR_TYPE_NONE;
29
0
    rtor->poll_w.type       = BIO_POLL_DESCRIPTOR_TYPE_NONE;
30
0
    rtor->net_read_desired  = 0;
31
0
    rtor->net_write_desired = 0;
32
0
    rtor->can_poll_r        = 0;
33
0
    rtor->can_poll_w        = 0;
34
0
    rtor->tick_deadline     = initial_tick_deadline;
35
36
0
    rtor->tick_cb           = tick_cb;
37
0
    rtor->tick_cb_arg       = tick_cb_arg;
38
0
    rtor->mutex             = mutex;
39
40
0
    rtor->cur_blocking_waiters = 0;
41
42
0
    if ((flags & QUIC_REACTOR_FLAG_USE_NOTIFIER) != 0) {
43
0
        if (!ossl_rio_notifier_init(&rtor->notifier))
44
0
            return 0;
45
46
0
        if ((rtor->notifier_cv = ossl_crypto_condvar_new()) == NULL) {
47
0
            ossl_rio_notifier_cleanup(&rtor->notifier);
48
0
            return 0;
49
0
        }
50
51
0
        rtor->have_notifier = 1;
52
0
    } else {
53
0
        rtor->have_notifier = 0;
54
0
    }
55
56
0
    return 1;
57
0
}
58
59
void ossl_quic_reactor_cleanup(QUIC_REACTOR *rtor)
60
0
{
61
0
    if (rtor == NULL)
62
0
        return;
63
64
0
    if (rtor->have_notifier) {
65
0
        ossl_rio_notifier_cleanup(&rtor->notifier);
66
0
        rtor->have_notifier = 0;
67
68
0
        ossl_crypto_condvar_free(&rtor->notifier_cv);
69
0
    }
70
0
}
71
72
void ossl_quic_reactor_set_poll_r(QUIC_REACTOR *rtor, const BIO_POLL_DESCRIPTOR *r)
73
0
{
74
0
    if (r == NULL)
75
0
        rtor->poll_r.type = BIO_POLL_DESCRIPTOR_TYPE_NONE;
76
0
    else
77
0
        rtor->poll_r = *r;
78
79
0
    rtor->can_poll_r
80
0
        = ossl_quic_reactor_can_support_poll_descriptor(rtor, &rtor->poll_r);
81
0
}
82
83
void ossl_quic_reactor_set_poll_w(QUIC_REACTOR *rtor, const BIO_POLL_DESCRIPTOR *w)
84
0
{
85
0
    if (w == NULL)
86
0
        rtor->poll_w.type = BIO_POLL_DESCRIPTOR_TYPE_NONE;
87
0
    else
88
0
        rtor->poll_w = *w;
89
90
0
    rtor->can_poll_w
91
0
        = ossl_quic_reactor_can_support_poll_descriptor(rtor, &rtor->poll_w);
92
0
}
93
94
const BIO_POLL_DESCRIPTOR *ossl_quic_reactor_get_poll_r(const QUIC_REACTOR *rtor)
95
0
{
96
0
    return &rtor->poll_r;
97
0
}
98
99
const BIO_POLL_DESCRIPTOR *ossl_quic_reactor_get_poll_w(const QUIC_REACTOR *rtor)
100
0
{
101
0
    return &rtor->poll_w;
102
0
}
103
104
int ossl_quic_reactor_can_support_poll_descriptor(const QUIC_REACTOR *rtor,
105
                                                  const BIO_POLL_DESCRIPTOR *d)
106
0
{
107
0
    return d->type == BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD;
108
0
}
109
110
int ossl_quic_reactor_can_poll_r(const QUIC_REACTOR *rtor)
111
0
{
112
0
    return rtor->can_poll_r;
113
0
}
114
115
int ossl_quic_reactor_can_poll_w(const QUIC_REACTOR *rtor)
116
0
{
117
0
    return rtor->can_poll_w;
118
0
}
119
120
int ossl_quic_reactor_net_read_desired(QUIC_REACTOR *rtor)
121
0
{
122
0
    return rtor->net_read_desired;
123
0
}
124
125
int ossl_quic_reactor_net_write_desired(QUIC_REACTOR *rtor)
126
0
{
127
0
    return rtor->net_write_desired;
128
0
}
129
130
OSSL_TIME ossl_quic_reactor_get_tick_deadline(QUIC_REACTOR *rtor)
131
0
{
132
0
    return rtor->tick_deadline;
133
0
}
134
135
int ossl_quic_reactor_tick(QUIC_REACTOR *rtor, uint32_t flags)
136
0
{
137
0
    QUIC_TICK_RESULT res = {0};
138
139
    /*
140
     * Note that the tick callback cannot fail; this is intentional. Arguably it
141
     * does not make that much sense for ticking to 'fail' (in the sense of an
142
     * explicit error indicated to the user) because ticking is by its nature
143
     * best effort. If something fatal happens with a connection we can report
144
     * it on the next actual application I/O call.
145
     */
146
0
    rtor->tick_cb(&res, rtor->tick_cb_arg, flags);
147
148
0
    rtor->net_read_desired  = res.net_read_desired;
149
0
    rtor->net_write_desired = res.net_write_desired;
150
0
    rtor->tick_deadline     = res.tick_deadline;
151
0
    if (res.notify_other_threads)
152
0
        rtor_notify_other_threads(rtor);
153
154
0
    return 1;
155
0
}
156
157
RIO_NOTIFIER *ossl_quic_reactor_get0_notifier(QUIC_REACTOR *rtor)
158
0
{
159
0
    return rtor->have_notifier ? &rtor->notifier : NULL;
160
0
}
161
162
/*
163
 * Blocking I/O Adaptation Layer
164
 * =============================
165
 */
166
167
/*
168
 * Utility which can be used to poll on up to two FDs. This is designed to
169
 * support use of split FDs (e.g. with SSL_set_rfd and SSL_set_wfd where
170
 * different FDs are used for read and write).
171
 *
172
 * Generally use of poll(2) is preferred where available. Windows, however,
173
 * hasn't traditionally offered poll(2), only select(2). WSAPoll() was
174
 * introduced in Vista but has seemingly been buggy until relatively recent
175
 * versions of Windows 10. Moreover we support XP so this is not a suitable
176
 * target anyway. However, the traditional issues with select(2) turn out not to
177
 * be an issue on Windows; whereas traditional *NIX select(2) uses a bitmap of
178
 * FDs (and thus is limited in the magnitude of the FDs expressible), Windows
179
 * select(2) is very different. In Windows, socket handles are not allocated
180
 * contiguously from zero and thus this bitmap approach was infeasible. Thus in
181
 * adapting the Berkeley sockets API to Windows a different approach was taken
182
 * whereby the fd_set contains a fixed length array of socket handles and an
183
 * integer indicating how many entries are valid; thus Windows select()
184
 * ironically is actually much more like *NIX poll(2) than *NIX select(2). In
185
 * any case, this means that the relevant limit for Windows select() is the
186
 * number of FDs being polled, not the magnitude of those FDs. Since we only
187
 * poll for two FDs here, this limit does not concern us.
188
 *
189
 * Usage: rfd and wfd may be the same or different. Either or both may also be
190
 * -1. If rfd_want_read is 1, rfd is polled for readability, and if
191
 * wfd_want_write is 1, wfd is polled for writability. Note that since any
192
 * passed FD is always polled for error conditions, setting rfd_want_read=0 and
193
 * wfd_want_write=0 is not the same as passing -1 for both FDs.
194
 *
195
 * deadline is a timestamp to return at. If it is ossl_time_infinite(), the call
196
 * never times out.
197
 *
198
 * Returns 0 on error and 1 on success. Timeout expiry is considered a success
199
 * condition. We don't elaborate our return values here because the way we are
200
 * actually using this doesn't currently care.
201
 *
202
 * If mutex is non-NULL, it is assumed to be held for write and is unlocked for
203
 * the duration of the call.
204
 *
205
 * Precondition:   mutex is NULL or is held for write (unchecked)
206
 * Postcondition:  mutex is NULL or is held for write (unless
207
 *                   CRYPTO_THREAD_write_lock fails)
208
 */
209
static int poll_two_fds(int rfd, int rfd_want_read,
210
                        int wfd, int wfd_want_write,
211
                        int notify_rfd,
212
                        OSSL_TIME deadline,
213
                        CRYPTO_MUTEX *mutex)
214
0
{
215
#if defined(OPENSSL_SYS_WINDOWS) || !defined(POLLIN)
216
    fd_set rfd_set, wfd_set, efd_set;
217
    OSSL_TIME now, timeout;
218
    struct timeval tv, *ptv;
219
    int maxfd, pres;
220
221
# ifndef OPENSSL_SYS_WINDOWS
222
    /*
223
     * On Windows there is no relevant limit to the magnitude of a fd value (see
224
     * above). On *NIX the fd_set uses a bitmap and we must check the limit.
225
     */
226
    if (rfd >= FD_SETSIZE || wfd >= FD_SETSIZE)
227
        return 0;
228
# endif
229
230
    FD_ZERO(&rfd_set);
231
    FD_ZERO(&wfd_set);
232
    FD_ZERO(&efd_set);
233
234
    if (rfd != INVALID_SOCKET && rfd_want_read)
235
        openssl_fdset(rfd, &rfd_set);
236
    if (wfd != INVALID_SOCKET && wfd_want_write)
237
        openssl_fdset(wfd, &wfd_set);
238
239
    /* Always check for error conditions. */
240
    if (rfd != INVALID_SOCKET)
241
        openssl_fdset(rfd, &efd_set);
242
    if (wfd != INVALID_SOCKET)
243
        openssl_fdset(wfd, &efd_set);
244
245
    /* Check for notifier FD readability. */
246
    if (notify_rfd != INVALID_SOCKET) {
247
        openssl_fdset(notify_rfd, &rfd_set);
248
        openssl_fdset(notify_rfd, &efd_set);
249
    }
250
251
    maxfd = rfd;
252
    if (wfd > maxfd)
253
        maxfd = wfd;
254
    if (notify_rfd > maxfd)
255
        maxfd = notify_rfd;
256
257
    if (!ossl_assert(rfd != INVALID_SOCKET || wfd != INVALID_SOCKET
258
                     || !ossl_time_is_infinite(deadline)))
259
        /* Do not block forever; should not happen. */
260
        return 0;
261
262
    /*
263
     * The mutex dance (unlock/re-locak after poll/seclect) is
264
     * potentially problematic. This may create a situation when
265
     * two threads arrive to select/poll with the same file
266
     * descriptors. We just need to be aware of this.
267
     */
268
# if defined(OPENSSL_THREADS)
269
    if (mutex != NULL)
270
        ossl_crypto_mutex_unlock(mutex);
271
# endif
272
273
    do {
274
        /*
275
         * select expects a timeout, not a deadline, so do the conversion.
276
         * Update for each call to ensure the correct value is used if we repeat
277
         * due to EINTR.
278
         */
279
        if (ossl_time_is_infinite(deadline)) {
280
            ptv = NULL;
281
        } else {
282
            now = ossl_time_now();
283
            /*
284
             * ossl_time_subtract saturates to zero so we don't need to check if
285
             * now > deadline.
286
             */
287
            timeout = ossl_time_subtract(deadline, now);
288
            tv      = ossl_time_to_timeval(timeout);
289
            ptv     = &tv;
290
        }
291
292
        pres = select(maxfd + 1, &rfd_set, &wfd_set, &efd_set, ptv);
293
    } while (pres == -1 && get_last_socket_error_is_eintr());
294
295
# if defined(OPENSSL_THREADS)
296
    if (mutex != NULL)
297
        ossl_crypto_mutex_lock(mutex);
298
# endif
299
300
    return pres < 0 ? 0 : 1;
301
#else
302
0
    int pres, timeout_ms;
303
0
    OSSL_TIME now, timeout;
304
0
    struct pollfd pfds[3] = {0};
305
0
    size_t npfd = 0;
306
307
0
    if (rfd == wfd) {
308
0
        pfds[npfd].fd = rfd;
309
0
        pfds[npfd].events = (rfd_want_read  ? POLLIN  : 0)
310
0
                          | (wfd_want_write ? POLLOUT : 0);
311
0
        if (rfd >= 0 && pfds[npfd].events != 0)
312
0
            ++npfd;
313
0
    } else {
314
0
        pfds[npfd].fd     = rfd;
315
0
        pfds[npfd].events = (rfd_want_read ? POLLIN : 0);
316
0
        if (rfd >= 0 && pfds[npfd].events != 0)
317
0
            ++npfd;
318
319
0
        pfds[npfd].fd     = wfd;
320
0
        pfds[npfd].events = (wfd_want_write ? POLLOUT : 0);
321
0
        if (wfd >= 0 && pfds[npfd].events != 0)
322
0
            ++npfd;
323
0
    }
324
325
0
    if (notify_rfd >= 0) {
326
0
        pfds[npfd].fd       = notify_rfd;
327
0
        pfds[npfd].events   = POLLIN;
328
0
        ++npfd;
329
0
    }
330
331
0
    if (!ossl_assert(npfd != 0 || !ossl_time_is_infinite(deadline)))
332
        /* Do not block forever; should not happen. */
333
0
        return 0;
334
335
0
# if defined(OPENSSL_THREADS)
336
0
    if (mutex != NULL)
337
0
        ossl_crypto_mutex_unlock(mutex);
338
0
# endif
339
340
0
    do {
341
0
        if (ossl_time_is_infinite(deadline)) {
342
0
            timeout_ms = -1;
343
0
        } else {
344
0
            now         = ossl_time_now();
345
0
            timeout     = ossl_time_subtract(deadline, now);
346
0
            timeout_ms  = ossl_time2ms(timeout);
347
0
        }
348
349
0
        pres = poll(pfds, npfd, timeout_ms);
350
0
    } while (pres == -1 && get_last_socket_error_is_eintr());
351
352
0
# if defined(OPENSSL_THREADS)
353
0
    if (mutex != NULL)
354
0
        ossl_crypto_mutex_lock(mutex);
355
0
# endif
356
357
0
    return pres < 0 ? 0 : 1;
358
0
#endif
359
0
}
360
361
static int poll_descriptor_to_fd(const BIO_POLL_DESCRIPTOR *d, int *fd)
362
0
{
363
0
    if (d == NULL || d->type == BIO_POLL_DESCRIPTOR_TYPE_NONE) {
364
0
        *fd = INVALID_SOCKET;
365
0
        return 1;
366
0
    }
367
368
0
    if (d->type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD
369
0
            || d->value.fd == INVALID_SOCKET)
370
0
        return 0;
371
372
0
    *fd = d->value.fd;
373
0
    return 1;
374
0
}
375
376
/*
377
 * Poll up to two abstract poll descriptors, as well as an optional notify FD.
378
 * Currently we only support poll descriptors which represent FDs.
379
 *
380
 * If mutex is non-NULL, it is assumed be a lock currently held for write and is
381
 * unlocked for the duration of any wait.
382
 *
383
 * Precondition:   mutex is NULL or is held for write (unchecked)
384
 * Postcondition:  mutex is NULL or is held for write (unless
385
 *                   CRYPTO_THREAD_write_lock fails)
386
 */
387
static int poll_two_descriptors(const BIO_POLL_DESCRIPTOR *r, int r_want_read,
388
                                const BIO_POLL_DESCRIPTOR *w, int w_want_write,
389
                                int notify_rfd,
390
                                OSSL_TIME deadline,
391
                                CRYPTO_MUTEX *mutex)
392
0
{
393
0
    int rfd, wfd;
394
395
0
    if (!poll_descriptor_to_fd(r, &rfd)
396
0
        || !poll_descriptor_to_fd(w, &wfd))
397
0
        return 0;
398
399
0
    return poll_two_fds(rfd, r_want_read, wfd, w_want_write,
400
0
                        notify_rfd, deadline, mutex);
401
0
}
402
403
/*
404
 * Notify other threads currently blocking in
405
 * ossl_quic_reactor_block_until_pred() calls that a predicate they are using
406
 * might now be met due to state changes.
407
 *
408
 * This function must be called after state changes which might cause a
409
 * predicate in another thread to now be met (i.e., ticking). It is a no-op if
410
 * inter-thread notification is not being used.
411
 *
412
 * The reactor mutex must be held while calling this function.
413
 */
414
static void rtor_notify_other_threads(QUIC_REACTOR *rtor)
415
0
{
416
0
    if (!rtor->have_notifier)
417
0
        return;
418
419
    /*
420
     * This function is called when we have done anything on this thread which
421
     * might allow a predicate for a block_until_pred call on another thread to
422
     * now be met.
423
     *
424
     * When this happens, we need to wake those threads using the notifier.
425
     * However, we do not want to wake *this* thread (if/when it subsequently
426
     * enters block_until_pred) due to the notifier FD becoming readable.
427
     * Therefore, signal the notifier, and use a CV to detect when all other
428
     * threads have woken.
429
     */
430
431
0
   if (rtor->cur_blocking_waiters == 0)
432
       /* Nothing to do in this case. */
433
0
       return;
434
435
   /* Signal the notifier to wake up all threads. */
436
0
   if (!rtor->signalled_notifier) {
437
0
       ossl_rio_notifier_signal(&rtor->notifier);
438
0
       rtor->signalled_notifier = 1;
439
0
   }
440
441
   /*
442
    * Wait on the CV until all threads have finished the first phase of the
443
    * wakeup process and the last thread out has taken responsibility for
444
    * unsignalling the notifier.
445
    */
446
0
    while (rtor->signalled_notifier)
447
0
        ossl_crypto_condvar_wait(rtor->notifier_cv, rtor->mutex);
448
0
}
449
450
/*
451
 * Block until a predicate function evaluates to true.
452
 *
453
 * If mutex is non-NULL, it is assumed be a lock currently held for write and is
454
 * unlocked for the duration of any wait.
455
 *
456
 * Precondition:   Must hold channel write lock (unchecked)
457
 * Precondition:   mutex is NULL or is held for write (unchecked)
458
 * Postcondition:  mutex is NULL or is held for write (unless
459
 *                   CRYPTO_THREAD_write_lock fails)
460
 */
461
int ossl_quic_reactor_block_until_pred(QUIC_REACTOR *rtor,
462
                                       int (*pred)(void *arg), void *pred_arg,
463
                                       uint32_t flags)
464
0
{
465
0
    int res, net_read_desired, net_write_desired, notifier_fd;
466
0
    OSSL_TIME tick_deadline;
467
468
0
    notifier_fd
469
0
        = (rtor->have_notifier ? ossl_rio_notifier_as_fd(&rtor->notifier)
470
0
                               : INVALID_SOCKET);
471
472
0
    for (;;) {
473
0
        if ((flags & SKIP_FIRST_TICK) != 0)
474
0
            flags &= ~SKIP_FIRST_TICK;
475
0
        else
476
            /* best effort */
477
0
            ossl_quic_reactor_tick(rtor, 0);
478
479
0
        if ((res = pred(pred_arg)) != 0)
480
0
            return res;
481
482
0
        net_read_desired  = ossl_quic_reactor_net_read_desired(rtor);
483
0
        net_write_desired = ossl_quic_reactor_net_write_desired(rtor);
484
0
        tick_deadline     = ossl_quic_reactor_get_tick_deadline(rtor);
485
0
        if (!net_read_desired && !net_write_desired
486
0
            && ossl_time_is_infinite(tick_deadline))
487
            /* Can't wait if there is nothing to wait for. */
488
0
            return 0;
489
490
0
        ossl_quic_reactor_enter_blocking_section(rtor);
491
492
0
        res = poll_two_descriptors(ossl_quic_reactor_get_poll_r(rtor),
493
0
                                   net_read_desired,
494
0
                                   ossl_quic_reactor_get_poll_w(rtor),
495
0
                                   net_write_desired,
496
0
                                   notifier_fd,
497
0
                                   tick_deadline,
498
0
                                   rtor->mutex);
499
500
        /*
501
         * We have now exited the OS poller call. We may have
502
         * (rtor->signalled_notifier), and other threads may still be blocking.
503
         * This means that cur_blocking_waiters may still be non-zero. As such,
504
         * we cannot unsignal the notifier until all threads have had an
505
         * opportunity to wake up.
506
         *
507
         * At the same time, we cannot unsignal in the case where
508
         * cur_blocking_waiters is now zero because this condition may not occur
509
         * reliably. Consider the following scenario:
510
         *
511
         *   T1 enters block_until_pred, cur_blocking_waiters -> 1
512
         *   T2 enters block_until_pred, cur_blocking_waiters -> 2
513
         *   T3 enters block_until_pred, cur_blocking_waiters -> 3
514
         *
515
         *   T4 enters block_until_pred, does not block, ticks,
516
         *     sees that cur_blocking_waiters > 0 and signals the notifier
517
         *
518
         *   T3 wakes, cur_blocking_waiters -> 2
519
         *   T3 predicate is not satisfied, cur_blocking_waiters -> 3, block again
520
         *
521
         *   Notifier is still signalled, so T3 immediately wakes again
522
         *   and is stuck repeating the above steps.
523
         *
524
         *   T1, T2 are also woken by the notifier but never see
525
         *   cur_blocking_waiters drop to 0, so never unsignal the notifier.
526
         *
527
         * As such, a two phase approach is chosen when designalling the
528
         * notifier:
529
         *
530
         *   First, all of the poll_two_descriptor calls on all threads are
531
         *   allowed to exit due to the notifier being signalled.
532
         *
533
         *   Second, the thread which happened to be the one which decremented
534
         *   cur_blocking_waiters to 0 unsignals the notifier and is then
535
         *   responsible for broadcasting to a CV to indicate to the other
536
         *   threads that the synchronised wakeup has been completed. Other
537
         *   threads wait for this CV to be signalled.
538
         *
539
         */
540
0
        ossl_quic_reactor_leave_blocking_section(rtor);
541
542
0
        if (!res)
543
            /*
544
             * We don't actually care why the call succeeded (timeout, FD
545
             * readiness), we just call reactor_tick and start trying to do I/O
546
             * things again. If poll_two_fds returns 0, this is some other
547
             * non-timeout failure and we should stop here.
548
             *
549
             * TODO(QUIC FUTURE): In the future we could avoid unnecessary
550
             * syscalls by not retrying network I/O that isn't ready based
551
             * on the result of the poll call. However this might be difficult
552
             * because it requires we do the call to poll(2) or equivalent
553
             * syscall ourselves, whereas in the general case the application
554
             * does the polling and just calls SSL_handle_events().
555
             * Implementing this optimisation in the future will probably
556
             * therefore require API changes.
557
             */
558
0
            return 0;
559
0
    }
560
561
0
    return res;
562
0
}
563
564
void ossl_quic_reactor_enter_blocking_section(QUIC_REACTOR *rtor)
565
0
{
566
0
    ++rtor->cur_blocking_waiters;
567
0
}
568
569
void ossl_quic_reactor_leave_blocking_section(QUIC_REACTOR *rtor)
570
0
{
571
0
    assert(rtor->cur_blocking_waiters > 0);
572
0
    --rtor->cur_blocking_waiters;
573
574
0
    if (rtor->have_notifier && rtor->signalled_notifier) {
575
0
        if (rtor->cur_blocking_waiters == 0) {
576
0
            ossl_rio_notifier_unsignal(&rtor->notifier);
577
0
            rtor->signalled_notifier = 0;
578
579
            /*
580
             * Release the other threads which have woken up (and possibly
581
             * rtor_notify_other_threads as well).
582
             */
583
0
            ossl_crypto_condvar_broadcast(rtor->notifier_cv);
584
0
        } else {
585
            /* We are not the last waiter out - so wait for that one. */
586
0
            while (rtor->signalled_notifier)
587
0
                ossl_crypto_condvar_wait(rtor->notifier_cv, rtor->mutex);
588
0
        }
589
0
    }
590
0
}