event_queue.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright 2022 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 <stdlib.h>
  10. #include "internal/event_queue.h"
  11. #include "crypto/sparse_array.h"
  12. #include "ssl_local.h"
  13. struct ossl_event_queue_st {
  14. PRIORITY_QUEUE_OF(OSSL_EVENT) *timed_events;
  15. PRIORITY_QUEUE_OF(OSSL_EVENT) *now_events;
  16. };
  17. static int event_compare_times(const OSSL_EVENT *a, const OSSL_EVENT *b)
  18. {
  19. return ossl_time_compare(a->when, b->when);
  20. }
  21. static int event_compare_priority(const OSSL_EVENT *a, const OSSL_EVENT *b)
  22. {
  23. if (a->priority > b->priority)
  24. return -1;
  25. if (a->priority < b->priority)
  26. return 1;
  27. return 0;
  28. }
  29. OSSL_EVENT_QUEUE *ossl_event_queue_new(void)
  30. {
  31. OSSL_EVENT_QUEUE *r = OPENSSL_malloc(sizeof(*r));
  32. if (r != NULL) {
  33. r->timed_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_times);
  34. r->now_events = ossl_pqueue_OSSL_EVENT_new(&event_compare_priority);
  35. if (r->timed_events == NULL || r->now_events == NULL) {
  36. ossl_event_queue_free(r);
  37. return NULL;
  38. }
  39. }
  40. return r;
  41. }
  42. void ossl_event_free(OSSL_EVENT *event)
  43. {
  44. if (event != NULL) {
  45. if (event->flag_dynamic)
  46. OPENSSL_free(event);
  47. else
  48. event->queue = NULL;
  49. }
  50. }
  51. static void event_queue_free(PRIORITY_QUEUE_OF(OSSL_EVENT) *queue)
  52. {
  53. OSSL_EVENT *e;
  54. if (queue != NULL) {
  55. while ((e = ossl_pqueue_OSSL_EVENT_pop(queue)) != NULL)
  56. ossl_event_free(e);
  57. ossl_pqueue_OSSL_EVENT_free(queue);
  58. }
  59. }
  60. void ossl_event_queue_free(OSSL_EVENT_QUEUE *queue)
  61. {
  62. if (queue != NULL) {
  63. event_queue_free(queue->now_events);
  64. event_queue_free(queue->timed_events);
  65. OPENSSL_free(queue);
  66. }
  67. }
  68. static ossl_inline
  69. int event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
  70. {
  71. PRIORITY_QUEUE_OF(OSSL_EVENT) *pq =
  72. ossl_time_compare(event->when, ossl_time_now()) <= 0
  73. ? queue->now_events
  74. : queue->timed_events;
  75. if (ossl_pqueue_OSSL_EVENT_push(pq, event, &event->ref)) {
  76. event->queue = pq;
  77. return 1;
  78. }
  79. return 0;
  80. }
  81. static ossl_inline
  82. void ossl_event_set(OSSL_EVENT *event, uint32_t type, uint32_t priority,
  83. OSSL_TIME when, void *ctx,
  84. void *payload, size_t payload_size)
  85. {
  86. event->type = type;
  87. event->priority = priority;
  88. event->when = when;
  89. event->ctx = ctx;
  90. event->payload = payload;
  91. event->payload_size = payload_size;
  92. }
  93. OSSL_EVENT *ossl_event_queue_add_new(OSSL_EVENT_QUEUE *queue,
  94. uint32_t type, uint32_t priority,
  95. OSSL_TIME when, void *ctx,
  96. void *payload, size_t payload_size)
  97. {
  98. OSSL_EVENT *e = OPENSSL_malloc(sizeof(*e));
  99. if (e == NULL || queue == NULL)
  100. return NULL;
  101. ossl_event_set(e, type, priority, when, ctx, payload, payload_size);
  102. e->flag_dynamic = 1;
  103. if (event_queue_add(queue, e))
  104. return e;
  105. OPENSSL_free(e);
  106. return NULL;
  107. }
  108. int ossl_event_queue_add(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event,
  109. uint32_t type, uint32_t priority,
  110. OSSL_TIME when, void *ctx,
  111. void *payload, size_t payload_size)
  112. {
  113. if (event == NULL || queue == NULL)
  114. return 0;
  115. ossl_event_set(event, type, priority, when, ctx, payload, payload_size);
  116. event->flag_dynamic = 0;
  117. return event_queue_add(queue, event);
  118. }
  119. int ossl_event_queue_remove(OSSL_EVENT_QUEUE *queue, OSSL_EVENT *event)
  120. {
  121. if (event != NULL && event->queue != NULL) {
  122. ossl_pqueue_OSSL_EVENT_remove(event->queue, event->ref);
  123. event->queue = NULL;
  124. }
  125. return 1;
  126. }
  127. OSSL_TIME ossl_event_time_until(const OSSL_EVENT *event)
  128. {
  129. if (event == NULL)
  130. return OSSL_TIME_INFINITY;
  131. return ossl_time_subtract(event->when, ossl_time_now());
  132. }
  133. OSSL_TIME ossl_event_queue_time_until_next(const OSSL_EVENT_QUEUE *queue)
  134. {
  135. if (queue == NULL)
  136. return OSSL_TIME_INFINITY;
  137. if (ossl_pqueue_OSSL_EVENT_num(queue->now_events) > 0)
  138. return OSSL_TIME_IMMEDIATE;
  139. return ossl_event_time_until(ossl_pqueue_OSSL_EVENT_peek(queue->timed_events));
  140. }
  141. int ossl_event_queue_postpone_until(OSSL_EVENT_QUEUE *queue,
  142. OSSL_EVENT *event,
  143. OSSL_TIME when)
  144. {
  145. if (ossl_event_queue_remove(queue, event)) {
  146. event->when = when;
  147. return event_queue_add(queue, event);
  148. }
  149. return 0;
  150. }
  151. int ossl_event_queue_get1_next_event(OSSL_EVENT_QUEUE *queue,
  152. OSSL_EVENT **event)
  153. {
  154. OSSL_TIME now = ossl_time_now();
  155. OSSL_EVENT *e;
  156. /* Check for expired timer based events and convert them to now events */
  157. while ((e = ossl_pqueue_OSSL_EVENT_peek(queue->timed_events)) != NULL
  158. && ossl_time_compare(e->when, now) <= 0) {
  159. e = ossl_pqueue_OSSL_EVENT_pop(queue->timed_events);
  160. if (!ossl_pqueue_OSSL_EVENT_push(queue->now_events, e, &e->ref)) {
  161. e->queue = NULL;
  162. return 0;
  163. }
  164. }
  165. /*
  166. * Get next event from the now queue.
  167. * The pop returns NULL when there is none.
  168. */
  169. *event = ossl_pqueue_OSSL_EVENT_pop(queue->now_events);
  170. return 1;
  171. }