summaryrefslogtreecommitdiffstats
path: root/ssl/event_queue.c
diff options
context:
space:
mode:
authorPauli <pauli@openssl.org>2022-05-10 12:05:11 +1000
committerPauli <pauli@openssl.org>2022-07-06 10:33:11 +1000
commite6be47e427fb6650f274c418947e7665fbe08889 (patch)
tree3d4bc858454690b7aca6e11a2025d1a254236241 /ssl/event_queue.c
parent16612c19290d712de65a7adcb043ba91165f3e0f (diff)
ssl: implement an event queue
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18345)
Diffstat (limited to 'ssl/event_queue.c')
-rw-r--r--ssl/event_queue.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/ssl/event_queue.c b/ssl/event_queue.c
new file mode 100644
index 0000000000..f828d5280f
--- /dev/null
+++ b/ssl/event_queue.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include "internal/event_queue.h"
+#include "crypto/sparse_array.h"
+#include "ssl_local.h"
+
+struct ossl_event_queue_st {
+ PRIORITY_QUEUE_OF(OSSL_EVENT) *timed_events;
+ PRIORITY_QUEUE_OF(OSSL_EVENT) *now_events;
+};
+
+static int event_compare_times(const OSSL_EVENT *a, const OSSL_EVENT *b)
+{
+ return ossl_time_compare(a->when, b->when);
+}
+
+static int event_compare_priority(const OSSL_EVENT *a, const OSSL_EVENT *b)
+{
+ if (a->priority > b->priority)
+ return -1;
+ if (a->priority < b->priority)
+ return 1;
+ return 0;
+}
+
+OSSL_EVENT_QUEUE *ossl_event_queue_new(void)
+{
+ OSSL_EVENT_QUEUE *r = OPENSSL_malloc(sizeof(*r));
+
+ if (r != NULL) {
+ r->timed_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_times);
+ r->now_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_priority);
+ if (r->timed_events == NULL || r->now_events == NULL) {
+ ossl_event_queue_free(r);
+ return NULL;
+ }
+ }
+ return r;
+}
+
+void ossl_event_free(OSSL_EVENT *event)
+{
+ if (event != NULL) {
+ if (event->flag_dynamic)
+ OPENSSL_free(event);
+ else
+ event->queue = NULL;
+ }
+}
+
+static void event_queue_free(PRIORITY_QUEUE_OF(OSSL_EVENT) *queue)
+{
+ OSSL_EVENT *e;
+
+ if (queue != NULL) {
+ while ((e = ossl_pqueue_OSSL_EVENT_pop(queue)) != NULL)
+ ossl_event_free(e);
+ ossl_pqueue_OSSL_EVENT_free(queue);
+ }
+}
+
+void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue)
+{
+ if (queue != NULL) {
+ event_queue_free(queue->now_events);
+ event_queue_free(queue->timed_events);
+ OPENSSL_free(queue);
+ }
+}
+
+static ossl_inline
+int event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
+{
+ PRIORITY_QUEUE_OF(OSSL_EVENT) *pq =
+ ossl_time_compare(event->when, ossl_time_now()) <= 0
+ ? queue->now_events
+ : queue->timed_events;
+
+ if (ossl_pqueue_OSSL_EVENT_push(pq, event, &event->ref)) {
+ event->queue = pq;
+ return 1;
+ }
+ return 0;
+}
+
+static ossl_inline
+void ossl_event_set(OSSL_EVENT *event, uint32_t type, uint32_t priority,
+ OSSL_TIME when, void *ctx,
+ void *payload, size_t payload_size)
+{
+ event->type = type;
+ event->priority = priority;
+ event->when = when;
+ event->ctx = ctx;
+ event->payload = payload;
+ event->payload_size = payload_size;
+}
+
+OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
+ uint32_t type, uint32_t priority,
+ OSSL_TIME when, void *ctx,
+ void *payload, size_t payload_size)
+{
+ OSSL_EVENT *e = OPENSSL_malloc(sizeof(*e));
+
+ if (e == NULL || queue == NULL)
+ return NULL;
+ ossl_event_set(e, type, priority, when, ctx, payload, payload_size);
+ e->flag_dynamic = 1;
+ if (event_queue_add(queue, e))
+ return e;
+ OPENSSL_free(e);
+ return NULL;
+}
+
+int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
+ uint32_t type, uint32_t priority,
+ OSSL_TIME when, void *ctx,
+ void *payload, size_t payload_size)
+{
+ if (event == NULL || queue == NULL)
+ return 0;
+ ossl_event_set(event, type, priority, when, ctx, payload, payload_size);
+ event->flag_dynamic = 0;
+ return event_queue_add(queue, event);
+}
+
+int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
+{
+ if (event != NULL && event->queue != NULL) {
+ ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref);
+ event->queue = NULL;
+ }
+ return 1;
+}
+
+OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event)
+{
+ if (event == NULL)
+ return OSSL_TIME_INFINITY;
+ return ossl_time_subtract(event->when, ossl_time_now());
+}
+
+OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue)
+{
+ if (queue == NULL)
+ return OSSL_TIME_INFINITY;
+ if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0)
+ return OSSL_TIME_IMMEDIATE;
+ return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events));
+}
+
+int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
+ OSSL_EVENT *event,
+ OSSL_TIME when)
+{
+ if (ossl_event_queue_remove(queue, event)) {
+ event->when = when;
+ return event_queue_add(queue, event);
+ }
+ return 0;
+}
+
+int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
+ OSSL_EVENT **event)
+{
+ OSSL_TIME now = ossl_time_now();
+ OSSL_EVENT *e;
+
+ /* Check for expired timer based events and convert them to now events */
+ while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL
+ && ossl_time_compare(e->when, now) <= 0) {
+ e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events);
+ if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) {
+ e->queue = NULL;
+ return 0;
+ }
+ }
+
+ /*
+ * Get next event from the now queue.
+ * The pop returns NULL when there is none.
+ */
+ *event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events);
+ return 1;
+}