xref: /nrf52832-nimble/rt-thread/components/vbus/prio_queue.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2013-11-04     Grissiom     add comment
9*10465441SEvalZero  */
10*10465441SEvalZero 
11*10465441SEvalZero #include <rthw.h>
12*10465441SEvalZero #include <rtthread.h>
13*10465441SEvalZero 
14*10465441SEvalZero #include "prio_queue.h"
15*10465441SEvalZero 
16*10465441SEvalZero struct rt_prio_queue_item {
17*10465441SEvalZero     struct rt_prio_queue_item *next;
18*10465441SEvalZero     /* data follows */
19*10465441SEvalZero };
20*10465441SEvalZero 
_do_push(struct rt_prio_queue * que,rt_uint8_t prio,struct rt_prio_queue_item * item)21*10465441SEvalZero static void _do_push(struct rt_prio_queue *que,
22*10465441SEvalZero                      rt_uint8_t prio,
23*10465441SEvalZero                      struct rt_prio_queue_item *item)
24*10465441SEvalZero {
25*10465441SEvalZero     if (que->head[prio] == RT_NULL)
26*10465441SEvalZero     {
27*10465441SEvalZero         que->head[prio] = item;
28*10465441SEvalZero         que->bitmap |= 1 << prio;
29*10465441SEvalZero     }
30*10465441SEvalZero     else
31*10465441SEvalZero     {
32*10465441SEvalZero         RT_ASSERT(que->tail[prio]);
33*10465441SEvalZero         que->tail[prio]->next = item;
34*10465441SEvalZero     }
35*10465441SEvalZero     que->tail[prio] = item;
36*10465441SEvalZero }
37*10465441SEvalZero 
_do_pop(struct rt_prio_queue * que)38*10465441SEvalZero static struct rt_prio_queue_item* _do_pop(struct rt_prio_queue *que)
39*10465441SEvalZero {
40*10465441SEvalZero     int ffs;
41*10465441SEvalZero     struct rt_prio_queue_item *item;
42*10465441SEvalZero 
43*10465441SEvalZero     ffs = __rt_ffs(que->bitmap);
44*10465441SEvalZero     if (ffs == 0)
45*10465441SEvalZero         return RT_NULL;
46*10465441SEvalZero     ffs--;
47*10465441SEvalZero 
48*10465441SEvalZero     item = que->head[ffs];
49*10465441SEvalZero     RT_ASSERT(item);
50*10465441SEvalZero 
51*10465441SEvalZero     que->head[ffs] = item->next;
52*10465441SEvalZero     if (que->head[ffs] == RT_NULL)
53*10465441SEvalZero     {
54*10465441SEvalZero         que->bitmap &= ~(1 << ffs);
55*10465441SEvalZero     }
56*10465441SEvalZero 
57*10465441SEvalZero     return item;
58*10465441SEvalZero }
59*10465441SEvalZero 
rt_prio_queue_init(struct rt_prio_queue * que,const char * name,void * buf,rt_size_t bufsz,rt_size_t itemsz)60*10465441SEvalZero rt_err_t rt_prio_queue_init(struct rt_prio_queue *que,
61*10465441SEvalZero                             const char *name,
62*10465441SEvalZero                             void *buf,
63*10465441SEvalZero                             rt_size_t bufsz,
64*10465441SEvalZero                             rt_size_t itemsz)
65*10465441SEvalZero {
66*10465441SEvalZero     RT_ASSERT(que);
67*10465441SEvalZero 
68*10465441SEvalZero     rt_memset(que, 0, sizeof(*que));
69*10465441SEvalZero 
70*10465441SEvalZero     rt_list_init(&(que->suspended_pop_list));
71*10465441SEvalZero 
72*10465441SEvalZero     rt_mp_init(&que->pool, name, buf, bufsz,
73*10465441SEvalZero                sizeof(struct rt_prio_queue_item) + itemsz);
74*10465441SEvalZero 
75*10465441SEvalZero     que->item_sz = itemsz;
76*10465441SEvalZero 
77*10465441SEvalZero     return RT_EOK;
78*10465441SEvalZero }
79*10465441SEvalZero 
rt_prio_queue_detach(struct rt_prio_queue * que)80*10465441SEvalZero void rt_prio_queue_detach(struct rt_prio_queue *que)
81*10465441SEvalZero {
82*10465441SEvalZero     /* wake up all suspended pop threads, push thread is suspended on mempool.
83*10465441SEvalZero      */
84*10465441SEvalZero     while (!rt_list_isempty(&(que->suspended_pop_list)))
85*10465441SEvalZero     {
86*10465441SEvalZero         rt_thread_t thread;
87*10465441SEvalZero 
88*10465441SEvalZero         /* disable interrupt */
89*10465441SEvalZero         rt_ubase_t temp = rt_hw_interrupt_disable();
90*10465441SEvalZero 
91*10465441SEvalZero         /* get next suspend thread */
92*10465441SEvalZero         thread = rt_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist);
93*10465441SEvalZero         /* set error code to RT_ERROR */
94*10465441SEvalZero         thread->error = -RT_ERROR;
95*10465441SEvalZero 
96*10465441SEvalZero         rt_thread_resume(thread);
97*10465441SEvalZero 
98*10465441SEvalZero         /* enable interrupt */
99*10465441SEvalZero         rt_hw_interrupt_enable(temp);
100*10465441SEvalZero     }
101*10465441SEvalZero     rt_mp_detach(&que->pool);
102*10465441SEvalZero }
103*10465441SEvalZero 
104*10465441SEvalZero #ifdef RT_USING_HEAP
rt_prio_queue_create(const char * name,rt_size_t item_nr,rt_size_t item_sz)105*10465441SEvalZero struct rt_prio_queue* rt_prio_queue_create(const char *name,
106*10465441SEvalZero                                            rt_size_t item_nr,
107*10465441SEvalZero                                            rt_size_t item_sz)
108*10465441SEvalZero {
109*10465441SEvalZero     struct rt_prio_queue *que;
110*10465441SEvalZero     rt_size_t bufsz;
111*10465441SEvalZero 
112*10465441SEvalZero     bufsz = item_nr * (sizeof(struct rt_prio_queue_item)
113*10465441SEvalZero                        + item_sz
114*10465441SEvalZero                        + sizeof(void*));
115*10465441SEvalZero 
116*10465441SEvalZero     RT_ASSERT(item_nr);
117*10465441SEvalZero 
118*10465441SEvalZero     que = rt_malloc(sizeof(*que) + bufsz);
119*10465441SEvalZero     if (!que)
120*10465441SEvalZero         return RT_NULL;
121*10465441SEvalZero 
122*10465441SEvalZero     rt_prio_queue_init(que, name, que+1, bufsz, item_sz);
123*10465441SEvalZero 
124*10465441SEvalZero     return que;
125*10465441SEvalZero }
126*10465441SEvalZero 
rt_prio_queue_delete(struct rt_prio_queue * que)127*10465441SEvalZero void rt_prio_queue_delete(struct rt_prio_queue *que)
128*10465441SEvalZero {
129*10465441SEvalZero     rt_prio_queue_detach(que);
130*10465441SEvalZero     rt_free(que);
131*10465441SEvalZero }
132*10465441SEvalZero #endif
133*10465441SEvalZero 
rt_prio_queue_push(struct rt_prio_queue * que,rt_uint8_t prio,void * data,rt_int32_t timeout)134*10465441SEvalZero rt_err_t rt_prio_queue_push(struct rt_prio_queue *que,
135*10465441SEvalZero                             rt_uint8_t prio,
136*10465441SEvalZero                             void *data,
137*10465441SEvalZero                             rt_int32_t timeout)
138*10465441SEvalZero {
139*10465441SEvalZero     rt_ubase_t level;
140*10465441SEvalZero     struct rt_prio_queue_item *item;
141*10465441SEvalZero 
142*10465441SEvalZero     RT_ASSERT(que);
143*10465441SEvalZero 
144*10465441SEvalZero     if (prio >= RT_PRIO_QUEUE_PRIO_MAX)
145*10465441SEvalZero         return -RT_ERROR;
146*10465441SEvalZero 
147*10465441SEvalZero     item = rt_mp_alloc(&que->pool, timeout);
148*10465441SEvalZero     if (item == RT_NULL)
149*10465441SEvalZero         return -RT_ENOMEM;
150*10465441SEvalZero 
151*10465441SEvalZero     rt_memcpy(item+1, data, que->item_sz);
152*10465441SEvalZero     item->next = RT_NULL;
153*10465441SEvalZero 
154*10465441SEvalZero     level = rt_hw_interrupt_disable();
155*10465441SEvalZero 
156*10465441SEvalZero     _do_push(que, prio, item);
157*10465441SEvalZero 
158*10465441SEvalZero     if (!rt_list_isempty(&(que->suspended_pop_list)))
159*10465441SEvalZero     {
160*10465441SEvalZero         rt_thread_t thread;
161*10465441SEvalZero 
162*10465441SEvalZero         /* get thread entry */
163*10465441SEvalZero         thread = rt_list_entry(que->suspended_pop_list.next,
164*10465441SEvalZero                                struct rt_thread,
165*10465441SEvalZero                                tlist);
166*10465441SEvalZero         /* resume it */
167*10465441SEvalZero         rt_thread_resume(thread);
168*10465441SEvalZero         rt_hw_interrupt_enable(level);
169*10465441SEvalZero 
170*10465441SEvalZero         /* perform a schedule */
171*10465441SEvalZero         rt_schedule();
172*10465441SEvalZero 
173*10465441SEvalZero         return RT_EOK;
174*10465441SEvalZero     }
175*10465441SEvalZero 
176*10465441SEvalZero     rt_hw_interrupt_enable(level);
177*10465441SEvalZero 
178*10465441SEvalZero     return RT_EOK;
179*10465441SEvalZero }
180*10465441SEvalZero 
rt_prio_queue_pop(struct rt_prio_queue * que,void * data,rt_int32_t timeout)181*10465441SEvalZero rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que,
182*10465441SEvalZero                            void *data,
183*10465441SEvalZero                            rt_int32_t timeout)
184*10465441SEvalZero {
185*10465441SEvalZero     rt_ubase_t level;
186*10465441SEvalZero     struct rt_prio_queue_item *item;
187*10465441SEvalZero 
188*10465441SEvalZero     RT_ASSERT(que);
189*10465441SEvalZero     RT_ASSERT(data);
190*10465441SEvalZero 
191*10465441SEvalZero     level = rt_hw_interrupt_disable();
192*10465441SEvalZero     for (item = _do_pop(que);
193*10465441SEvalZero          item == RT_NULL;
194*10465441SEvalZero          item = _do_pop(que))
195*10465441SEvalZero     {
196*10465441SEvalZero         rt_thread_t thread;
197*10465441SEvalZero 
198*10465441SEvalZero         if (timeout == 0)
199*10465441SEvalZero         {
200*10465441SEvalZero             rt_hw_interrupt_enable(level);
201*10465441SEvalZero             return -RT_ETIMEOUT;
202*10465441SEvalZero         }
203*10465441SEvalZero 
204*10465441SEvalZero         RT_DEBUG_NOT_IN_INTERRUPT;
205*10465441SEvalZero 
206*10465441SEvalZero         thread = rt_thread_self();
207*10465441SEvalZero         thread->error = RT_EOK;
208*10465441SEvalZero         rt_thread_suspend(thread);
209*10465441SEvalZero 
210*10465441SEvalZero         rt_list_insert_before(&(que->suspended_pop_list), &(thread->tlist));
211*10465441SEvalZero 
212*10465441SEvalZero         if (timeout > 0)
213*10465441SEvalZero         {
214*10465441SEvalZero             rt_timer_control(&(thread->thread_timer),
215*10465441SEvalZero                              RT_TIMER_CTRL_SET_TIME,
216*10465441SEvalZero                              &timeout);
217*10465441SEvalZero             rt_timer_start(&(thread->thread_timer));
218*10465441SEvalZero         }
219*10465441SEvalZero 
220*10465441SEvalZero         rt_hw_interrupt_enable(level);
221*10465441SEvalZero 
222*10465441SEvalZero         rt_schedule();
223*10465441SEvalZero 
224*10465441SEvalZero         /* thread is waked up */
225*10465441SEvalZero         if (thread->error != RT_EOK)
226*10465441SEvalZero             return thread->error;
227*10465441SEvalZero         level = rt_hw_interrupt_disable();
228*10465441SEvalZero     }
229*10465441SEvalZero 
230*10465441SEvalZero     rt_hw_interrupt_enable(level);
231*10465441SEvalZero 
232*10465441SEvalZero     rt_memcpy(data, item+1, que->item_sz);
233*10465441SEvalZero     rt_mp_free(item);
234*10465441SEvalZero 
235*10465441SEvalZero     return RT_EOK;
236*10465441SEvalZero }
237*10465441SEvalZero 
rt_prio_queue_dump(struct rt_prio_queue * que)238*10465441SEvalZero void rt_prio_queue_dump(struct rt_prio_queue *que)
239*10465441SEvalZero {
240*10465441SEvalZero     int level = 0;
241*10465441SEvalZero 
242*10465441SEvalZero     rt_kprintf("bitmap: %08x\n", que->bitmap);
243*10465441SEvalZero     for (level = 0; level < RT_PRIO_QUEUE_PRIO_MAX; level++)
244*10465441SEvalZero     {
245*10465441SEvalZero         struct rt_prio_queue_item *item;
246*10465441SEvalZero 
247*10465441SEvalZero         rt_kprintf("%2d: ", level);
248*10465441SEvalZero         for (item = que->head[level];
249*10465441SEvalZero              item;
250*10465441SEvalZero              item = item->next)
251*10465441SEvalZero         {
252*10465441SEvalZero             rt_kprintf("%p, ", item);
253*10465441SEvalZero         }
254*10465441SEvalZero         rt_kprintf("\n");
255*10465441SEvalZero     }
256*10465441SEvalZero }
257*10465441SEvalZero 
258