5
5
* SPDX-License-Identifier: Apache-2.0
6
6
*/
7
7
8
+ /**
9
+ * FIFO-style "memory queue" permitting enqueue at tail and dequeue from head.
10
+ * Element's payload is a pointer to arbitrary memory.
11
+ *
12
+ * Implemented as a singly-linked list, with always one-more element.
13
+ * The linked list must always contain at least one link-element, as emptiness
14
+ * is given by head == tail.
15
+ * For a queue to be valid, it must be initialized with an initial link-element.
16
+ *
17
+ * Invariant: The tail element's mem pointer is DontCare.
18
+ *
19
+ * Note that at enqueue, memory is not coupled with its accompanying
20
+ * link-element, but the link-element before it!
21
+ *
22
+ * Call | State after call
23
+ * ------------------------+-------------------------------
24
+ * memq_init(I,H,T) | H -> I[] <- T
25
+ * memq_enqueue(A,a,T); | H -> I[a] -> A[] <- T
26
+ * memq_enqueue(B,b,T); | H -> I[a] -> A[b] -> B[] <- T
27
+ * memq_dequeue(T,H,dest); | H -> A[b] -> B[] <- T # I and a as return and dest
28
+ *
29
+ * where H is the pointer to Head link-element (oldest element).
30
+ * where T is the pointer to Tail link-element (newest element).
31
+ * where I[] means the initial link-element, whose mem pointer is DontCare.
32
+ * where A[b] means the A'th link-element, whose mem pointer is b.
33
+ */
34
+
8
35
#include <zephyr/types.h>
9
36
#include <stddef.h>
10
37
11
38
#include "memq.h"
12
39
13
- inline memq_link_t * memq_peek (memq_link_t * head , memq_link_t * tail , void * * mem );
14
-
40
+ /**
41
+ * @brief Initialize a memory queue to be empty and valid.
42
+ *
43
+ * @param link[in] Initial link-element. Not associated with any mem
44
+ * @param head[out] Head of queue. Will be updated
45
+ * @param tail[out] Tail of queue. Will be updated
46
+ * @return Initial link-element
47
+ */
15
48
memq_link_t * memq_init (memq_link_t * link , memq_link_t * * head , memq_link_t * * tail )
16
49
{
17
- /* head and tail pointer to the initial link */
50
+ /* Head and tail pointer to the initial link - forms an empty queue */
18
51
* head = * tail = link ;
19
52
20
53
return link ;
21
54
}
22
55
56
+ /**
57
+ * @brief De-initialize a memory queue to be empty and invalid.
58
+ *
59
+ * @param head[in,out] Head of queue. Will be updated
60
+ * @param tail[in,out] Tail of queue. Will be updated
61
+ * @return If empty, return initial link-element. Otherwise NULL
62
+ */
23
63
memq_link_t * memq_deinit (memq_link_t * * head , memq_link_t * * tail )
24
64
{
25
65
memq_link_t * link ;
26
66
27
- /* if head and tail are not equal, then queue is not empty */
67
+ /* If head and tail are not equal, then queue is not empty */
28
68
if (* head != * tail ) {
29
69
return NULL ;
30
70
}
@@ -35,47 +75,75 @@ memq_link_t *memq_deinit(memq_link_t **head, memq_link_t **tail)
35
75
return link ;
36
76
}
37
77
78
+ /**
79
+ * @brief Enqueue at the tail of the queue
80
+ * @details Enqueue is destructive so tail will change to new tail
81
+ *
82
+ * @param link[in] Element to become the new tail. Not associated mem
83
+ * @param mem[in] Memory buffer. Will be owned by old tail
84
+ * @param tail[in,out] Tail of queue. Will be updated to point to link
85
+ * @return New tail
86
+ */
38
87
memq_link_t * memq_enqueue (memq_link_t * link , void * mem , memq_link_t * * tail )
39
88
{
40
- /* make the current tail link's next point to new link */
89
+ /* Let the old tail element point to the new tail element */
41
90
(* tail )-> next = link ;
42
91
43
- /* assign mem to current tail link's mem */
92
+ /* Let the old tail element point the the new memory */
44
93
(* tail )-> mem = mem ;
45
94
46
- /* increment the tail! */
95
+ /* Update the tail-pointer to point to the new tail element.
96
+ * The new tail-element is not expected to point to anything sensible
97
+ */
47
98
* tail = link ;
48
99
49
100
return link ;
50
101
}
51
102
103
+ /**
104
+ * @brief Non-destructive peek of head of queue.
105
+ *
106
+ * @param head[in] Pointer to head link-element of queue
107
+ * @param tail[in] Pointer to tail link-element of queue
108
+ * @param mem[out] The memory pointed to by head-element
109
+ * @return head or NULL if queue is empty
110
+ */
52
111
memq_link_t * memq_peek (memq_link_t * head , memq_link_t * tail , void * * mem )
53
112
{
54
- /* if head and tail are equal, then queue empty */
113
+ /* If head and tail are equal, then queue empty */
55
114
if (head == tail ) {
56
115
return NULL ;
57
116
}
58
117
59
- /* extract the link's mem */
118
+ /* Extract the head link-element 's memory */
60
119
if (mem ) {
61
120
* mem = head -> mem ;
62
121
}
63
122
64
- return head ;
123
+ return head ; /* queue was not empty */
65
124
}
66
125
126
+ /**
127
+ * @brief Remove and returns the head of queue.
128
+ * @details Dequeue is destructive so head will change to new head
129
+ *
130
+ * @param tail[in] Pointer to tail link-element of queue
131
+ * @param head[in,out] Pointer to head link-element of queue. Will be updated
132
+ * @param mem[out] The memory pointed to by head-element
133
+ * @return head or NULL if queue is empty
134
+ */
67
135
memq_link_t * memq_dequeue (memq_link_t * tail , memq_link_t * * head , void * * mem )
68
136
{
69
- memq_link_t * link ;
137
+ memq_link_t * old_head ;
70
138
71
- /* use memq peek to get the link and mem */
72
- link = memq_peek (* head , tail , mem );
73
- if (! link ) {
74
- return link ;
139
+ /* Use memq peek to get the old head and its mem */
140
+ old_head = memq_peek (* head , tail , mem );
141
+ if (old_head == NULL ) {
142
+ return NULL ; /* queue is empty */
75
143
}
76
144
77
- /* increment the head to next link node */
78
- * head = link -> next ;
145
+ /* Update the head-pointer to point to the new head element */
146
+ * head = old_head -> next ;
79
147
80
- return link ;
148
+ return old_head ;
81
149
}
0 commit comments