1 /*
2  * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "osi/allocator.h"
8 #include "osi/pkt_queue.h"
9 #include "osi/fixed_pkt_queue.h"
10 #include "osi/osi.h"
11 #include "osi/semaphore.h"
12 
13 typedef struct fixed_pkt_queue_t {
14     struct pkt_queue *pkt_list;
15     osi_sem_t enqueue_sem;
16     osi_sem_t dequeue_sem;
17     size_t capacity;
18     fixed_pkt_queue_cb dequeue_ready;
19 } fixed_pkt_queue_t;
20 
fixed_pkt_queue_new(size_t capacity)21 fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity)
22 {
23     fixed_pkt_queue_t *ret = osi_calloc(sizeof(fixed_pkt_queue_t));
24     if (!ret) {
25         goto error;
26     }
27 
28     ret->capacity = capacity;
29     ret->pkt_list = pkt_queue_create();
30     if (!ret->pkt_list) {
31         goto error;
32     }
33 
34     osi_sem_new(&ret->enqueue_sem, capacity, capacity);
35     if (!ret->enqueue_sem) {
36         goto error;
37     }
38 
39     osi_sem_new(&ret->dequeue_sem, capacity, 0);
40     if (!ret->dequeue_sem) {
41         goto error;
42     }
43 
44     return ret;
45 
46 error:
47     fixed_pkt_queue_free(ret, NULL);
48     return NULL;
49 }
50 
fixed_pkt_queue_free(fixed_pkt_queue_t * queue,fixed_pkt_queue_free_cb free_cb)51 void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb)
52 {
53     if (queue == NULL) {
54         return;
55     }
56 
57     fixed_pkt_queue_unregister_dequeue(queue);
58 
59     pkt_queue_destroy(queue->pkt_list, (pkt_queue_free_cb)free_cb);
60     queue->pkt_list = NULL;
61 
62     if (queue->enqueue_sem) {
63         osi_sem_free(&queue->enqueue_sem);
64     }
65     if (queue->dequeue_sem) {
66         osi_sem_free(&queue->dequeue_sem);
67     }
68     osi_free(queue);
69 }
70 
fixed_pkt_queue_is_empty(fixed_pkt_queue_t * queue)71 bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue)
72 {
73     if (queue == NULL) {
74         return true;
75     }
76 
77     return pkt_queue_is_empty(queue->pkt_list);
78 }
79 
fixed_pkt_queue_length(fixed_pkt_queue_t * queue)80 size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue)
81 {
82     if (queue == NULL) {
83         return 0;
84     }
85     return pkt_queue_length(queue->pkt_list);
86 }
87 
fixed_pkt_queue_capacity(fixed_pkt_queue_t * queue)88 size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue)
89 {
90     assert(queue != NULL);
91 
92     return queue->capacity;
93 }
94 
fixed_pkt_queue_enqueue(fixed_pkt_queue_t * queue,pkt_linked_item_t * linked_pkt,uint32_t timeout)95 bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout)
96 {
97     bool ret = false;
98 
99     assert(queue != NULL);
100     assert(linked_pkt != NULL);
101 
102     if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) {
103         return false;
104     }
105 
106     ret = pkt_queue_enqueue(queue->pkt_list, linked_pkt);
107 
108     assert(ret == true);
109     osi_sem_give(&queue->dequeue_sem);
110 
111     return ret;
112 }
113 
fixed_pkt_queue_dequeue(fixed_pkt_queue_t * queue,uint32_t timeout)114 pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout)
115 {
116     pkt_linked_item_t *ret = NULL;
117 
118     assert(queue != NULL);
119 
120     if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) {
121         return NULL;
122     }
123     ret = pkt_queue_dequeue(queue->pkt_list);
124 
125     osi_sem_give(&queue->enqueue_sem);
126 
127     return ret;
128 }
129 
fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t * queue)130 pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue)
131 {
132     if (queue == NULL) {
133         return NULL;
134     }
135 
136     return pkt_queue_try_peek_first(queue->pkt_list);
137 }
138 
fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t * queue,fixed_pkt_queue_cb ready_cb)139 void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb)
140 {
141     assert(queue != NULL);
142     assert(ready_cb != NULL);
143 
144     queue->dequeue_ready = ready_cb;
145 }
146 
fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t * queue)147 void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue)
148 {
149     assert(queue != NULL);
150 
151     queue->dequeue_ready = NULL;
152 }
153 
fixed_pkt_queue_process(fixed_pkt_queue_t * queue)154 void fixed_pkt_queue_process(fixed_pkt_queue_t *queue)
155 {
156     assert(queue != NULL);
157 
158     if (queue->dequeue_ready) {
159         queue->dequeue_ready(queue);
160     }
161 }
162