2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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
11 #include "internal/event_queue.h"
12 #include "crypto/sparse_array.h"
13 #include "ssl_local.h"
15 struct ossl_event_queue_st {
16 PRIORITY_QUEUE_OF(OSSL_EVENT) *timed_events;
17 PRIORITY_QUEUE_OF(OSSL_EVENT) *now_events;
20 static int event_compare_times(const OSSL_EVENT *a, const OSSL_EVENT *b)
22 return ossl_time_compare(a->when, b->when);
25 static int event_compare_priority(const OSSL_EVENT *a, const OSSL_EVENT *b)
27 if (a->priority > b->priority)
29 if (a->priority < b->priority)
34 OSSL_EVENT_QUEUE *ossl_event_queue_new(void)
36 OSSL_EVENT_QUEUE *r = OPENSSL_malloc(sizeof(*r));
39 r->timed_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_times);
40 r->now_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_priority);
41 if (r->timed_events == NULL || r->now_events == NULL) {
42 ossl_event_queue_free(r);
49 void ossl_event_free(OSSL_EVENT *event)
52 if (event->flag_dynamic)
59 static void event_queue_free(PRIORITY_QUEUE_OF(OSSL_EVENT) *queue)
64 while ((e = ossl_pqueue_OSSL_EVENT_pop(queue)) != NULL)
66 ossl_pqueue_OSSL_EVENT_free(queue);
70 void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue)
73 event_queue_free(queue->now_events);
74 event_queue_free(queue->timed_events);
80 int event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
82 PRIORITY_QUEUE_OF(OSSL_EVENT) *pq =
83 ossl_time_compare(event->when, ossl_time_now()) <= 0
85 : queue->timed_events;
87 if (ossl_pqueue_OSSL_EVENT_push(pq, event, &event->ref)) {
95 void ossl_event_set(OSSL_EVENT *event, uint32_t type, uint32_t priority,
96 OSSL_TIME when, void *ctx,
97 void *payload, size_t payload_size)
100 event->priority = priority;
103 event->payload = payload;
104 event->payload_size = payload_size;
107 OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
108 uint32_t type, uint32_t priority,
109 OSSL_TIME when, void *ctx,
110 void *payload, size_t payload_size)
112 OSSL_EVENT *e = OPENSSL_malloc(sizeof(*e));
114 if (e == NULL || queue == NULL)
116 ossl_event_set(e, type, priority, when, ctx, payload, payload_size);
118 if (event_queue_add(queue, e))
124 int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
125 uint32_t type, uint32_t priority,
126 OSSL_TIME when, void *ctx,
127 void *payload, size_t payload_size)
129 if (event == NULL || queue == NULL)
131 ossl_event_set(event, type, priority, when, ctx, payload, payload_size);
132 event->flag_dynamic = 0;
133 return event_queue_add(queue, event);
136 int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
138 if (event != NULL && event->queue != NULL) {
139 ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref);
145 OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event)
148 return ossl_time_infinite();
149 return ossl_time_subtract(event->when, ossl_time_now());
152 OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue)
155 return ossl_time_infinite();
156 if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0)
157 return ossl_time_zero();
158 return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events));
161 int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
165 if (ossl_event_queue_remove(queue, event)) {
167 return event_queue_add(queue, event);
172 int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
175 OSSL_TIME now = ossl_time_now();
178 /* Check for expired timer based events and convert them to now events */
179 while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL
180 && ossl_time_compare(e->when, now) <= 0) {
181 e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events);
182 if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) {
189 * Get next event from the now queue.
190 * The pop returns NULL when there is none.
192 *event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events);