-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from #18345)
- Loading branch information
Showing
3 changed files
with
358 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
* 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 | ||
*/ | ||
|
||
#ifndef OSSL_INTERNAL_EVENT_QUEUE_H | ||
# define OSSL_INTERNAL_EVENT_QUEUE_H | ||
# pragma once | ||
|
||
# include "internal/priority_queue.h" | ||
# include "internal/time.h" | ||
|
||
/* | ||
* Opaque type holding an event. | ||
*/ | ||
typedef struct ossl_event_st OSSL_EVENT; | ||
|
||
DEFINE_PRIORITY_QUEUE_OF(OSSL_EVENT); | ||
|
||
/* | ||
* Public type representing an event queue, the underlying structure being | ||
* opaque. | ||
*/ | ||
typedef struct ossl_event_queue_st OSSL_EVENT_QUEUE; | ||
|
||
/* | ||
* Public type representing a event queue entry. | ||
* It is (internally) public so that it can be embedded into other structures, | ||
* it should otherwise be treated as opaque. | ||
*/ | ||
struct ossl_event_st { | ||
uint32_t type; /* What type of event this is */ | ||
uint32_t priority; /* What priority this event has */ | ||
OSSL_TIME when; /* When the event is scheduled to happen */ | ||
void *ctx; /* User argument passed to call backs */ | ||
void *payload; /* Event specific data of unknown kind */ | ||
size_t payload_size; /* Length (in bytes) of event specific data */ | ||
|
||
/* These fields are for internal use only */ | ||
PRIORITY_QUEUE_OF(OSSL_EVENT) *queue; /* Queue containing this event */ | ||
size_t ref; /* ID for this event */ | ||
unsigned int flag_dynamic : 1; /* Malloced or not? */ | ||
}; | ||
|
||
/* | ||
* Utility function to populate an event structure and add it to the queue | ||
*/ | ||
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); | ||
|
||
/* | ||
* Utility functions to extract event fields | ||
*/ | ||
static ossl_unused ossl_inline | ||
uint32_t ossl_event_get_type(const OSSL_EVENT *event) | ||
{ | ||
return event->type; | ||
} | ||
|
||
static ossl_unused ossl_inline | ||
uint32_t ossl_event_get_priority(const OSSL_EVENT *event) | ||
{ | ||
return event->priority; | ||
} | ||
|
||
static ossl_unused ossl_inline | ||
OSSL_TIME ossl_event_get_when(const OSSL_EVENT *event) | ||
{ | ||
return event->when; | ||
} | ||
|
||
static ossl_unused ossl_inline | ||
void *ossl_event_get0_ctx(const OSSL_EVENT *event) | ||
{ | ||
return event->ctx; | ||
} | ||
|
||
static ossl_unused ossl_inline | ||
void *ossl_event_get0_payload(const OSSL_EVENT *event, size_t *length) | ||
{ | ||
if (length != NULL) | ||
*length = event->payload_size; | ||
return event->payload; | ||
} | ||
|
||
/* | ||
* Create and free a queue. | ||
*/ | ||
OSSL_EVENT_QUEUE *ossl_event_queue_new(void); | ||
void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue); | ||
|
||
/* | ||
* Schedule a new event into an event queue. | ||
* | ||
* The event parameters are taken from the function arguments. | ||
* | ||
* The function reutrns NULL on failure and the added event on success. | ||
*/ | ||
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) | ||
; | ||
|
||
/* | ||
* Schedule an event into an event queue. | ||
* | ||
* The event parameters are taken from the function arguments. | ||
* | ||
* The function reutrns 0 on failure and 1 on success. | ||
*/ | ||
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); | ||
|
||
/* | ||
* Delete an event from the queue. | ||
* This will cause the early deletion function to be called if it is non-NULL. | ||
* A pointer to the event structure is returned. | ||
*/ | ||
int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event); | ||
|
||
/* | ||
* Free a dynamic event. | ||
* Is a NOP for a static event. | ||
*/ | ||
void ossl_event_free(OSSL_EVENT *event); | ||
|
||
/* | ||
* Return the time until the next event for the specified event, if the event's | ||
* time is past, zero is returned. Once activated, the event reference becomes | ||
* invalid and this function becomes undefined. | ||
*/ | ||
OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event); | ||
|
||
/* | ||
* Return the time until the next event in the queue. | ||
* If the next event is in the past, zero is returned. | ||
*/ | ||
OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue); | ||
|
||
/* | ||
* Postpone an event to trigger at the specified time. | ||
* If the event has triggered, this function's behaviour is undefined. | ||
*/ | ||
int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue, | ||
OSSL_EVENT *event, | ||
OSSL_TIME when); | ||
|
||
/* | ||
* Return the next event to process. | ||
*/ | ||
int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue, | ||
OSSL_EVENT **event); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |