1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#pragma once
13
14#include <stdint.h>
15#include <stdbool.h>
16#include <stdlib.h>
17#include <platsupport/io.h>
18#include <platsupport/time_manager.h>
19
20/* Multiplex absolute timeouts -> maps ids of a timeout to absolute timeouts and returns the
21 * next timeout due */
22typedef struct {
23    /* absolute time this timeout should occur */
24    uint64_t abs_time;
25    /* period this timeout should reoccur (0 if not periodic) */
26    uint64_t period;
27    /* token to call callback with */
28    uintptr_t token;
29    /* callback to call */
30    timeout_cb_fn_t callback;
31} timeout_t;
32
33struct tqueue_node {
34    /* details of the timeout */
35    timeout_t timeout;
36    /* is this timeout allocated? */
37    bool allocated;
38    /* is this timeout in the callback queue? */
39    bool active;
40    /* next ptr for queue */
41    struct tqueue_node *next;
42};
43typedef struct tqueue_node tqueue_node_t;
44
45typedef struct {
46    /* head of ordered list of timeouts */
47    tqueue_node_t *queue;
48    /* id indexed array of timeouts */
49    tqueue_node_t *array;
50    /* size of timeout array */
51    int n;
52} tqueue_t;
53
54/*
55 * Alloc a new id for registering timeouts with tqueue_register.
56 *
57 * @param id    pointer to store allocated id in.
58 * @return      ENOMEM if there are no free ids, EINVAL if tq or id are NULL, 0 on success.
59 */
60int tqueue_alloc_id(tqueue_t *tq, unsigned int *id);
61
62/*
63 * Alloc a specific id for registering timeouts with tqueue_register.
64 *
65 * @param id    id to specifically allocate. Must be < size the timeout multiplexer
66 *              was initialised with.
67 * @return      ENOMEM if there are no free ids,
68 *              EINVAL if tq is NULL or id is invalid,
69 *              EADDRINUSE if id is already in use,
70 *              or id are NULL, 0 on success.
71 */
72int tqueue_alloc_id_at(tqueue_t *tq, unsigned int id);
73
74/*
75 * Free an id. This id can no longer be used to register timeouts with, and
76 * can be reallocated by tqueue_alloc_id.
77 *
78 * @param id    an id allocated by tqueue_alloc_id
79 * @return      EINVAL if tq is NULL or id is invalid (not allocated by tqueue_alloc_id), 0 on sucess.
80 */
81int tqueue_free_id(tqueue_t *tq, unsigned int id);
82
83/*
84 * Register a timeout. The timeout callback will be called when tqueue_update is called and
85 * the abs_time in the timeout has passed. If the timeout has already passed, the callback will be called when
86 * tqueue_update is called.
87 *
88 * This function can be called from callbacks.
89 *
90 * @param id        id to register timeout with. If the id already has a callback registered, override it.
91 * @param timeout   populated details of the timeout.
92 * @return          EINVAL if id or tq are invalid, 0 on success.
93 *
94 */
95int tqueue_register(tqueue_t *tq, unsigned int id, timeout_t *timeout);
96
97/*
98 * Cancel a timeout. The id is still valid, but the callback will not be called.
99 *
100 * @param id    id to cancel timeout for.
101 * @return      EINVAL if id or tq are invalid, 0 on success.
102 */
103int tqueue_cancel(tqueue_t *tq, unsigned int id);
104
105/*
106 * Call any callbacks where abs_time is >= curr_time. Return the next timeout due in next_time. Reenqueue
107 * any periodic callbacks.
108 *
109 * @param curr_time         the time to check abs_time against for all timeouts.
110 * @param[out] next_time    field to populate with next lowest time to be set after all callbacks called.
111 *                          If NULL, ignore.
112 * @return                  EINVAL if tq is invalid, 0 on sucess.
113 *
114 */
115int tqueue_update(tqueue_t *tq, uint64_t curr_time, uint64_t *next_time);
116
117/*
118 * Get the smallest registered timeout.
119 *
120 * @param[out] next_time    field to populate with next lowest time to be set.
121 * @return                  EINVAL if tq or next_time is NULL, 0 on success.
122 */
123int tqueue_next(tqueue_t *tq, uint64_t *next_time);
124
125/*
126 * Initialise a statically sized timeout multiplexer.
127 *
128 * @param[out] tq   pointer to memory to use to initialise timout mutiplexer.
129 * @param mops      malloc ops to allocate timeout nodes with. Not stored for use beyond this function.
130 * @param size      maximum number of ids that can be registered.
131 * @return          0 on success.
132 */
133int tqueue_init_static(tqueue_t *tq, ps_malloc_ops_t *mops, int size);
134