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