xref: /src/crypto/openssl/ssl/priority_queue.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
109a25192SPierre Pronchery /*
209a25192SPierre Pronchery  * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
309a25192SPierre Pronchery  *
409a25192SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
509a25192SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
609a25192SPierre Pronchery  * in the file LICENSE in the source distribution or at
709a25192SPierre Pronchery  * https://www.openssl.org/source/license.html
809a25192SPierre Pronchery  */
909a25192SPierre Pronchery 
1009a25192SPierre Pronchery #include <openssl/crypto.h>
1109a25192SPierre Pronchery #include <openssl/err.h>
1209a25192SPierre Pronchery #include <assert.h>
1309a25192SPierre Pronchery #include "internal/priority_queue.h"
1409a25192SPierre Pronchery #include "internal/safe_math.h"
1509a25192SPierre Pronchery #include "internal/numbers.h"
1609a25192SPierre Pronchery 
1709a25192SPierre Pronchery OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
1809a25192SPierre Pronchery 
1909a25192SPierre Pronchery /*
2009a25192SPierre Pronchery  * Fundamental operations:
2109a25192SPierre Pronchery  *                        Binary Heap   Fibonacci Heap
2209a25192SPierre Pronchery  *  Get smallest            O(1)          O(1)
2309a25192SPierre Pronchery  *  Delete any              O(log n)      O(log n) average but worst O(n)
2409a25192SPierre Pronchery  *  Insert                  O(log n)      O(1)
2509a25192SPierre Pronchery  *
2609a25192SPierre Pronchery  * Not supported:
2709a25192SPierre Pronchery  *  Merge two structures    O(log n)      O(1)
2809a25192SPierre Pronchery  *  Decrease key            O(log n)      O(1)
2909a25192SPierre Pronchery  *  Increase key            O(log n)      ?
3009a25192SPierre Pronchery  *
3109a25192SPierre Pronchery  * The Fibonacci heap is quite a bit more complicated to implement and has
3209a25192SPierre Pronchery  * larger overhead in practice.  We favour the binary heap here.  A multi-way
3309a25192SPierre Pronchery  * (ternary or quaternary) heap might elicit a performance advantage via better
3409a25192SPierre Pronchery  * cache access patterns.
3509a25192SPierre Pronchery  */
3609a25192SPierre Pronchery 
3709a25192SPierre Pronchery struct pq_heap_st {
3809a25192SPierre Pronchery     void *data; /* User supplied data pointer */
3909a25192SPierre Pronchery     size_t index; /* Constant index in elements[] */
4009a25192SPierre Pronchery };
4109a25192SPierre Pronchery 
4209a25192SPierre Pronchery struct pq_elem_st {
4309a25192SPierre Pronchery     size_t posn; /* Current index in heap[] or link in free list */
4409a25192SPierre Pronchery #ifndef NDEBUG
4509a25192SPierre Pronchery     int used; /* Debug flag indicating that this is in use */
4609a25192SPierre Pronchery #endif
4709a25192SPierre Pronchery };
4809a25192SPierre Pronchery 
4909a25192SPierre Pronchery struct ossl_pqueue_st {
5009a25192SPierre Pronchery     struct pq_heap_st *heap;
5109a25192SPierre Pronchery     struct pq_elem_st *elements;
5209a25192SPierre Pronchery     int (*compare)(const void *, const void *);
5309a25192SPierre Pronchery     size_t htop; /* Highest used heap element */
5409a25192SPierre Pronchery     size_t hmax; /* Allocated heap & element space */
5509a25192SPierre Pronchery     size_t freelist; /* Index into elements[], start of free element list */
5609a25192SPierre Pronchery };
5709a25192SPierre Pronchery 
5809a25192SPierre Pronchery /*
5909a25192SPierre Pronchery  * The initial and maximum number of elements in the heap.
6009a25192SPierre Pronchery  */
6109a25192SPierre Pronchery static const size_t min_nodes = 8;
62808413daSEnji Cooper static const size_t max_nodes = SIZE_MAX / (sizeof(struct pq_heap_st) > sizeof(struct pq_elem_st) ? sizeof(struct pq_heap_st) : sizeof(struct pq_elem_st));
6309a25192SPierre Pronchery 
6409a25192SPierre Pronchery #ifndef NDEBUG
6509a25192SPierre Pronchery /* Some basic sanity checking of the data structure */
6609a25192SPierre Pronchery #define ASSERT_USED(pq, idx)                        \
6709a25192SPierre Pronchery     assert(pq->elements[pq->heap[idx].index].used); \
6809a25192SPierre Pronchery     assert(pq->elements[pq->heap[idx].index].posn == idx)
6909a25192SPierre Pronchery #define ASSERT_ELEM_USED(pq, elem) \
7009a25192SPierre Pronchery     assert(pq->elements[elem].used)
7109a25192SPierre Pronchery #else
7209a25192SPierre Pronchery #define ASSERT_USED(pq, idx)
7309a25192SPierre Pronchery #define ASSERT_ELEM_USED(pq, elem)
7409a25192SPierre Pronchery #endif
7509a25192SPierre Pronchery 
7609a25192SPierre Pronchery /*
7709a25192SPierre Pronchery  * Calculate the array growth based on the target size.
7809a25192SPierre Pronchery  *
7909a25192SPierre Pronchery  * The growth factor is a rational number and is defined by a numerator
8009a25192SPierre Pronchery  * and a denominator.  According to Andrew Koenig in his paper "Why Are
8109a25192SPierre Pronchery  * Vectors Efficient?" from JOOP 11(5) 1998, this factor should be less
8209a25192SPierre Pronchery  * than the golden ratio (1.618...).
8309a25192SPierre Pronchery  *
8409a25192SPierre Pronchery  * We use an expansion factor of 8 / 5 = 1.6
8509a25192SPierre Pronchery  */
compute_pqueue_growth(size_t target,size_t current)8609a25192SPierre Pronchery static ossl_inline size_t compute_pqueue_growth(size_t target, size_t current)
8709a25192SPierre Pronchery {
8809a25192SPierre Pronchery     int err = 0;
8909a25192SPierre Pronchery 
9009a25192SPierre Pronchery     while (current < target) {
9109a25192SPierre Pronchery         if (current >= max_nodes)
9209a25192SPierre Pronchery             return 0;
9309a25192SPierre Pronchery 
9409a25192SPierre Pronchery         current = safe_muldiv_size_t(current, 8, 5, &err);
9509a25192SPierre Pronchery         if (err)
9609a25192SPierre Pronchery             return 0;
9709a25192SPierre Pronchery         if (current >= max_nodes)
9809a25192SPierre Pronchery             current = max_nodes;
9909a25192SPierre Pronchery     }
10009a25192SPierre Pronchery     return current;
10109a25192SPierre Pronchery }
10209a25192SPierre Pronchery 
pqueue_swap_elem(OSSL_PQUEUE * pq,size_t i,size_t j)10309a25192SPierre Pronchery static ossl_inline void pqueue_swap_elem(OSSL_PQUEUE *pq, size_t i, size_t j)
10409a25192SPierre Pronchery {
10509a25192SPierre Pronchery     struct pq_heap_st *h = pq->heap, t_h;
10609a25192SPierre Pronchery     struct pq_elem_st *e = pq->elements;
10709a25192SPierre Pronchery 
10809a25192SPierre Pronchery     ASSERT_USED(pq, i);
10909a25192SPierre Pronchery     ASSERT_USED(pq, j);
11009a25192SPierre Pronchery 
11109a25192SPierre Pronchery     t_h = h[i];
11209a25192SPierre Pronchery     h[i] = h[j];
11309a25192SPierre Pronchery     h[j] = t_h;
11409a25192SPierre Pronchery 
11509a25192SPierre Pronchery     e[h[i].index].posn = i;
11609a25192SPierre Pronchery     e[h[j].index].posn = j;
11709a25192SPierre Pronchery }
11809a25192SPierre Pronchery 
pqueue_move_elem(OSSL_PQUEUE * pq,size_t from,size_t to)11909a25192SPierre Pronchery static ossl_inline void pqueue_move_elem(OSSL_PQUEUE *pq, size_t from, size_t to)
12009a25192SPierre Pronchery {
12109a25192SPierre Pronchery     struct pq_heap_st *h = pq->heap;
12209a25192SPierre Pronchery     struct pq_elem_st *e = pq->elements;
12309a25192SPierre Pronchery 
12409a25192SPierre Pronchery     ASSERT_USED(pq, from);
12509a25192SPierre Pronchery 
12609a25192SPierre Pronchery     h[to] = h[from];
12709a25192SPierre Pronchery     e[h[to].index].posn = to;
12809a25192SPierre Pronchery }
12909a25192SPierre Pronchery 
13009a25192SPierre Pronchery /*
13109a25192SPierre Pronchery  * Force the specified element to the front of the heap.  This breaks
13209a25192SPierre Pronchery  * the heap partial ordering pre-condition.
13309a25192SPierre Pronchery  */
pqueue_force_bottom(OSSL_PQUEUE * pq,size_t n)13409a25192SPierre Pronchery static ossl_inline void pqueue_force_bottom(OSSL_PQUEUE *pq, size_t n)
13509a25192SPierre Pronchery {
13609a25192SPierre Pronchery     ASSERT_USED(pq, n);
13709a25192SPierre Pronchery     while (n > 0) {
13809a25192SPierre Pronchery         const size_t p = (n - 1) / 2;
13909a25192SPierre Pronchery 
14009a25192SPierre Pronchery         ASSERT_USED(pq, p);
14109a25192SPierre Pronchery         pqueue_swap_elem(pq, n, p);
14209a25192SPierre Pronchery         n = p;
14309a25192SPierre Pronchery     }
14409a25192SPierre Pronchery }
14509a25192SPierre Pronchery 
14609a25192SPierre Pronchery /*
14709a25192SPierre Pronchery  * Move an element down to its correct position to restore the partial
14809a25192SPierre Pronchery  * order pre-condition.
14909a25192SPierre Pronchery  */
pqueue_move_down(OSSL_PQUEUE * pq,size_t n)15009a25192SPierre Pronchery static ossl_inline void pqueue_move_down(OSSL_PQUEUE *pq, size_t n)
15109a25192SPierre Pronchery {
15209a25192SPierre Pronchery     struct pq_heap_st *h = pq->heap;
15309a25192SPierre Pronchery 
15409a25192SPierre Pronchery     ASSERT_USED(pq, n);
15509a25192SPierre Pronchery     while (n > 0) {
15609a25192SPierre Pronchery         const size_t p = (n - 1) / 2;
15709a25192SPierre Pronchery 
15809a25192SPierre Pronchery         ASSERT_USED(pq, p);
15909a25192SPierre Pronchery         if (pq->compare(h[n].data, h[p].data) >= 0)
16009a25192SPierre Pronchery             break;
16109a25192SPierre Pronchery         pqueue_swap_elem(pq, n, p);
16209a25192SPierre Pronchery         n = p;
16309a25192SPierre Pronchery     }
16409a25192SPierre Pronchery }
16509a25192SPierre Pronchery 
16609a25192SPierre Pronchery /*
16709a25192SPierre Pronchery  * Move an element up to its correct position to restore the partial
16809a25192SPierre Pronchery  * order pre-condition.
16909a25192SPierre Pronchery  */
pqueue_move_up(OSSL_PQUEUE * pq,size_t n)17009a25192SPierre Pronchery static ossl_inline void pqueue_move_up(OSSL_PQUEUE *pq, size_t n)
17109a25192SPierre Pronchery {
17209a25192SPierre Pronchery     struct pq_heap_st *h = pq->heap;
17309a25192SPierre Pronchery     size_t p = n * 2 + 1;
17409a25192SPierre Pronchery 
17509a25192SPierre Pronchery     ASSERT_USED(pq, n);
17609a25192SPierre Pronchery     if (pq->htop > p + 1) {
17709a25192SPierre Pronchery         ASSERT_USED(pq, p);
17809a25192SPierre Pronchery         ASSERT_USED(pq, p + 1);
17909a25192SPierre Pronchery         if (pq->compare(h[p].data, h[p + 1].data) > 0)
18009a25192SPierre Pronchery             p++;
18109a25192SPierre Pronchery     }
18209a25192SPierre Pronchery     while (pq->htop > p && pq->compare(h[p].data, h[n].data) < 0) {
18309a25192SPierre Pronchery         ASSERT_USED(pq, p);
18409a25192SPierre Pronchery         pqueue_swap_elem(pq, n, p);
18509a25192SPierre Pronchery         n = p;
18609a25192SPierre Pronchery         p = n * 2 + 1;
18709a25192SPierre Pronchery         if (pq->htop > p + 1) {
18809a25192SPierre Pronchery             ASSERT_USED(pq, p + 1);
18909a25192SPierre Pronchery             if (pq->compare(h[p].data, h[p + 1].data) > 0)
19009a25192SPierre Pronchery                 p++;
19109a25192SPierre Pronchery         }
19209a25192SPierre Pronchery     }
19309a25192SPierre Pronchery }
19409a25192SPierre Pronchery 
ossl_pqueue_push(OSSL_PQUEUE * pq,void * data,size_t * elem)19509a25192SPierre Pronchery int ossl_pqueue_push(OSSL_PQUEUE *pq, void *data, size_t *elem)
19609a25192SPierre Pronchery {
19709a25192SPierre Pronchery     size_t n, m;
19809a25192SPierre Pronchery 
19909a25192SPierre Pronchery     if (!ossl_pqueue_reserve(pq, 1))
20009a25192SPierre Pronchery         return 0;
20109a25192SPierre Pronchery 
20209a25192SPierre Pronchery     n = pq->htop++;
20309a25192SPierre Pronchery     m = pq->freelist;
20409a25192SPierre Pronchery     pq->freelist = pq->elements[m].posn;
20509a25192SPierre Pronchery 
20609a25192SPierre Pronchery     pq->heap[n].data = data;
20709a25192SPierre Pronchery     pq->heap[n].index = m;
20809a25192SPierre Pronchery 
20909a25192SPierre Pronchery     pq->elements[m].posn = n;
21009a25192SPierre Pronchery #ifndef NDEBUG
21109a25192SPierre Pronchery     pq->elements[m].used = 1;
21209a25192SPierre Pronchery #endif
21309a25192SPierre Pronchery     pqueue_move_down(pq, n);
21409a25192SPierre Pronchery     if (elem != NULL)
21509a25192SPierre Pronchery         *elem = m;
21609a25192SPierre Pronchery     return 1;
21709a25192SPierre Pronchery }
21809a25192SPierre Pronchery 
ossl_pqueue_peek(const OSSL_PQUEUE * pq)21909a25192SPierre Pronchery void *ossl_pqueue_peek(const OSSL_PQUEUE *pq)
22009a25192SPierre Pronchery {
22109a25192SPierre Pronchery     if (pq->htop > 0) {
22209a25192SPierre Pronchery         ASSERT_USED(pq, 0);
22309a25192SPierre Pronchery         return pq->heap->data;
22409a25192SPierre Pronchery     }
22509a25192SPierre Pronchery     return NULL;
22609a25192SPierre Pronchery }
22709a25192SPierre Pronchery 
ossl_pqueue_pop(OSSL_PQUEUE * pq)22809a25192SPierre Pronchery void *ossl_pqueue_pop(OSSL_PQUEUE *pq)
22909a25192SPierre Pronchery {
23009a25192SPierre Pronchery     void *res;
23109a25192SPierre Pronchery     size_t elem;
23209a25192SPierre Pronchery 
23309a25192SPierre Pronchery     if (pq == NULL || pq->htop == 0)
23409a25192SPierre Pronchery         return NULL;
23509a25192SPierre Pronchery 
23609a25192SPierre Pronchery     ASSERT_USED(pq, 0);
23709a25192SPierre Pronchery     res = pq->heap->data;
23809a25192SPierre Pronchery     elem = pq->heap->index;
23909a25192SPierre Pronchery 
24009a25192SPierre Pronchery     if (--pq->htop != 0) {
24109a25192SPierre Pronchery         pqueue_move_elem(pq, pq->htop, 0);
24209a25192SPierre Pronchery         pqueue_move_up(pq, 0);
24309a25192SPierre Pronchery     }
24409a25192SPierre Pronchery 
24509a25192SPierre Pronchery     pq->elements[elem].posn = pq->freelist;
24609a25192SPierre Pronchery     pq->freelist = elem;
24709a25192SPierre Pronchery #ifndef NDEBUG
24809a25192SPierre Pronchery     pq->elements[elem].used = 0;
24909a25192SPierre Pronchery #endif
25009a25192SPierre Pronchery     return res;
25109a25192SPierre Pronchery }
25209a25192SPierre Pronchery 
ossl_pqueue_remove(OSSL_PQUEUE * pq,size_t elem)25309a25192SPierre Pronchery void *ossl_pqueue_remove(OSSL_PQUEUE *pq, size_t elem)
25409a25192SPierre Pronchery {
25509a25192SPierre Pronchery     size_t n;
25609a25192SPierre Pronchery 
25709a25192SPierre Pronchery     if (pq == NULL || elem >= pq->hmax || pq->htop == 0)
25809a25192SPierre Pronchery         return 0;
25909a25192SPierre Pronchery 
26009a25192SPierre Pronchery     ASSERT_ELEM_USED(pq, elem);
26109a25192SPierre Pronchery     n = pq->elements[elem].posn;
26209a25192SPierre Pronchery 
26309a25192SPierre Pronchery     ASSERT_USED(pq, n);
26409a25192SPierre Pronchery 
26509a25192SPierre Pronchery     if (n == pq->htop - 1) {
26609a25192SPierre Pronchery         pq->elements[elem].posn = pq->freelist;
26709a25192SPierre Pronchery         pq->freelist = elem;
26809a25192SPierre Pronchery #ifndef NDEBUG
26909a25192SPierre Pronchery         pq->elements[elem].used = 0;
27009a25192SPierre Pronchery #endif
27109a25192SPierre Pronchery         return pq->heap[--pq->htop].data;
27209a25192SPierre Pronchery     }
27309a25192SPierre Pronchery     if (n > 0)
27409a25192SPierre Pronchery         pqueue_force_bottom(pq, n);
27509a25192SPierre Pronchery     return ossl_pqueue_pop(pq);
27609a25192SPierre Pronchery }
27709a25192SPierre Pronchery 
pqueue_add_freelist(OSSL_PQUEUE * pq,size_t from)27809a25192SPierre Pronchery static void pqueue_add_freelist(OSSL_PQUEUE *pq, size_t from)
27909a25192SPierre Pronchery {
28009a25192SPierre Pronchery     struct pq_elem_st *e = pq->elements;
28109a25192SPierre Pronchery     size_t i;
28209a25192SPierre Pronchery 
28309a25192SPierre Pronchery #ifndef NDEBUG
28409a25192SPierre Pronchery     for (i = from; i < pq->hmax; i++)
28509a25192SPierre Pronchery         e[i].used = 0;
28609a25192SPierre Pronchery #endif
28709a25192SPierre Pronchery     e[from].posn = pq->freelist;
28809a25192SPierre Pronchery     for (i = from + 1; i < pq->hmax; i++)
28909a25192SPierre Pronchery         e[i].posn = i - 1;
29009a25192SPierre Pronchery     pq->freelist = pq->hmax - 1;
29109a25192SPierre Pronchery }
29209a25192SPierre Pronchery 
ossl_pqueue_reserve(OSSL_PQUEUE * pq,size_t n)29309a25192SPierre Pronchery int ossl_pqueue_reserve(OSSL_PQUEUE *pq, size_t n)
29409a25192SPierre Pronchery {
29509a25192SPierre Pronchery     size_t new_max, cur_max;
29609a25192SPierre Pronchery     struct pq_heap_st *h;
29709a25192SPierre Pronchery     struct pq_elem_st *e;
29809a25192SPierre Pronchery 
29909a25192SPierre Pronchery     if (pq == NULL)
30009a25192SPierre Pronchery         return 0;
30109a25192SPierre Pronchery     cur_max = pq->hmax;
30209a25192SPierre Pronchery     if (pq->htop + n < cur_max)
30309a25192SPierre Pronchery         return 1;
30409a25192SPierre Pronchery 
30509a25192SPierre Pronchery     new_max = compute_pqueue_growth(n + cur_max, cur_max);
30609a25192SPierre Pronchery     if (new_max == 0) {
30709a25192SPierre Pronchery         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
30809a25192SPierre Pronchery         return 0;
30909a25192SPierre Pronchery     }
31009a25192SPierre Pronchery 
31109a25192SPierre Pronchery     h = OPENSSL_realloc(pq->heap, new_max * sizeof(*pq->heap));
31209a25192SPierre Pronchery     if (h == NULL)
31309a25192SPierre Pronchery         return 0;
31409a25192SPierre Pronchery     pq->heap = h;
31509a25192SPierre Pronchery 
31609a25192SPierre Pronchery     e = OPENSSL_realloc(pq->elements, new_max * sizeof(*pq->elements));
31709a25192SPierre Pronchery     if (e == NULL)
31809a25192SPierre Pronchery         return 0;
31909a25192SPierre Pronchery     pq->elements = e;
32009a25192SPierre Pronchery 
32109a25192SPierre Pronchery     pq->hmax = new_max;
32209a25192SPierre Pronchery     pqueue_add_freelist(pq, cur_max);
32309a25192SPierre Pronchery     return 1;
32409a25192SPierre Pronchery }
32509a25192SPierre Pronchery 
ossl_pqueue_new(int (* compare)(const void *,const void *))32609a25192SPierre Pronchery OSSL_PQUEUE *ossl_pqueue_new(int (*compare)(const void *, const void *))
32709a25192SPierre Pronchery {
32809a25192SPierre Pronchery     OSSL_PQUEUE *pq;
32909a25192SPierre Pronchery 
33009a25192SPierre Pronchery     if (compare == NULL)
33109a25192SPierre Pronchery         return NULL;
33209a25192SPierre Pronchery 
33309a25192SPierre Pronchery     pq = OPENSSL_malloc(sizeof(*pq));
33409a25192SPierre Pronchery     if (pq == NULL)
33509a25192SPierre Pronchery         return NULL;
33609a25192SPierre Pronchery     pq->compare = compare;
33709a25192SPierre Pronchery     pq->hmax = min_nodes;
33809a25192SPierre Pronchery     pq->htop = 0;
33909a25192SPierre Pronchery     pq->freelist = 0;
34009a25192SPierre Pronchery     pq->heap = OPENSSL_malloc(sizeof(*pq->heap) * min_nodes);
34109a25192SPierre Pronchery     pq->elements = OPENSSL_malloc(sizeof(*pq->elements) * min_nodes);
34209a25192SPierre Pronchery     if (pq->heap == NULL || pq->elements == NULL) {
34309a25192SPierre Pronchery         ossl_pqueue_free(pq);
34409a25192SPierre Pronchery         return NULL;
34509a25192SPierre Pronchery     }
34609a25192SPierre Pronchery     pqueue_add_freelist(pq, 0);
34709a25192SPierre Pronchery     return pq;
34809a25192SPierre Pronchery }
34909a25192SPierre Pronchery 
ossl_pqueue_free(OSSL_PQUEUE * pq)35009a25192SPierre Pronchery void ossl_pqueue_free(OSSL_PQUEUE *pq)
35109a25192SPierre Pronchery {
35209a25192SPierre Pronchery     if (pq != NULL) {
35309a25192SPierre Pronchery         OPENSSL_free(pq->heap);
35409a25192SPierre Pronchery         OPENSSL_free(pq->elements);
35509a25192SPierre Pronchery         OPENSSL_free(pq);
35609a25192SPierre Pronchery     }
35709a25192SPierre Pronchery }
35809a25192SPierre Pronchery 
ossl_pqueue_pop_free(OSSL_PQUEUE * pq,void (* freefunc)(void *))35909a25192SPierre Pronchery void ossl_pqueue_pop_free(OSSL_PQUEUE *pq, void (*freefunc)(void *))
36009a25192SPierre Pronchery {
36109a25192SPierre Pronchery     size_t i;
36209a25192SPierre Pronchery 
36309a25192SPierre Pronchery     if (pq != NULL) {
36409a25192SPierre Pronchery         for (i = 0; i < pq->htop; i++)
36509a25192SPierre Pronchery             (*freefunc)(pq->heap[i].data);
36609a25192SPierre Pronchery         ossl_pqueue_free(pq);
36709a25192SPierre Pronchery     }
36809a25192SPierre Pronchery }
36909a25192SPierre Pronchery 
ossl_pqueue_num(const OSSL_PQUEUE * pq)37009a25192SPierre Pronchery size_t ossl_pqueue_num(const OSSL_PQUEUE *pq)
37109a25192SPierre Pronchery {
37209a25192SPierre Pronchery     return pq != NULL ? pq->htop : 0;
37309a25192SPierre Pronchery }
374