xref: /nrf52832-nimble/rt-thread/src/ipc.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2006-03-14     Bernard      the first version
9*10465441SEvalZero  * 2006-04-25     Bernard      implement semaphore
10*10465441SEvalZero  * 2006-05-03     Bernard      add RT_IPC_DEBUG
11*10465441SEvalZero  *                             modify the type of IPC waiting time to rt_int32_t
12*10465441SEvalZero  * 2006-05-10     Bernard      fix the semaphore take bug and add IPC object
13*10465441SEvalZero  * 2006-05-12     Bernard      implement mailbox and message queue
14*10465441SEvalZero  * 2006-05-20     Bernard      implement mutex
15*10465441SEvalZero  * 2006-05-23     Bernard      implement fast event
16*10465441SEvalZero  * 2006-05-24     Bernard      implement event
17*10465441SEvalZero  * 2006-06-03     Bernard      fix the thread timer init bug
18*10465441SEvalZero  * 2006-06-05     Bernard      fix the mutex release bug
19*10465441SEvalZero  * 2006-06-07     Bernard      fix the message queue send bug
20*10465441SEvalZero  * 2006-08-04     Bernard      add hook support
21*10465441SEvalZero  * 2009-05-21     Yi.qiu       fix the sem release bug
22*10465441SEvalZero  * 2009-07-18     Bernard      fix the event clear bug
23*10465441SEvalZero  * 2009-09-09     Bernard      remove fast event and fix ipc release bug
24*10465441SEvalZero  * 2009-10-10     Bernard      change semaphore and mutex value to unsigned value
25*10465441SEvalZero  * 2009-10-25     Bernard      change the mb/mq receive timeout to 0 if the
26*10465441SEvalZero  *                             re-calculated delta tick is a negative number.
27*10465441SEvalZero  * 2009-12-16     Bernard      fix the rt_ipc_object_suspend issue when IPC flag
28*10465441SEvalZero  *                             is RT_IPC_FLAG_PRIO
29*10465441SEvalZero  * 2010-01-20     mbbill       remove rt_ipc_object_decrease function.
30*10465441SEvalZero  * 2010-04-20     Bernard      move memcpy outside interrupt disable in mq
31*10465441SEvalZero  * 2010-10-26     yi.qiu       add module support in rt_mp_delete and rt_mq_delete
32*10465441SEvalZero  * 2010-11-10     Bernard      add IPC reset command implementation.
33*10465441SEvalZero  * 2011-12-18     Bernard      add more parameter checking in message queue
34*10465441SEvalZero  * 2013-09-14     Grissiom     add an option check in rt_event_recv
35*10465441SEvalZero  * 2018-10-02     Bernard      add 64bit support for mailbox
36*10465441SEvalZero  */
37*10465441SEvalZero 
38*10465441SEvalZero #include <rtthread.h>
39*10465441SEvalZero #include <rthw.h>
40*10465441SEvalZero 
41*10465441SEvalZero #ifdef RT_USING_HOOK
42*10465441SEvalZero extern void (*rt_object_trytake_hook)(struct rt_object *object);
43*10465441SEvalZero extern void (*rt_object_take_hook)(struct rt_object *object);
44*10465441SEvalZero extern void (*rt_object_put_hook)(struct rt_object *object);
45*10465441SEvalZero #endif
46*10465441SEvalZero 
47*10465441SEvalZero /**
48*10465441SEvalZero  * @addtogroup IPC
49*10465441SEvalZero  */
50*10465441SEvalZero 
51*10465441SEvalZero /**@{*/
52*10465441SEvalZero 
53*10465441SEvalZero /**
54*10465441SEvalZero  * This function will initialize an IPC object
55*10465441SEvalZero  *
56*10465441SEvalZero  * @param ipc the IPC object
57*10465441SEvalZero  *
58*10465441SEvalZero  * @return the operation status, RT_EOK on successful
59*10465441SEvalZero  */
rt_ipc_object_init(struct rt_ipc_object * ipc)60*10465441SEvalZero rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
61*10465441SEvalZero {
62*10465441SEvalZero     /* init ipc object */
63*10465441SEvalZero     rt_list_init(&(ipc->suspend_thread));
64*10465441SEvalZero 
65*10465441SEvalZero     return RT_EOK;
66*10465441SEvalZero }
67*10465441SEvalZero 
68*10465441SEvalZero /**
69*10465441SEvalZero  * This function will suspend a thread to a specified list. IPC object or some
70*10465441SEvalZero  * double-queue object (mailbox etc.) contains this kind of list.
71*10465441SEvalZero  *
72*10465441SEvalZero  * @param list the IPC suspended thread list
73*10465441SEvalZero  * @param thread the thread object to be suspended
74*10465441SEvalZero  * @param flag the IPC object flag,
75*10465441SEvalZero  *        which shall be RT_IPC_FLAG_FIFO/RT_IPC_FLAG_PRIO.
76*10465441SEvalZero  *
77*10465441SEvalZero  * @return the operation status, RT_EOK on successful
78*10465441SEvalZero  */
rt_ipc_list_suspend(rt_list_t * list,struct rt_thread * thread,rt_uint8_t flag)79*10465441SEvalZero rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t        *list,
80*10465441SEvalZero                                        struct rt_thread *thread,
81*10465441SEvalZero                                        rt_uint8_t        flag)
82*10465441SEvalZero {
83*10465441SEvalZero     /* suspend thread */
84*10465441SEvalZero     rt_thread_suspend(thread);
85*10465441SEvalZero 
86*10465441SEvalZero     switch (flag)
87*10465441SEvalZero     {
88*10465441SEvalZero     case RT_IPC_FLAG_FIFO:
89*10465441SEvalZero         rt_list_insert_before(list, &(thread->tlist));
90*10465441SEvalZero         break;
91*10465441SEvalZero 
92*10465441SEvalZero     case RT_IPC_FLAG_PRIO:
93*10465441SEvalZero         {
94*10465441SEvalZero             struct rt_list_node *n;
95*10465441SEvalZero             struct rt_thread *sthread;
96*10465441SEvalZero 
97*10465441SEvalZero             /* find a suitable position */
98*10465441SEvalZero             for (n = list->next; n != list; n = n->next)
99*10465441SEvalZero             {
100*10465441SEvalZero                 sthread = rt_list_entry(n, struct rt_thread, tlist);
101*10465441SEvalZero 
102*10465441SEvalZero                 /* find out */
103*10465441SEvalZero                 if (thread->current_priority < sthread->current_priority)
104*10465441SEvalZero                 {
105*10465441SEvalZero                     /* insert this thread before the sthread */
106*10465441SEvalZero                     rt_list_insert_before(&(sthread->tlist), &(thread->tlist));
107*10465441SEvalZero                     break;
108*10465441SEvalZero                 }
109*10465441SEvalZero             }
110*10465441SEvalZero 
111*10465441SEvalZero             /*
112*10465441SEvalZero              * not found a suitable position,
113*10465441SEvalZero              * append to the end of suspend_thread list
114*10465441SEvalZero              */
115*10465441SEvalZero             if (n == list)
116*10465441SEvalZero                 rt_list_insert_before(list, &(thread->tlist));
117*10465441SEvalZero         }
118*10465441SEvalZero         break;
119*10465441SEvalZero     }
120*10465441SEvalZero 
121*10465441SEvalZero     return RT_EOK;
122*10465441SEvalZero }
123*10465441SEvalZero 
124*10465441SEvalZero /**
125*10465441SEvalZero  * This function will resume the first thread in the list of a IPC object:
126*10465441SEvalZero  * - remove the thread from suspend queue of IPC object
127*10465441SEvalZero  * - put the thread into system ready queue
128*10465441SEvalZero  *
129*10465441SEvalZero  * @param list the thread list
130*10465441SEvalZero  *
131*10465441SEvalZero  * @return the operation status, RT_EOK on successful
132*10465441SEvalZero  */
rt_ipc_list_resume(rt_list_t * list)133*10465441SEvalZero rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list)
134*10465441SEvalZero {
135*10465441SEvalZero     struct rt_thread *thread;
136*10465441SEvalZero 
137*10465441SEvalZero     /* get thread entry */
138*10465441SEvalZero     thread = rt_list_entry(list->next, struct rt_thread, tlist);
139*10465441SEvalZero 
140*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name));
141*10465441SEvalZero 
142*10465441SEvalZero     /* resume it */
143*10465441SEvalZero     rt_thread_resume(thread);
144*10465441SEvalZero 
145*10465441SEvalZero     return RT_EOK;
146*10465441SEvalZero }
147*10465441SEvalZero 
148*10465441SEvalZero /**
149*10465441SEvalZero  * This function will resume all suspended threads in a list, including
150*10465441SEvalZero  * suspend list of IPC object and private list of mailbox etc.
151*10465441SEvalZero  *
152*10465441SEvalZero  * @param list of the threads to resume
153*10465441SEvalZero  *
154*10465441SEvalZero  * @return the operation status, RT_EOK on successful
155*10465441SEvalZero  */
rt_ipc_list_resume_all(rt_list_t * list)156*10465441SEvalZero rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
157*10465441SEvalZero {
158*10465441SEvalZero     struct rt_thread *thread;
159*10465441SEvalZero     register rt_ubase_t temp;
160*10465441SEvalZero 
161*10465441SEvalZero     /* wakeup all suspend threads */
162*10465441SEvalZero     while (!rt_list_isempty(list))
163*10465441SEvalZero     {
164*10465441SEvalZero         /* disable interrupt */
165*10465441SEvalZero         temp = rt_hw_interrupt_disable();
166*10465441SEvalZero 
167*10465441SEvalZero         /* get next suspend thread */
168*10465441SEvalZero         thread = rt_list_entry(list->next, struct rt_thread, tlist);
169*10465441SEvalZero         /* set error code to RT_ERROR */
170*10465441SEvalZero         thread->error = -RT_ERROR;
171*10465441SEvalZero 
172*10465441SEvalZero         /*
173*10465441SEvalZero          * resume thread
174*10465441SEvalZero          * In rt_thread_resume function, it will remove current thread from
175*10465441SEvalZero          * suspend list
176*10465441SEvalZero          */
177*10465441SEvalZero         rt_thread_resume(thread);
178*10465441SEvalZero 
179*10465441SEvalZero         /* enable interrupt */
180*10465441SEvalZero         rt_hw_interrupt_enable(temp);
181*10465441SEvalZero     }
182*10465441SEvalZero 
183*10465441SEvalZero     return RT_EOK;
184*10465441SEvalZero }
185*10465441SEvalZero 
186*10465441SEvalZero #ifdef RT_USING_SEMAPHORE
187*10465441SEvalZero /**
188*10465441SEvalZero  * This function will initialize a semaphore and put it under control of
189*10465441SEvalZero  * resource management.
190*10465441SEvalZero  *
191*10465441SEvalZero  * @param sem the semaphore object
192*10465441SEvalZero  * @param name the name of semaphore
193*10465441SEvalZero  * @param value the init value of semaphore
194*10465441SEvalZero  * @param flag the flag of semaphore
195*10465441SEvalZero  *
196*10465441SEvalZero  * @return the operation status, RT_EOK on successful
197*10465441SEvalZero  */
rt_sem_init(rt_sem_t sem,const char * name,rt_uint32_t value,rt_uint8_t flag)198*10465441SEvalZero rt_err_t rt_sem_init(rt_sem_t    sem,
199*10465441SEvalZero                      const char *name,
200*10465441SEvalZero                      rt_uint32_t value,
201*10465441SEvalZero                      rt_uint8_t  flag)
202*10465441SEvalZero {
203*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
204*10465441SEvalZero 
205*10465441SEvalZero     /* init object */
206*10465441SEvalZero     rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
207*10465441SEvalZero 
208*10465441SEvalZero     /* init ipc object */
209*10465441SEvalZero     rt_ipc_object_init(&(sem->parent));
210*10465441SEvalZero 
211*10465441SEvalZero     /* set init value */
212*10465441SEvalZero     sem->value = value;
213*10465441SEvalZero 
214*10465441SEvalZero     /* set parent */
215*10465441SEvalZero     sem->parent.parent.flag = flag;
216*10465441SEvalZero 
217*10465441SEvalZero     return RT_EOK;
218*10465441SEvalZero }
219*10465441SEvalZero RTM_EXPORT(rt_sem_init);
220*10465441SEvalZero 
221*10465441SEvalZero /**
222*10465441SEvalZero  * This function will detach a semaphore from resource management
223*10465441SEvalZero  *
224*10465441SEvalZero  * @param sem the semaphore object
225*10465441SEvalZero  *
226*10465441SEvalZero  * @return the operation status, RT_EOK on successful
227*10465441SEvalZero  *
228*10465441SEvalZero  * @see rt_sem_delete
229*10465441SEvalZero  */
rt_sem_detach(rt_sem_t sem)230*10465441SEvalZero rt_err_t rt_sem_detach(rt_sem_t sem)
231*10465441SEvalZero {
232*10465441SEvalZero     /* parameter check */
233*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
234*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
235*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent));
236*10465441SEvalZero 
237*10465441SEvalZero     /* wakeup all suspend threads */
238*10465441SEvalZero     rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
239*10465441SEvalZero 
240*10465441SEvalZero     /* detach semaphore object */
241*10465441SEvalZero     rt_object_detach(&(sem->parent.parent));
242*10465441SEvalZero 
243*10465441SEvalZero     return RT_EOK;
244*10465441SEvalZero }
245*10465441SEvalZero RTM_EXPORT(rt_sem_detach);
246*10465441SEvalZero 
247*10465441SEvalZero #ifdef RT_USING_HEAP
248*10465441SEvalZero /**
249*10465441SEvalZero  * This function will create a semaphore from system resource
250*10465441SEvalZero  *
251*10465441SEvalZero  * @param name the name of semaphore
252*10465441SEvalZero  * @param value the init value of semaphore
253*10465441SEvalZero  * @param flag the flag of semaphore
254*10465441SEvalZero  *
255*10465441SEvalZero  * @return the created semaphore, RT_NULL on error happen
256*10465441SEvalZero  *
257*10465441SEvalZero  * @see rt_sem_init
258*10465441SEvalZero  */
rt_sem_create(const char * name,rt_uint32_t value,rt_uint8_t flag)259*10465441SEvalZero rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
260*10465441SEvalZero {
261*10465441SEvalZero     rt_sem_t sem;
262*10465441SEvalZero 
263*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
264*10465441SEvalZero 
265*10465441SEvalZero     /* allocate object */
266*10465441SEvalZero     sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
267*10465441SEvalZero     if (sem == RT_NULL)
268*10465441SEvalZero         return sem;
269*10465441SEvalZero 
270*10465441SEvalZero     /* init ipc object */
271*10465441SEvalZero     rt_ipc_object_init(&(sem->parent));
272*10465441SEvalZero 
273*10465441SEvalZero     /* set init value */
274*10465441SEvalZero     sem->value = value;
275*10465441SEvalZero 
276*10465441SEvalZero     /* set parent */
277*10465441SEvalZero     sem->parent.parent.flag = flag;
278*10465441SEvalZero 
279*10465441SEvalZero     return sem;
280*10465441SEvalZero }
281*10465441SEvalZero RTM_EXPORT(rt_sem_create);
282*10465441SEvalZero 
283*10465441SEvalZero /**
284*10465441SEvalZero  * This function will delete a semaphore object and release the memory
285*10465441SEvalZero  *
286*10465441SEvalZero  * @param sem the semaphore object
287*10465441SEvalZero  *
288*10465441SEvalZero  * @return the error code
289*10465441SEvalZero  *
290*10465441SEvalZero  * @see rt_sem_detach
291*10465441SEvalZero  */
rt_sem_delete(rt_sem_t sem)292*10465441SEvalZero rt_err_t rt_sem_delete(rt_sem_t sem)
293*10465441SEvalZero {
294*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
295*10465441SEvalZero 
296*10465441SEvalZero     /* parameter check */
297*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
298*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
299*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent) == RT_FALSE);
300*10465441SEvalZero 
301*10465441SEvalZero     /* wakeup all suspend threads */
302*10465441SEvalZero     rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
303*10465441SEvalZero 
304*10465441SEvalZero     /* delete semaphore object */
305*10465441SEvalZero     rt_object_delete(&(sem->parent.parent));
306*10465441SEvalZero 
307*10465441SEvalZero     return RT_EOK;
308*10465441SEvalZero }
309*10465441SEvalZero RTM_EXPORT(rt_sem_delete);
310*10465441SEvalZero #endif
311*10465441SEvalZero 
312*10465441SEvalZero /**
313*10465441SEvalZero  * This function will take a semaphore, if the semaphore is unavailable, the
314*10465441SEvalZero  * thread shall wait for a specified time.
315*10465441SEvalZero  *
316*10465441SEvalZero  * @param sem the semaphore object
317*10465441SEvalZero  * @param time the waiting time
318*10465441SEvalZero  *
319*10465441SEvalZero  * @return the error code
320*10465441SEvalZero  */
rt_sem_take(rt_sem_t sem,rt_int32_t time)321*10465441SEvalZero rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
322*10465441SEvalZero {
323*10465441SEvalZero     register rt_base_t temp;
324*10465441SEvalZero     struct rt_thread *thread;
325*10465441SEvalZero 
326*10465441SEvalZero     /* parameter check */
327*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
328*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
329*10465441SEvalZero 
330*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));
331*10465441SEvalZero 
332*10465441SEvalZero     /* disable interrupt */
333*10465441SEvalZero     temp = rt_hw_interrupt_disable();
334*10465441SEvalZero 
335*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",
336*10465441SEvalZero                                 rt_thread_self()->name,
337*10465441SEvalZero                                 ((struct rt_object *)sem)->name,
338*10465441SEvalZero                                 sem->value));
339*10465441SEvalZero 
340*10465441SEvalZero     if (sem->value > 0)
341*10465441SEvalZero     {
342*10465441SEvalZero         /* semaphore is available */
343*10465441SEvalZero         sem->value --;
344*10465441SEvalZero 
345*10465441SEvalZero         /* enable interrupt */
346*10465441SEvalZero         rt_hw_interrupt_enable(temp);
347*10465441SEvalZero     }
348*10465441SEvalZero     else
349*10465441SEvalZero     {
350*10465441SEvalZero         /* no waiting, return with timeout */
351*10465441SEvalZero         if (time == 0)
352*10465441SEvalZero         {
353*10465441SEvalZero             rt_hw_interrupt_enable(temp);
354*10465441SEvalZero 
355*10465441SEvalZero             return -RT_ETIMEOUT;
356*10465441SEvalZero         }
357*10465441SEvalZero         else
358*10465441SEvalZero         {
359*10465441SEvalZero             /* current context checking */
360*10465441SEvalZero             RT_DEBUG_IN_THREAD_CONTEXT;
361*10465441SEvalZero 
362*10465441SEvalZero             /* semaphore is unavailable, push to suspend list */
363*10465441SEvalZero             /* get current thread */
364*10465441SEvalZero             thread = rt_thread_self();
365*10465441SEvalZero 
366*10465441SEvalZero             /* reset thread error number */
367*10465441SEvalZero             thread->error = RT_EOK;
368*10465441SEvalZero 
369*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
370*10465441SEvalZero                                         thread->name));
371*10465441SEvalZero 
372*10465441SEvalZero             /* suspend thread */
373*10465441SEvalZero             rt_ipc_list_suspend(&(sem->parent.suspend_thread),
374*10465441SEvalZero                                 thread,
375*10465441SEvalZero                                 sem->parent.parent.flag);
376*10465441SEvalZero 
377*10465441SEvalZero             /* has waiting time, start thread timer */
378*10465441SEvalZero             if (time > 0)
379*10465441SEvalZero             {
380*10465441SEvalZero                 RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
381*10465441SEvalZero                                             thread->name));
382*10465441SEvalZero 
383*10465441SEvalZero                 /* reset the timeout of thread timer and start it */
384*10465441SEvalZero                 rt_timer_control(&(thread->thread_timer),
385*10465441SEvalZero                                  RT_TIMER_CTRL_SET_TIME,
386*10465441SEvalZero                                  &time);
387*10465441SEvalZero                 rt_timer_start(&(thread->thread_timer));
388*10465441SEvalZero             }
389*10465441SEvalZero 
390*10465441SEvalZero             /* enable interrupt */
391*10465441SEvalZero             rt_hw_interrupt_enable(temp);
392*10465441SEvalZero 
393*10465441SEvalZero             /* do schedule */
394*10465441SEvalZero             rt_schedule();
395*10465441SEvalZero 
396*10465441SEvalZero             if (thread->error != RT_EOK)
397*10465441SEvalZero             {
398*10465441SEvalZero                 return thread->error;
399*10465441SEvalZero             }
400*10465441SEvalZero         }
401*10465441SEvalZero     }
402*10465441SEvalZero 
403*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));
404*10465441SEvalZero 
405*10465441SEvalZero     return RT_EOK;
406*10465441SEvalZero }
407*10465441SEvalZero RTM_EXPORT(rt_sem_take);
408*10465441SEvalZero 
409*10465441SEvalZero /**
410*10465441SEvalZero  * This function will try to take a semaphore and immediately return
411*10465441SEvalZero  *
412*10465441SEvalZero  * @param sem the semaphore object
413*10465441SEvalZero  *
414*10465441SEvalZero  * @return the error code
415*10465441SEvalZero  */
rt_sem_trytake(rt_sem_t sem)416*10465441SEvalZero rt_err_t rt_sem_trytake(rt_sem_t sem)
417*10465441SEvalZero {
418*10465441SEvalZero     return rt_sem_take(sem, 0);
419*10465441SEvalZero }
420*10465441SEvalZero RTM_EXPORT(rt_sem_trytake);
421*10465441SEvalZero 
422*10465441SEvalZero /**
423*10465441SEvalZero  * This function will release a semaphore, if there are threads suspended on
424*10465441SEvalZero  * semaphore, it will be waked up.
425*10465441SEvalZero  *
426*10465441SEvalZero  * @param sem the semaphore object
427*10465441SEvalZero  *
428*10465441SEvalZero  * @return the error code
429*10465441SEvalZero  */
rt_sem_release(rt_sem_t sem)430*10465441SEvalZero rt_err_t rt_sem_release(rt_sem_t sem)
431*10465441SEvalZero {
432*10465441SEvalZero     register rt_base_t temp;
433*10465441SEvalZero     register rt_bool_t need_schedule;
434*10465441SEvalZero 
435*10465441SEvalZero     /* parameter check */
436*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
437*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
438*10465441SEvalZero 
439*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));
440*10465441SEvalZero 
441*10465441SEvalZero     need_schedule = RT_FALSE;
442*10465441SEvalZero 
443*10465441SEvalZero     /* disable interrupt */
444*10465441SEvalZero     temp = rt_hw_interrupt_disable();
445*10465441SEvalZero 
446*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
447*10465441SEvalZero                                 rt_thread_self()->name,
448*10465441SEvalZero                                 ((struct rt_object *)sem)->name,
449*10465441SEvalZero                                 sem->value));
450*10465441SEvalZero 
451*10465441SEvalZero     if (!rt_list_isempty(&sem->parent.suspend_thread))
452*10465441SEvalZero     {
453*10465441SEvalZero         /* resume the suspended thread */
454*10465441SEvalZero         rt_ipc_list_resume(&(sem->parent.suspend_thread));
455*10465441SEvalZero         need_schedule = RT_TRUE;
456*10465441SEvalZero     }
457*10465441SEvalZero     else
458*10465441SEvalZero         sem->value ++; /* increase value */
459*10465441SEvalZero 
460*10465441SEvalZero     /* enable interrupt */
461*10465441SEvalZero     rt_hw_interrupt_enable(temp);
462*10465441SEvalZero 
463*10465441SEvalZero     /* resume a thread, re-schedule */
464*10465441SEvalZero     if (need_schedule == RT_TRUE)
465*10465441SEvalZero         rt_schedule();
466*10465441SEvalZero 
467*10465441SEvalZero     return RT_EOK;
468*10465441SEvalZero }
469*10465441SEvalZero RTM_EXPORT(rt_sem_release);
470*10465441SEvalZero 
471*10465441SEvalZero /**
472*10465441SEvalZero  * This function can get or set some extra attributions of a semaphore object.
473*10465441SEvalZero  *
474*10465441SEvalZero  * @param sem the semaphore object
475*10465441SEvalZero  * @param cmd the execution command
476*10465441SEvalZero  * @param arg the execution argument
477*10465441SEvalZero  *
478*10465441SEvalZero  * @return the error code
479*10465441SEvalZero  */
rt_sem_control(rt_sem_t sem,int cmd,void * arg)480*10465441SEvalZero rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg)
481*10465441SEvalZero {
482*10465441SEvalZero     rt_ubase_t level;
483*10465441SEvalZero 
484*10465441SEvalZero     /* parameter check */
485*10465441SEvalZero     RT_ASSERT(sem != RT_NULL);
486*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
487*10465441SEvalZero 
488*10465441SEvalZero     if (cmd == RT_IPC_CMD_RESET)
489*10465441SEvalZero     {
490*10465441SEvalZero         rt_ubase_t value;
491*10465441SEvalZero 
492*10465441SEvalZero         /* get value */
493*10465441SEvalZero         value = (rt_ubase_t)arg;
494*10465441SEvalZero         /* disable interrupt */
495*10465441SEvalZero         level = rt_hw_interrupt_disable();
496*10465441SEvalZero 
497*10465441SEvalZero         /* resume all waiting thread */
498*10465441SEvalZero         rt_ipc_list_resume_all(&sem->parent.suspend_thread);
499*10465441SEvalZero 
500*10465441SEvalZero         /* set new value */
501*10465441SEvalZero         sem->value = (rt_uint16_t)value;
502*10465441SEvalZero 
503*10465441SEvalZero         /* enable interrupt */
504*10465441SEvalZero         rt_hw_interrupt_enable(level);
505*10465441SEvalZero 
506*10465441SEvalZero         rt_schedule();
507*10465441SEvalZero 
508*10465441SEvalZero         return RT_EOK;
509*10465441SEvalZero     }
510*10465441SEvalZero 
511*10465441SEvalZero     return -RT_ERROR;
512*10465441SEvalZero }
513*10465441SEvalZero RTM_EXPORT(rt_sem_control);
514*10465441SEvalZero #endif /* end of RT_USING_SEMAPHORE */
515*10465441SEvalZero 
516*10465441SEvalZero #ifdef RT_USING_MUTEX
517*10465441SEvalZero /**
518*10465441SEvalZero  * This function will initialize a mutex and put it under control of resource
519*10465441SEvalZero  * management.
520*10465441SEvalZero  *
521*10465441SEvalZero  * @param mutex the mutex object
522*10465441SEvalZero  * @param name the name of mutex
523*10465441SEvalZero  * @param flag the flag of mutex
524*10465441SEvalZero  *
525*10465441SEvalZero  * @return the operation status, RT_EOK on successful
526*10465441SEvalZero  */
rt_mutex_init(rt_mutex_t mutex,const char * name,rt_uint8_t flag)527*10465441SEvalZero rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
528*10465441SEvalZero {
529*10465441SEvalZero     /* parameter check */
530*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
531*10465441SEvalZero 
532*10465441SEvalZero     /* init object */
533*10465441SEvalZero     rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);
534*10465441SEvalZero 
535*10465441SEvalZero     /* init ipc object */
536*10465441SEvalZero     rt_ipc_object_init(&(mutex->parent));
537*10465441SEvalZero 
538*10465441SEvalZero     mutex->value = 1;
539*10465441SEvalZero     mutex->owner = RT_NULL;
540*10465441SEvalZero     mutex->original_priority = 0xFF;
541*10465441SEvalZero     mutex->hold  = 0;
542*10465441SEvalZero 
543*10465441SEvalZero     /* set flag */
544*10465441SEvalZero     mutex->parent.parent.flag = flag;
545*10465441SEvalZero 
546*10465441SEvalZero     return RT_EOK;
547*10465441SEvalZero }
548*10465441SEvalZero RTM_EXPORT(rt_mutex_init);
549*10465441SEvalZero 
550*10465441SEvalZero /**
551*10465441SEvalZero  * This function will detach a mutex from resource management
552*10465441SEvalZero  *
553*10465441SEvalZero  * @param mutex the mutex object
554*10465441SEvalZero  *
555*10465441SEvalZero  * @return the operation status, RT_EOK on successful
556*10465441SEvalZero  *
557*10465441SEvalZero  * @see rt_mutex_delete
558*10465441SEvalZero  */
rt_mutex_detach(rt_mutex_t mutex)559*10465441SEvalZero rt_err_t rt_mutex_detach(rt_mutex_t mutex)
560*10465441SEvalZero {
561*10465441SEvalZero     /* parameter check */
562*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
563*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
564*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent));
565*10465441SEvalZero 
566*10465441SEvalZero     /* wakeup all suspend threads */
567*10465441SEvalZero     rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));
568*10465441SEvalZero 
569*10465441SEvalZero     /* detach semaphore object */
570*10465441SEvalZero     rt_object_detach(&(mutex->parent.parent));
571*10465441SEvalZero 
572*10465441SEvalZero     return RT_EOK;
573*10465441SEvalZero }
574*10465441SEvalZero RTM_EXPORT(rt_mutex_detach);
575*10465441SEvalZero 
576*10465441SEvalZero #ifdef RT_USING_HEAP
577*10465441SEvalZero /**
578*10465441SEvalZero  * This function will create a mutex from system resource
579*10465441SEvalZero  *
580*10465441SEvalZero  * @param name the name of mutex
581*10465441SEvalZero  * @param flag the flag of mutex
582*10465441SEvalZero  *
583*10465441SEvalZero  * @return the created mutex, RT_NULL on error happen
584*10465441SEvalZero  *
585*10465441SEvalZero  * @see rt_mutex_init
586*10465441SEvalZero  */
rt_mutex_create(const char * name,rt_uint8_t flag)587*10465441SEvalZero rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
588*10465441SEvalZero {
589*10465441SEvalZero     struct rt_mutex *mutex;
590*10465441SEvalZero 
591*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
592*10465441SEvalZero 
593*10465441SEvalZero     /* allocate object */
594*10465441SEvalZero     mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
595*10465441SEvalZero     if (mutex == RT_NULL)
596*10465441SEvalZero         return mutex;
597*10465441SEvalZero 
598*10465441SEvalZero     /* init ipc object */
599*10465441SEvalZero     rt_ipc_object_init(&(mutex->parent));
600*10465441SEvalZero 
601*10465441SEvalZero     mutex->value              = 1;
602*10465441SEvalZero     mutex->owner              = RT_NULL;
603*10465441SEvalZero     mutex->original_priority  = 0xFF;
604*10465441SEvalZero     mutex->hold               = 0;
605*10465441SEvalZero 
606*10465441SEvalZero     /* set flag */
607*10465441SEvalZero     mutex->parent.parent.flag = flag;
608*10465441SEvalZero 
609*10465441SEvalZero     return mutex;
610*10465441SEvalZero }
611*10465441SEvalZero RTM_EXPORT(rt_mutex_create);
612*10465441SEvalZero 
613*10465441SEvalZero /**
614*10465441SEvalZero  * This function will delete a mutex object and release the memory
615*10465441SEvalZero  *
616*10465441SEvalZero  * @param mutex the mutex object
617*10465441SEvalZero  *
618*10465441SEvalZero  * @return the error code
619*10465441SEvalZero  *
620*10465441SEvalZero  * @see rt_mutex_detach
621*10465441SEvalZero  */
rt_mutex_delete(rt_mutex_t mutex)622*10465441SEvalZero rt_err_t rt_mutex_delete(rt_mutex_t mutex)
623*10465441SEvalZero {
624*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
625*10465441SEvalZero 
626*10465441SEvalZero     /* parameter check */
627*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
628*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
629*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent) == RT_FALSE);
630*10465441SEvalZero 
631*10465441SEvalZero     /* wakeup all suspend threads */
632*10465441SEvalZero     rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));
633*10465441SEvalZero 
634*10465441SEvalZero     /* delete semaphore object */
635*10465441SEvalZero     rt_object_delete(&(mutex->parent.parent));
636*10465441SEvalZero 
637*10465441SEvalZero     return RT_EOK;
638*10465441SEvalZero }
639*10465441SEvalZero RTM_EXPORT(rt_mutex_delete);
640*10465441SEvalZero #endif
641*10465441SEvalZero 
642*10465441SEvalZero /**
643*10465441SEvalZero  * This function will take a mutex, if the mutex is unavailable, the
644*10465441SEvalZero  * thread shall wait for a specified time.
645*10465441SEvalZero  *
646*10465441SEvalZero  * @param mutex the mutex object
647*10465441SEvalZero  * @param time the waiting time
648*10465441SEvalZero  *
649*10465441SEvalZero  * @return the error code
650*10465441SEvalZero  */
rt_mutex_take(rt_mutex_t mutex,rt_int32_t time)651*10465441SEvalZero rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
652*10465441SEvalZero {
653*10465441SEvalZero     register rt_base_t temp;
654*10465441SEvalZero     struct rt_thread *thread;
655*10465441SEvalZero 
656*10465441SEvalZero     /* this function must not be used in interrupt even if time = 0 */
657*10465441SEvalZero     RT_DEBUG_IN_THREAD_CONTEXT;
658*10465441SEvalZero 
659*10465441SEvalZero     /* parameter check */
660*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
661*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
662*10465441SEvalZero 
663*10465441SEvalZero     /* get current thread */
664*10465441SEvalZero     thread = rt_thread_self();
665*10465441SEvalZero 
666*10465441SEvalZero     /* disable interrupt */
667*10465441SEvalZero     temp = rt_hw_interrupt_disable();
668*10465441SEvalZero 
669*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent)));
670*10465441SEvalZero 
671*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_IPC,
672*10465441SEvalZero                  ("mutex_take: current thread %s, mutex value: %d, hold: %d\n",
673*10465441SEvalZero                   thread->name, mutex->value, mutex->hold));
674*10465441SEvalZero 
675*10465441SEvalZero     /* reset thread error */
676*10465441SEvalZero     thread->error = RT_EOK;
677*10465441SEvalZero 
678*10465441SEvalZero     if (mutex->owner == thread)
679*10465441SEvalZero     {
680*10465441SEvalZero         /* it's the same thread */
681*10465441SEvalZero         mutex->hold ++;
682*10465441SEvalZero     }
683*10465441SEvalZero     else
684*10465441SEvalZero     {
685*10465441SEvalZero __again:
686*10465441SEvalZero         /* The value of mutex is 1 in initial status. Therefore, if the
687*10465441SEvalZero          * value is great than 0, it indicates the mutex is avaible.
688*10465441SEvalZero          */
689*10465441SEvalZero         if (mutex->value > 0)
690*10465441SEvalZero         {
691*10465441SEvalZero             /* mutex is available */
692*10465441SEvalZero             mutex->value --;
693*10465441SEvalZero 
694*10465441SEvalZero             /* set mutex owner and original priority */
695*10465441SEvalZero             mutex->owner             = thread;
696*10465441SEvalZero             mutex->original_priority = thread->current_priority;
697*10465441SEvalZero             mutex->hold ++;
698*10465441SEvalZero         }
699*10465441SEvalZero         else
700*10465441SEvalZero         {
701*10465441SEvalZero             /* no waiting, return with timeout */
702*10465441SEvalZero             if (time == 0)
703*10465441SEvalZero             {
704*10465441SEvalZero                 /* set error as timeout */
705*10465441SEvalZero                 thread->error = -RT_ETIMEOUT;
706*10465441SEvalZero 
707*10465441SEvalZero                 /* enable interrupt */
708*10465441SEvalZero                 rt_hw_interrupt_enable(temp);
709*10465441SEvalZero 
710*10465441SEvalZero                 return -RT_ETIMEOUT;
711*10465441SEvalZero             }
712*10465441SEvalZero             else
713*10465441SEvalZero             {
714*10465441SEvalZero                 /* mutex is unavailable, push to suspend list */
715*10465441SEvalZero                 RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
716*10465441SEvalZero                                             thread->name));
717*10465441SEvalZero 
718*10465441SEvalZero                 /* change the owner thread priority of mutex */
719*10465441SEvalZero                 if (thread->current_priority < mutex->owner->current_priority)
720*10465441SEvalZero                 {
721*10465441SEvalZero                     /* change the owner thread priority */
722*10465441SEvalZero                     rt_thread_control(mutex->owner,
723*10465441SEvalZero                                       RT_THREAD_CTRL_CHANGE_PRIORITY,
724*10465441SEvalZero                                       &thread->current_priority);
725*10465441SEvalZero                 }
726*10465441SEvalZero 
727*10465441SEvalZero                 /* suspend current thread */
728*10465441SEvalZero                 rt_ipc_list_suspend(&(mutex->parent.suspend_thread),
729*10465441SEvalZero                                     thread,
730*10465441SEvalZero                                     mutex->parent.parent.flag);
731*10465441SEvalZero 
732*10465441SEvalZero                 /* has waiting time, start thread timer */
733*10465441SEvalZero                 if (time > 0)
734*10465441SEvalZero                 {
735*10465441SEvalZero                     RT_DEBUG_LOG(RT_DEBUG_IPC,
736*10465441SEvalZero                                  ("mutex_take: start the timer of thread:%s\n",
737*10465441SEvalZero                                   thread->name));
738*10465441SEvalZero 
739*10465441SEvalZero                     /* reset the timeout of thread timer and start it */
740*10465441SEvalZero                     rt_timer_control(&(thread->thread_timer),
741*10465441SEvalZero                                      RT_TIMER_CTRL_SET_TIME,
742*10465441SEvalZero                                      &time);
743*10465441SEvalZero                     rt_timer_start(&(thread->thread_timer));
744*10465441SEvalZero                 }
745*10465441SEvalZero 
746*10465441SEvalZero                 /* enable interrupt */
747*10465441SEvalZero                 rt_hw_interrupt_enable(temp);
748*10465441SEvalZero 
749*10465441SEvalZero                 /* do schedule */
750*10465441SEvalZero                 rt_schedule();
751*10465441SEvalZero 
752*10465441SEvalZero                 if (thread->error != RT_EOK)
753*10465441SEvalZero                 {
754*10465441SEvalZero                 	/* interrupt by signal, try it again */
755*10465441SEvalZero                 	if (thread->error == -RT_EINTR) goto __again;
756*10465441SEvalZero 
757*10465441SEvalZero                     /* return error */
758*10465441SEvalZero                     return thread->error;
759*10465441SEvalZero                 }
760*10465441SEvalZero                 else
761*10465441SEvalZero                 {
762*10465441SEvalZero                     /* the mutex is taken successfully. */
763*10465441SEvalZero                     /* disable interrupt */
764*10465441SEvalZero                     temp = rt_hw_interrupt_disable();
765*10465441SEvalZero                 }
766*10465441SEvalZero             }
767*10465441SEvalZero         }
768*10465441SEvalZero     }
769*10465441SEvalZero 
770*10465441SEvalZero     /* enable interrupt */
771*10465441SEvalZero     rt_hw_interrupt_enable(temp);
772*10465441SEvalZero 
773*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent)));
774*10465441SEvalZero 
775*10465441SEvalZero     return RT_EOK;
776*10465441SEvalZero }
777*10465441SEvalZero RTM_EXPORT(rt_mutex_take);
778*10465441SEvalZero 
779*10465441SEvalZero /**
780*10465441SEvalZero  * This function will release a mutex, if there are threads suspended on mutex,
781*10465441SEvalZero  * it will be waked up.
782*10465441SEvalZero  *
783*10465441SEvalZero  * @param mutex the mutex object
784*10465441SEvalZero  *
785*10465441SEvalZero  * @return the error code
786*10465441SEvalZero  */
rt_mutex_release(rt_mutex_t mutex)787*10465441SEvalZero rt_err_t rt_mutex_release(rt_mutex_t mutex)
788*10465441SEvalZero {
789*10465441SEvalZero     register rt_base_t temp;
790*10465441SEvalZero     struct rt_thread *thread;
791*10465441SEvalZero     rt_bool_t need_schedule;
792*10465441SEvalZero 
793*10465441SEvalZero     /* parameter check */
794*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
795*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
796*10465441SEvalZero 
797*10465441SEvalZero     need_schedule = RT_FALSE;
798*10465441SEvalZero 
799*10465441SEvalZero     /* only thread could release mutex because we need test the ownership */
800*10465441SEvalZero     RT_DEBUG_IN_THREAD_CONTEXT;
801*10465441SEvalZero 
802*10465441SEvalZero     /* get current thread */
803*10465441SEvalZero     thread = rt_thread_self();
804*10465441SEvalZero 
805*10465441SEvalZero     /* disable interrupt */
806*10465441SEvalZero     temp = rt_hw_interrupt_disable();
807*10465441SEvalZero 
808*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_IPC,
809*10465441SEvalZero                  ("mutex_release:current thread %s, mutex value: %d, hold: %d\n",
810*10465441SEvalZero                   thread->name, mutex->value, mutex->hold));
811*10465441SEvalZero 
812*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
813*10465441SEvalZero 
814*10465441SEvalZero     /* mutex only can be released by owner */
815*10465441SEvalZero     if (thread != mutex->owner)
816*10465441SEvalZero     {
817*10465441SEvalZero         thread->error = -RT_ERROR;
818*10465441SEvalZero 
819*10465441SEvalZero         /* enable interrupt */
820*10465441SEvalZero         rt_hw_interrupt_enable(temp);
821*10465441SEvalZero 
822*10465441SEvalZero         return -RT_ERROR;
823*10465441SEvalZero     }
824*10465441SEvalZero 
825*10465441SEvalZero     /* decrease hold */
826*10465441SEvalZero     mutex->hold --;
827*10465441SEvalZero     /* if no hold */
828*10465441SEvalZero     if (mutex->hold == 0)
829*10465441SEvalZero     {
830*10465441SEvalZero         /* change the owner thread to original priority */
831*10465441SEvalZero         if (mutex->original_priority != mutex->owner->current_priority)
832*10465441SEvalZero         {
833*10465441SEvalZero             rt_thread_control(mutex->owner,
834*10465441SEvalZero                               RT_THREAD_CTRL_CHANGE_PRIORITY,
835*10465441SEvalZero                               &(mutex->original_priority));
836*10465441SEvalZero         }
837*10465441SEvalZero 
838*10465441SEvalZero         /* wakeup suspended thread */
839*10465441SEvalZero         if (!rt_list_isempty(&mutex->parent.suspend_thread))
840*10465441SEvalZero         {
841*10465441SEvalZero             /* get suspended thread */
842*10465441SEvalZero             thread = rt_list_entry(mutex->parent.suspend_thread.next,
843*10465441SEvalZero                                    struct rt_thread,
844*10465441SEvalZero                                    tlist);
845*10465441SEvalZero 
846*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
847*10465441SEvalZero                                         thread->name));
848*10465441SEvalZero 
849*10465441SEvalZero             /* set new owner and priority */
850*10465441SEvalZero             mutex->owner             = thread;
851*10465441SEvalZero             mutex->original_priority = thread->current_priority;
852*10465441SEvalZero             mutex->hold ++;
853*10465441SEvalZero 
854*10465441SEvalZero             /* resume thread */
855*10465441SEvalZero             rt_ipc_list_resume(&(mutex->parent.suspend_thread));
856*10465441SEvalZero 
857*10465441SEvalZero             need_schedule = RT_TRUE;
858*10465441SEvalZero         }
859*10465441SEvalZero         else
860*10465441SEvalZero         {
861*10465441SEvalZero             /* increase value */
862*10465441SEvalZero             mutex->value ++;
863*10465441SEvalZero 
864*10465441SEvalZero             /* clear owner */
865*10465441SEvalZero             mutex->owner             = RT_NULL;
866*10465441SEvalZero             mutex->original_priority = 0xff;
867*10465441SEvalZero         }
868*10465441SEvalZero     }
869*10465441SEvalZero 
870*10465441SEvalZero     /* enable interrupt */
871*10465441SEvalZero     rt_hw_interrupt_enable(temp);
872*10465441SEvalZero 
873*10465441SEvalZero     /* perform a schedule */
874*10465441SEvalZero     if (need_schedule == RT_TRUE)
875*10465441SEvalZero         rt_schedule();
876*10465441SEvalZero 
877*10465441SEvalZero     return RT_EOK;
878*10465441SEvalZero }
879*10465441SEvalZero RTM_EXPORT(rt_mutex_release);
880*10465441SEvalZero 
881*10465441SEvalZero /**
882*10465441SEvalZero  * This function can get or set some extra attributions of a mutex object.
883*10465441SEvalZero  *
884*10465441SEvalZero  * @param mutex the mutex object
885*10465441SEvalZero  * @param cmd the execution command
886*10465441SEvalZero  * @param arg the execution argument
887*10465441SEvalZero  *
888*10465441SEvalZero  * @return the error code
889*10465441SEvalZero  */
rt_mutex_control(rt_mutex_t mutex,int cmd,void * arg)890*10465441SEvalZero rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg)
891*10465441SEvalZero {
892*10465441SEvalZero     /* parameter check */
893*10465441SEvalZero     RT_ASSERT(mutex != RT_NULL);
894*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
895*10465441SEvalZero 
896*10465441SEvalZero     return -RT_ERROR;
897*10465441SEvalZero }
898*10465441SEvalZero RTM_EXPORT(rt_mutex_control);
899*10465441SEvalZero #endif /* end of RT_USING_MUTEX */
900*10465441SEvalZero 
901*10465441SEvalZero #ifdef RT_USING_EVENT
902*10465441SEvalZero /**
903*10465441SEvalZero  * This function will initialize an event and put it under control of resource
904*10465441SEvalZero  * management.
905*10465441SEvalZero  *
906*10465441SEvalZero  * @param event the event object
907*10465441SEvalZero  * @param name the name of event
908*10465441SEvalZero  * @param flag the flag of event
909*10465441SEvalZero  *
910*10465441SEvalZero  * @return the operation status, RT_EOK on successful
911*10465441SEvalZero  */
rt_event_init(rt_event_t event,const char * name,rt_uint8_t flag)912*10465441SEvalZero rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
913*10465441SEvalZero {
914*10465441SEvalZero     /* parameter check */
915*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
916*10465441SEvalZero 
917*10465441SEvalZero     /* init object */
918*10465441SEvalZero     rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
919*10465441SEvalZero 
920*10465441SEvalZero     /* set parent flag */
921*10465441SEvalZero     event->parent.parent.flag = flag;
922*10465441SEvalZero 
923*10465441SEvalZero     /* init ipc object */
924*10465441SEvalZero     rt_ipc_object_init(&(event->parent));
925*10465441SEvalZero 
926*10465441SEvalZero     /* init event */
927*10465441SEvalZero     event->set = 0;
928*10465441SEvalZero 
929*10465441SEvalZero     return RT_EOK;
930*10465441SEvalZero }
931*10465441SEvalZero RTM_EXPORT(rt_event_init);
932*10465441SEvalZero 
933*10465441SEvalZero /**
934*10465441SEvalZero  * This function will detach an event object from resource management
935*10465441SEvalZero  *
936*10465441SEvalZero  * @param event the event object
937*10465441SEvalZero  *
938*10465441SEvalZero  * @return the operation status, RT_EOK on successful
939*10465441SEvalZero  */
rt_event_detach(rt_event_t event)940*10465441SEvalZero rt_err_t rt_event_detach(rt_event_t event)
941*10465441SEvalZero {
942*10465441SEvalZero     /* parameter check */
943*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
944*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
945*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&event->parent.parent));
946*10465441SEvalZero 
947*10465441SEvalZero     /* resume all suspended thread */
948*10465441SEvalZero     rt_ipc_list_resume_all(&(event->parent.suspend_thread));
949*10465441SEvalZero 
950*10465441SEvalZero     /* detach event object */
951*10465441SEvalZero     rt_object_detach(&(event->parent.parent));
952*10465441SEvalZero 
953*10465441SEvalZero     return RT_EOK;
954*10465441SEvalZero }
955*10465441SEvalZero RTM_EXPORT(rt_event_detach);
956*10465441SEvalZero 
957*10465441SEvalZero #ifdef RT_USING_HEAP
958*10465441SEvalZero /**
959*10465441SEvalZero  * This function will create an event object from system resource
960*10465441SEvalZero  *
961*10465441SEvalZero  * @param name the name of event
962*10465441SEvalZero  * @param flag the flag of event
963*10465441SEvalZero  *
964*10465441SEvalZero  * @return the created event, RT_NULL on error happen
965*10465441SEvalZero  */
rt_event_create(const char * name,rt_uint8_t flag)966*10465441SEvalZero rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
967*10465441SEvalZero {
968*10465441SEvalZero     rt_event_t event;
969*10465441SEvalZero 
970*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
971*10465441SEvalZero 
972*10465441SEvalZero     /* allocate object */
973*10465441SEvalZero     event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name);
974*10465441SEvalZero     if (event == RT_NULL)
975*10465441SEvalZero         return event;
976*10465441SEvalZero 
977*10465441SEvalZero     /* set parent */
978*10465441SEvalZero     event->parent.parent.flag = flag;
979*10465441SEvalZero 
980*10465441SEvalZero     /* init ipc object */
981*10465441SEvalZero     rt_ipc_object_init(&(event->parent));
982*10465441SEvalZero 
983*10465441SEvalZero     /* init event */
984*10465441SEvalZero     event->set = 0;
985*10465441SEvalZero 
986*10465441SEvalZero     return event;
987*10465441SEvalZero }
988*10465441SEvalZero RTM_EXPORT(rt_event_create);
989*10465441SEvalZero 
990*10465441SEvalZero /**
991*10465441SEvalZero  * This function will delete an event object and release the memory
992*10465441SEvalZero  *
993*10465441SEvalZero  * @param event the event object
994*10465441SEvalZero  *
995*10465441SEvalZero  * @return the error code
996*10465441SEvalZero  */
rt_event_delete(rt_event_t event)997*10465441SEvalZero rt_err_t rt_event_delete(rt_event_t event)
998*10465441SEvalZero {
999*10465441SEvalZero     /* parameter check */
1000*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
1001*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
1002*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&event->parent.parent) == RT_FALSE);
1003*10465441SEvalZero 
1004*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
1005*10465441SEvalZero 
1006*10465441SEvalZero     /* resume all suspended thread */
1007*10465441SEvalZero     rt_ipc_list_resume_all(&(event->parent.suspend_thread));
1008*10465441SEvalZero 
1009*10465441SEvalZero     /* delete event object */
1010*10465441SEvalZero     rt_object_delete(&(event->parent.parent));
1011*10465441SEvalZero 
1012*10465441SEvalZero     return RT_EOK;
1013*10465441SEvalZero }
1014*10465441SEvalZero RTM_EXPORT(rt_event_delete);
1015*10465441SEvalZero #endif
1016*10465441SEvalZero 
1017*10465441SEvalZero /**
1018*10465441SEvalZero  * This function will send an event to the event object, if there are threads
1019*10465441SEvalZero  * suspended on event object, it will be waked up.
1020*10465441SEvalZero  *
1021*10465441SEvalZero  * @param event the event object
1022*10465441SEvalZero  * @param set the event set
1023*10465441SEvalZero  *
1024*10465441SEvalZero  * @return the error code
1025*10465441SEvalZero  */
rt_event_send(rt_event_t event,rt_uint32_t set)1026*10465441SEvalZero rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
1027*10465441SEvalZero {
1028*10465441SEvalZero     struct rt_list_node *n;
1029*10465441SEvalZero     struct rt_thread *thread;
1030*10465441SEvalZero     register rt_ubase_t level;
1031*10465441SEvalZero     register rt_base_t status;
1032*10465441SEvalZero     rt_bool_t need_schedule;
1033*10465441SEvalZero 
1034*10465441SEvalZero     /* parameter check */
1035*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
1036*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
1037*10465441SEvalZero 
1038*10465441SEvalZero     if (set == 0)
1039*10465441SEvalZero         return -RT_ERROR;
1040*10465441SEvalZero 
1041*10465441SEvalZero     need_schedule = RT_FALSE;
1042*10465441SEvalZero 
1043*10465441SEvalZero     /* disable interrupt */
1044*10465441SEvalZero     level = rt_hw_interrupt_disable();
1045*10465441SEvalZero 
1046*10465441SEvalZero     /* set event */
1047*10465441SEvalZero     event->set |= set;
1048*10465441SEvalZero 
1049*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(event->parent.parent)));
1050*10465441SEvalZero 
1051*10465441SEvalZero     if (!rt_list_isempty(&event->parent.suspend_thread))
1052*10465441SEvalZero     {
1053*10465441SEvalZero         /* search thread list to resume thread */
1054*10465441SEvalZero         n = event->parent.suspend_thread.next;
1055*10465441SEvalZero         while (n != &(event->parent.suspend_thread))
1056*10465441SEvalZero         {
1057*10465441SEvalZero             /* get thread */
1058*10465441SEvalZero             thread = rt_list_entry(n, struct rt_thread, tlist);
1059*10465441SEvalZero 
1060*10465441SEvalZero             status = -RT_ERROR;
1061*10465441SEvalZero             if (thread->event_info & RT_EVENT_FLAG_AND)
1062*10465441SEvalZero             {
1063*10465441SEvalZero                 if ((thread->event_set & event->set) == thread->event_set)
1064*10465441SEvalZero                 {
1065*10465441SEvalZero                     /* received an AND event */
1066*10465441SEvalZero                     status = RT_EOK;
1067*10465441SEvalZero                 }
1068*10465441SEvalZero             }
1069*10465441SEvalZero             else if (thread->event_info & RT_EVENT_FLAG_OR)
1070*10465441SEvalZero             {
1071*10465441SEvalZero                 if (thread->event_set & event->set)
1072*10465441SEvalZero                 {
1073*10465441SEvalZero                     /* save recieved event set */
1074*10465441SEvalZero                     thread->event_set = thread->event_set & event->set;
1075*10465441SEvalZero 
1076*10465441SEvalZero                     /* received an OR event */
1077*10465441SEvalZero                     status = RT_EOK;
1078*10465441SEvalZero                 }
1079*10465441SEvalZero             }
1080*10465441SEvalZero 
1081*10465441SEvalZero             /* move node to the next */
1082*10465441SEvalZero             n = n->next;
1083*10465441SEvalZero 
1084*10465441SEvalZero             /* condition is satisfied, resume thread */
1085*10465441SEvalZero             if (status == RT_EOK)
1086*10465441SEvalZero             {
1087*10465441SEvalZero                 /* clear event */
1088*10465441SEvalZero                 if (thread->event_info & RT_EVENT_FLAG_CLEAR)
1089*10465441SEvalZero                     event->set &= ~thread->event_set;
1090*10465441SEvalZero 
1091*10465441SEvalZero                 /* resume thread, and thread list breaks out */
1092*10465441SEvalZero                 rt_thread_resume(thread);
1093*10465441SEvalZero 
1094*10465441SEvalZero                 /* need do a scheduling */
1095*10465441SEvalZero                 need_schedule = RT_TRUE;
1096*10465441SEvalZero             }
1097*10465441SEvalZero         }
1098*10465441SEvalZero     }
1099*10465441SEvalZero 
1100*10465441SEvalZero     /* enable interrupt */
1101*10465441SEvalZero     rt_hw_interrupt_enable(level);
1102*10465441SEvalZero 
1103*10465441SEvalZero     /* do a schedule */
1104*10465441SEvalZero     if (need_schedule == RT_TRUE)
1105*10465441SEvalZero         rt_schedule();
1106*10465441SEvalZero 
1107*10465441SEvalZero     return RT_EOK;
1108*10465441SEvalZero }
1109*10465441SEvalZero RTM_EXPORT(rt_event_send);
1110*10465441SEvalZero 
1111*10465441SEvalZero /**
1112*10465441SEvalZero  * This function will receive an event from event object, if the event is
1113*10465441SEvalZero  * unavailable, the thread shall wait for a specified time.
1114*10465441SEvalZero  *
1115*10465441SEvalZero  * @param event the fast event object
1116*10465441SEvalZero  * @param set the interested event set
1117*10465441SEvalZero  * @param option the receive option, either RT_EVENT_FLAG_AND or
1118*10465441SEvalZero  *        RT_EVENT_FLAG_OR should be set.
1119*10465441SEvalZero  * @param timeout the waiting time
1120*10465441SEvalZero  * @param recved the received event, if you don't care, RT_NULL can be set.
1121*10465441SEvalZero  *
1122*10465441SEvalZero  * @return the error code
1123*10465441SEvalZero  */
rt_event_recv(rt_event_t event,rt_uint32_t set,rt_uint8_t option,rt_int32_t timeout,rt_uint32_t * recved)1124*10465441SEvalZero rt_err_t rt_event_recv(rt_event_t   event,
1125*10465441SEvalZero                        rt_uint32_t  set,
1126*10465441SEvalZero                        rt_uint8_t   option,
1127*10465441SEvalZero                        rt_int32_t   timeout,
1128*10465441SEvalZero                        rt_uint32_t *recved)
1129*10465441SEvalZero {
1130*10465441SEvalZero     struct rt_thread *thread;
1131*10465441SEvalZero     register rt_ubase_t level;
1132*10465441SEvalZero     register rt_base_t status;
1133*10465441SEvalZero 
1134*10465441SEvalZero     RT_DEBUG_IN_THREAD_CONTEXT;
1135*10465441SEvalZero 
1136*10465441SEvalZero     /* parameter check */
1137*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
1138*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
1139*10465441SEvalZero 
1140*10465441SEvalZero     if (set == 0)
1141*10465441SEvalZero         return -RT_ERROR;
1142*10465441SEvalZero 
1143*10465441SEvalZero     /* init status */
1144*10465441SEvalZero     status = -RT_ERROR;
1145*10465441SEvalZero     /* get current thread */
1146*10465441SEvalZero     thread = rt_thread_self();
1147*10465441SEvalZero     /* reset thread error */
1148*10465441SEvalZero     thread->error = RT_EOK;
1149*10465441SEvalZero 
1150*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(event->parent.parent)));
1151*10465441SEvalZero 
1152*10465441SEvalZero     /* disable interrupt */
1153*10465441SEvalZero     level = rt_hw_interrupt_disable();
1154*10465441SEvalZero 
1155*10465441SEvalZero     /* check event set */
1156*10465441SEvalZero     if (option & RT_EVENT_FLAG_AND)
1157*10465441SEvalZero     {
1158*10465441SEvalZero         if ((event->set & set) == set)
1159*10465441SEvalZero             status = RT_EOK;
1160*10465441SEvalZero     }
1161*10465441SEvalZero     else if (option & RT_EVENT_FLAG_OR)
1162*10465441SEvalZero     {
1163*10465441SEvalZero         if (event->set & set)
1164*10465441SEvalZero             status = RT_EOK;
1165*10465441SEvalZero     }
1166*10465441SEvalZero     else
1167*10465441SEvalZero     {
1168*10465441SEvalZero         /* either RT_EVENT_FLAG_AND or RT_EVENT_FLAG_OR should be set */
1169*10465441SEvalZero         RT_ASSERT(0);
1170*10465441SEvalZero     }
1171*10465441SEvalZero 
1172*10465441SEvalZero     if (status == RT_EOK)
1173*10465441SEvalZero     {
1174*10465441SEvalZero         /* set received event */
1175*10465441SEvalZero         if (recved)
1176*10465441SEvalZero             *recved = (event->set & set);
1177*10465441SEvalZero 
1178*10465441SEvalZero         /* received event */
1179*10465441SEvalZero         if (option & RT_EVENT_FLAG_CLEAR)
1180*10465441SEvalZero             event->set &= ~set;
1181*10465441SEvalZero     }
1182*10465441SEvalZero     else if (timeout == 0)
1183*10465441SEvalZero     {
1184*10465441SEvalZero         /* no waiting */
1185*10465441SEvalZero         thread->error = -RT_ETIMEOUT;
1186*10465441SEvalZero     }
1187*10465441SEvalZero     else
1188*10465441SEvalZero     {
1189*10465441SEvalZero         /* fill thread event info */
1190*10465441SEvalZero         thread->event_set  = set;
1191*10465441SEvalZero         thread->event_info = option;
1192*10465441SEvalZero 
1193*10465441SEvalZero         /* put thread to suspended thread list */
1194*10465441SEvalZero         rt_ipc_list_suspend(&(event->parent.suspend_thread),
1195*10465441SEvalZero                             thread,
1196*10465441SEvalZero                             event->parent.parent.flag);
1197*10465441SEvalZero 
1198*10465441SEvalZero         /* if there is a waiting timeout, active thread timer */
1199*10465441SEvalZero         if (timeout > 0)
1200*10465441SEvalZero         {
1201*10465441SEvalZero             /* reset the timeout of thread timer and start it */
1202*10465441SEvalZero             rt_timer_control(&(thread->thread_timer),
1203*10465441SEvalZero                              RT_TIMER_CTRL_SET_TIME,
1204*10465441SEvalZero                              &timeout);
1205*10465441SEvalZero             rt_timer_start(&(thread->thread_timer));
1206*10465441SEvalZero         }
1207*10465441SEvalZero 
1208*10465441SEvalZero         /* enable interrupt */
1209*10465441SEvalZero         rt_hw_interrupt_enable(level);
1210*10465441SEvalZero 
1211*10465441SEvalZero         /* do a schedule */
1212*10465441SEvalZero         rt_schedule();
1213*10465441SEvalZero 
1214*10465441SEvalZero         if (thread->error != RT_EOK)
1215*10465441SEvalZero         {
1216*10465441SEvalZero             /* return error */
1217*10465441SEvalZero             return thread->error;
1218*10465441SEvalZero         }
1219*10465441SEvalZero 
1220*10465441SEvalZero         /* received an event, disable interrupt to protect */
1221*10465441SEvalZero         level = rt_hw_interrupt_disable();
1222*10465441SEvalZero 
1223*10465441SEvalZero         /* set received event */
1224*10465441SEvalZero         if (recved)
1225*10465441SEvalZero             *recved = thread->event_set;
1226*10465441SEvalZero     }
1227*10465441SEvalZero 
1228*10465441SEvalZero     /* enable interrupt */
1229*10465441SEvalZero     rt_hw_interrupt_enable(level);
1230*10465441SEvalZero 
1231*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(event->parent.parent)));
1232*10465441SEvalZero 
1233*10465441SEvalZero     return thread->error;
1234*10465441SEvalZero }
1235*10465441SEvalZero RTM_EXPORT(rt_event_recv);
1236*10465441SEvalZero 
1237*10465441SEvalZero /**
1238*10465441SEvalZero  * This function can get or set some extra attributions of an event object.
1239*10465441SEvalZero  *
1240*10465441SEvalZero  * @param event the event object
1241*10465441SEvalZero  * @param cmd the execution command
1242*10465441SEvalZero  * @param arg the execution argument
1243*10465441SEvalZero  *
1244*10465441SEvalZero  * @return the error code
1245*10465441SEvalZero  */
rt_event_control(rt_event_t event,int cmd,void * arg)1246*10465441SEvalZero rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg)
1247*10465441SEvalZero {
1248*10465441SEvalZero     rt_ubase_t level;
1249*10465441SEvalZero 
1250*10465441SEvalZero     /* parameter check */
1251*10465441SEvalZero     RT_ASSERT(event != RT_NULL);
1252*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
1253*10465441SEvalZero 
1254*10465441SEvalZero     if (cmd == RT_IPC_CMD_RESET)
1255*10465441SEvalZero     {
1256*10465441SEvalZero         /* disable interrupt */
1257*10465441SEvalZero         level = rt_hw_interrupt_disable();
1258*10465441SEvalZero 
1259*10465441SEvalZero         /* resume all waiting thread */
1260*10465441SEvalZero         rt_ipc_list_resume_all(&event->parent.suspend_thread);
1261*10465441SEvalZero 
1262*10465441SEvalZero         /* init event set */
1263*10465441SEvalZero         event->set = 0;
1264*10465441SEvalZero 
1265*10465441SEvalZero         /* enable interrupt */
1266*10465441SEvalZero         rt_hw_interrupt_enable(level);
1267*10465441SEvalZero 
1268*10465441SEvalZero         rt_schedule();
1269*10465441SEvalZero 
1270*10465441SEvalZero         return RT_EOK;
1271*10465441SEvalZero     }
1272*10465441SEvalZero 
1273*10465441SEvalZero     return -RT_ERROR;
1274*10465441SEvalZero }
1275*10465441SEvalZero RTM_EXPORT(rt_event_control);
1276*10465441SEvalZero #endif /* end of RT_USING_EVENT */
1277*10465441SEvalZero 
1278*10465441SEvalZero #ifdef RT_USING_MAILBOX
1279*10465441SEvalZero /**
1280*10465441SEvalZero  * This function will initialize a mailbox and put it under control of resource
1281*10465441SEvalZero  * management.
1282*10465441SEvalZero  *
1283*10465441SEvalZero  * @param mb the mailbox object
1284*10465441SEvalZero  * @param name the name of mailbox
1285*10465441SEvalZero  * @param msgpool the begin address of buffer to save received mail
1286*10465441SEvalZero  * @param size the size of mailbox
1287*10465441SEvalZero  * @param flag the flag of mailbox
1288*10465441SEvalZero  *
1289*10465441SEvalZero  * @return the operation status, RT_EOK on successful
1290*10465441SEvalZero  */
rt_mb_init(rt_mailbox_t mb,const char * name,void * msgpool,rt_size_t size,rt_uint8_t flag)1291*10465441SEvalZero rt_err_t rt_mb_init(rt_mailbox_t mb,
1292*10465441SEvalZero                     const char  *name,
1293*10465441SEvalZero                     void        *msgpool,
1294*10465441SEvalZero                     rt_size_t    size,
1295*10465441SEvalZero                     rt_uint8_t   flag)
1296*10465441SEvalZero {
1297*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1298*10465441SEvalZero 
1299*10465441SEvalZero     /* init object */
1300*10465441SEvalZero     rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);
1301*10465441SEvalZero 
1302*10465441SEvalZero     /* set parent flag */
1303*10465441SEvalZero     mb->parent.parent.flag = flag;
1304*10465441SEvalZero 
1305*10465441SEvalZero     /* init ipc object */
1306*10465441SEvalZero     rt_ipc_object_init(&(mb->parent));
1307*10465441SEvalZero 
1308*10465441SEvalZero     /* init mailbox */
1309*10465441SEvalZero     mb->msg_pool   = msgpool;
1310*10465441SEvalZero     mb->size       = size;
1311*10465441SEvalZero     mb->entry      = 0;
1312*10465441SEvalZero     mb->in_offset  = 0;
1313*10465441SEvalZero     mb->out_offset = 0;
1314*10465441SEvalZero 
1315*10465441SEvalZero     /* init an additional list of sender suspend thread */
1316*10465441SEvalZero     rt_list_init(&(mb->suspend_sender_thread));
1317*10465441SEvalZero 
1318*10465441SEvalZero     return RT_EOK;
1319*10465441SEvalZero }
1320*10465441SEvalZero RTM_EXPORT(rt_mb_init);
1321*10465441SEvalZero 
1322*10465441SEvalZero /**
1323*10465441SEvalZero  * This function will detach a mailbox from resource management
1324*10465441SEvalZero  *
1325*10465441SEvalZero  * @param mb the mailbox object
1326*10465441SEvalZero  *
1327*10465441SEvalZero  * @return the operation status, RT_EOK on successful
1328*10465441SEvalZero  */
rt_mb_detach(rt_mailbox_t mb)1329*10465441SEvalZero rt_err_t rt_mb_detach(rt_mailbox_t mb)
1330*10465441SEvalZero {
1331*10465441SEvalZero     /* parameter check */
1332*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1333*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
1334*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent));
1335*10465441SEvalZero 
1336*10465441SEvalZero     /* resume all suspended thread */
1337*10465441SEvalZero     rt_ipc_list_resume_all(&(mb->parent.suspend_thread));
1338*10465441SEvalZero     /* also resume all mailbox private suspended thread */
1339*10465441SEvalZero     rt_ipc_list_resume_all(&(mb->suspend_sender_thread));
1340*10465441SEvalZero 
1341*10465441SEvalZero     /* detach mailbox object */
1342*10465441SEvalZero     rt_object_detach(&(mb->parent.parent));
1343*10465441SEvalZero 
1344*10465441SEvalZero     return RT_EOK;
1345*10465441SEvalZero }
1346*10465441SEvalZero RTM_EXPORT(rt_mb_detach);
1347*10465441SEvalZero 
1348*10465441SEvalZero #ifdef RT_USING_HEAP
1349*10465441SEvalZero /**
1350*10465441SEvalZero  * This function will create a mailbox object from system resource
1351*10465441SEvalZero  *
1352*10465441SEvalZero  * @param name the name of mailbox
1353*10465441SEvalZero  * @param size the size of mailbox
1354*10465441SEvalZero  * @param flag the flag of mailbox
1355*10465441SEvalZero  *
1356*10465441SEvalZero  * @return the created mailbox, RT_NULL on error happen
1357*10465441SEvalZero  */
rt_mb_create(const char * name,rt_size_t size,rt_uint8_t flag)1358*10465441SEvalZero rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
1359*10465441SEvalZero {
1360*10465441SEvalZero     rt_mailbox_t mb;
1361*10465441SEvalZero 
1362*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
1363*10465441SEvalZero 
1364*10465441SEvalZero     /* allocate object */
1365*10465441SEvalZero     mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name);
1366*10465441SEvalZero     if (mb == RT_NULL)
1367*10465441SEvalZero         return mb;
1368*10465441SEvalZero 
1369*10465441SEvalZero     /* set parent */
1370*10465441SEvalZero     mb->parent.parent.flag = flag;
1371*10465441SEvalZero 
1372*10465441SEvalZero     /* init ipc object */
1373*10465441SEvalZero     rt_ipc_object_init(&(mb->parent));
1374*10465441SEvalZero 
1375*10465441SEvalZero     /* init mailbox */
1376*10465441SEvalZero     mb->size     = size;
1377*10465441SEvalZero     mb->msg_pool = RT_KERNEL_MALLOC(mb->size * sizeof(rt_ubase_t));
1378*10465441SEvalZero     if (mb->msg_pool == RT_NULL)
1379*10465441SEvalZero     {
1380*10465441SEvalZero         /* delete mailbox object */
1381*10465441SEvalZero         rt_object_delete(&(mb->parent.parent));
1382*10465441SEvalZero 
1383*10465441SEvalZero         return RT_NULL;
1384*10465441SEvalZero     }
1385*10465441SEvalZero     mb->entry      = 0;
1386*10465441SEvalZero     mb->in_offset  = 0;
1387*10465441SEvalZero     mb->out_offset = 0;
1388*10465441SEvalZero 
1389*10465441SEvalZero     /* init an additional list of sender suspend thread */
1390*10465441SEvalZero     rt_list_init(&(mb->suspend_sender_thread));
1391*10465441SEvalZero 
1392*10465441SEvalZero     return mb;
1393*10465441SEvalZero }
1394*10465441SEvalZero RTM_EXPORT(rt_mb_create);
1395*10465441SEvalZero 
1396*10465441SEvalZero /**
1397*10465441SEvalZero  * This function will delete a mailbox object and release the memory
1398*10465441SEvalZero  *
1399*10465441SEvalZero  * @param mb the mailbox object
1400*10465441SEvalZero  *
1401*10465441SEvalZero  * @return the error code
1402*10465441SEvalZero  */
rt_mb_delete(rt_mailbox_t mb)1403*10465441SEvalZero rt_err_t rt_mb_delete(rt_mailbox_t mb)
1404*10465441SEvalZero {
1405*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
1406*10465441SEvalZero 
1407*10465441SEvalZero     /* parameter check */
1408*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1409*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
1410*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent) == RT_FALSE);
1411*10465441SEvalZero 
1412*10465441SEvalZero     /* resume all suspended thread */
1413*10465441SEvalZero     rt_ipc_list_resume_all(&(mb->parent.suspend_thread));
1414*10465441SEvalZero 
1415*10465441SEvalZero     /* also resume all mailbox private suspended thread */
1416*10465441SEvalZero     rt_ipc_list_resume_all(&(mb->suspend_sender_thread));
1417*10465441SEvalZero 
1418*10465441SEvalZero     /* free mailbox pool */
1419*10465441SEvalZero     RT_KERNEL_FREE(mb->msg_pool);
1420*10465441SEvalZero 
1421*10465441SEvalZero     /* delete mailbox object */
1422*10465441SEvalZero     rt_object_delete(&(mb->parent.parent));
1423*10465441SEvalZero 
1424*10465441SEvalZero     return RT_EOK;
1425*10465441SEvalZero }
1426*10465441SEvalZero RTM_EXPORT(rt_mb_delete);
1427*10465441SEvalZero #endif
1428*10465441SEvalZero 
1429*10465441SEvalZero /**
1430*10465441SEvalZero  * This function will send a mail to mailbox object. If the mailbox is full,
1431*10465441SEvalZero  * current thread will be suspended until timeout.
1432*10465441SEvalZero  *
1433*10465441SEvalZero  * @param mb the mailbox object
1434*10465441SEvalZero  * @param value the mail
1435*10465441SEvalZero  * @param timeout the waiting time
1436*10465441SEvalZero  *
1437*10465441SEvalZero  * @return the error code
1438*10465441SEvalZero  */
rt_mb_send_wait(rt_mailbox_t mb,rt_ubase_t value,rt_int32_t timeout)1439*10465441SEvalZero rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
1440*10465441SEvalZero                          rt_ubase_t   value,
1441*10465441SEvalZero                          rt_int32_t   timeout)
1442*10465441SEvalZero {
1443*10465441SEvalZero     struct rt_thread *thread;
1444*10465441SEvalZero     register rt_ubase_t temp;
1445*10465441SEvalZero     rt_uint32_t tick_delta;
1446*10465441SEvalZero 
1447*10465441SEvalZero     /* parameter check */
1448*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1449*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
1450*10465441SEvalZero 
1451*10465441SEvalZero     /* initialize delta tick */
1452*10465441SEvalZero     tick_delta = 0;
1453*10465441SEvalZero     /* get current thread */
1454*10465441SEvalZero     thread = rt_thread_self();
1455*10465441SEvalZero 
1456*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
1457*10465441SEvalZero 
1458*10465441SEvalZero     /* disable interrupt */
1459*10465441SEvalZero     temp = rt_hw_interrupt_disable();
1460*10465441SEvalZero 
1461*10465441SEvalZero     /* for non-blocking call */
1462*10465441SEvalZero     if (mb->entry == mb->size && timeout == 0)
1463*10465441SEvalZero     {
1464*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1465*10465441SEvalZero 
1466*10465441SEvalZero         return -RT_EFULL;
1467*10465441SEvalZero     }
1468*10465441SEvalZero 
1469*10465441SEvalZero     /* mailbox is full */
1470*10465441SEvalZero     while (mb->entry == mb->size)
1471*10465441SEvalZero     {
1472*10465441SEvalZero         /* reset error number in thread */
1473*10465441SEvalZero         thread->error = RT_EOK;
1474*10465441SEvalZero 
1475*10465441SEvalZero         /* no waiting, return timeout */
1476*10465441SEvalZero         if (timeout == 0)
1477*10465441SEvalZero         {
1478*10465441SEvalZero             /* enable interrupt */
1479*10465441SEvalZero             rt_hw_interrupt_enable(temp);
1480*10465441SEvalZero 
1481*10465441SEvalZero             return -RT_EFULL;
1482*10465441SEvalZero         }
1483*10465441SEvalZero 
1484*10465441SEvalZero         RT_DEBUG_IN_THREAD_CONTEXT;
1485*10465441SEvalZero         /* suspend current thread */
1486*10465441SEvalZero         rt_ipc_list_suspend(&(mb->suspend_sender_thread),
1487*10465441SEvalZero                             thread,
1488*10465441SEvalZero                             mb->parent.parent.flag);
1489*10465441SEvalZero 
1490*10465441SEvalZero         /* has waiting time, start thread timer */
1491*10465441SEvalZero         if (timeout > 0)
1492*10465441SEvalZero         {
1493*10465441SEvalZero             /* get the start tick of timer */
1494*10465441SEvalZero             tick_delta = rt_tick_get();
1495*10465441SEvalZero 
1496*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n",
1497*10465441SEvalZero                                         thread->name));
1498*10465441SEvalZero 
1499*10465441SEvalZero             /* reset the timeout of thread timer and start it */
1500*10465441SEvalZero             rt_timer_control(&(thread->thread_timer),
1501*10465441SEvalZero                              RT_TIMER_CTRL_SET_TIME,
1502*10465441SEvalZero                              &timeout);
1503*10465441SEvalZero             rt_timer_start(&(thread->thread_timer));
1504*10465441SEvalZero         }
1505*10465441SEvalZero 
1506*10465441SEvalZero         /* enable interrupt */
1507*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1508*10465441SEvalZero 
1509*10465441SEvalZero         /* re-schedule */
1510*10465441SEvalZero         rt_schedule();
1511*10465441SEvalZero 
1512*10465441SEvalZero         /* resume from suspend state */
1513*10465441SEvalZero         if (thread->error != RT_EOK)
1514*10465441SEvalZero         {
1515*10465441SEvalZero             /* return error */
1516*10465441SEvalZero             return thread->error;
1517*10465441SEvalZero         }
1518*10465441SEvalZero 
1519*10465441SEvalZero         /* disable interrupt */
1520*10465441SEvalZero         temp = rt_hw_interrupt_disable();
1521*10465441SEvalZero 
1522*10465441SEvalZero         /* if it's not waiting forever and then re-calculate timeout tick */
1523*10465441SEvalZero         if (timeout > 0)
1524*10465441SEvalZero         {
1525*10465441SEvalZero             tick_delta = rt_tick_get() - tick_delta;
1526*10465441SEvalZero             timeout -= tick_delta;
1527*10465441SEvalZero             if (timeout < 0)
1528*10465441SEvalZero                 timeout = 0;
1529*10465441SEvalZero         }
1530*10465441SEvalZero     }
1531*10465441SEvalZero 
1532*10465441SEvalZero     /* set ptr */
1533*10465441SEvalZero     mb->msg_pool[mb->in_offset] = value;
1534*10465441SEvalZero     /* increase input offset */
1535*10465441SEvalZero     ++ mb->in_offset;
1536*10465441SEvalZero     if (mb->in_offset >= mb->size)
1537*10465441SEvalZero         mb->in_offset = 0;
1538*10465441SEvalZero     /* increase message entry */
1539*10465441SEvalZero     mb->entry ++;
1540*10465441SEvalZero 
1541*10465441SEvalZero     /* resume suspended thread */
1542*10465441SEvalZero     if (!rt_list_isempty(&mb->parent.suspend_thread))
1543*10465441SEvalZero     {
1544*10465441SEvalZero         rt_ipc_list_resume(&(mb->parent.suspend_thread));
1545*10465441SEvalZero 
1546*10465441SEvalZero         /* enable interrupt */
1547*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1548*10465441SEvalZero 
1549*10465441SEvalZero         rt_schedule();
1550*10465441SEvalZero 
1551*10465441SEvalZero         return RT_EOK;
1552*10465441SEvalZero     }
1553*10465441SEvalZero 
1554*10465441SEvalZero     /* enable interrupt */
1555*10465441SEvalZero     rt_hw_interrupt_enable(temp);
1556*10465441SEvalZero 
1557*10465441SEvalZero     return RT_EOK;
1558*10465441SEvalZero }
1559*10465441SEvalZero RTM_EXPORT(rt_mb_send_wait);
1560*10465441SEvalZero 
1561*10465441SEvalZero /**
1562*10465441SEvalZero  * This function will send a mail to mailbox object, if there are threads
1563*10465441SEvalZero  * suspended on mailbox object, it will be waked up. This function will return
1564*10465441SEvalZero  * immediately, if you want blocking send, use rt_mb_send_wait instead.
1565*10465441SEvalZero  *
1566*10465441SEvalZero  * @param mb the mailbox object
1567*10465441SEvalZero  * @param value the mail
1568*10465441SEvalZero  *
1569*10465441SEvalZero  * @return the error code
1570*10465441SEvalZero  */
rt_mb_send(rt_mailbox_t mb,rt_ubase_t value)1571*10465441SEvalZero rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
1572*10465441SEvalZero {
1573*10465441SEvalZero     return rt_mb_send_wait(mb, value, 0);
1574*10465441SEvalZero }
1575*10465441SEvalZero RTM_EXPORT(rt_mb_send);
1576*10465441SEvalZero 
1577*10465441SEvalZero /**
1578*10465441SEvalZero  * This function will receive a mail from mailbox object, if there is no mail
1579*10465441SEvalZero  * in mailbox object, the thread shall wait for a specified time.
1580*10465441SEvalZero  *
1581*10465441SEvalZero  * @param mb the mailbox object
1582*10465441SEvalZero  * @param value the received mail will be saved in
1583*10465441SEvalZero  * @param timeout the waiting time
1584*10465441SEvalZero  *
1585*10465441SEvalZero  * @return the error code
1586*10465441SEvalZero  */
rt_mb_recv(rt_mailbox_t mb,rt_ubase_t * value,rt_int32_t timeout)1587*10465441SEvalZero rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
1588*10465441SEvalZero {
1589*10465441SEvalZero     struct rt_thread *thread;
1590*10465441SEvalZero     register rt_ubase_t temp;
1591*10465441SEvalZero     rt_uint32_t tick_delta;
1592*10465441SEvalZero 
1593*10465441SEvalZero     /* parameter check */
1594*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1595*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
1596*10465441SEvalZero 
1597*10465441SEvalZero     /* initialize delta tick */
1598*10465441SEvalZero     tick_delta = 0;
1599*10465441SEvalZero     /* get current thread */
1600*10465441SEvalZero     thread = rt_thread_self();
1601*10465441SEvalZero 
1602*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mb->parent.parent)));
1603*10465441SEvalZero 
1604*10465441SEvalZero     /* disable interrupt */
1605*10465441SEvalZero     temp = rt_hw_interrupt_disable();
1606*10465441SEvalZero 
1607*10465441SEvalZero     /* for non-blocking call */
1608*10465441SEvalZero     if (mb->entry == 0 && timeout == 0)
1609*10465441SEvalZero     {
1610*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1611*10465441SEvalZero 
1612*10465441SEvalZero         return -RT_ETIMEOUT;
1613*10465441SEvalZero     }
1614*10465441SEvalZero 
1615*10465441SEvalZero     /* mailbox is empty */
1616*10465441SEvalZero     while (mb->entry == 0)
1617*10465441SEvalZero     {
1618*10465441SEvalZero         /* reset error number in thread */
1619*10465441SEvalZero         thread->error = RT_EOK;
1620*10465441SEvalZero 
1621*10465441SEvalZero         /* no waiting, return timeout */
1622*10465441SEvalZero         if (timeout == 0)
1623*10465441SEvalZero         {
1624*10465441SEvalZero             /* enable interrupt */
1625*10465441SEvalZero             rt_hw_interrupt_enable(temp);
1626*10465441SEvalZero 
1627*10465441SEvalZero             thread->error = -RT_ETIMEOUT;
1628*10465441SEvalZero 
1629*10465441SEvalZero             return -RT_ETIMEOUT;
1630*10465441SEvalZero         }
1631*10465441SEvalZero 
1632*10465441SEvalZero         RT_DEBUG_IN_THREAD_CONTEXT;
1633*10465441SEvalZero         /* suspend current thread */
1634*10465441SEvalZero         rt_ipc_list_suspend(&(mb->parent.suspend_thread),
1635*10465441SEvalZero                             thread,
1636*10465441SEvalZero                             mb->parent.parent.flag);
1637*10465441SEvalZero 
1638*10465441SEvalZero         /* has waiting time, start thread timer */
1639*10465441SEvalZero         if (timeout > 0)
1640*10465441SEvalZero         {
1641*10465441SEvalZero             /* get the start tick of timer */
1642*10465441SEvalZero             tick_delta = rt_tick_get();
1643*10465441SEvalZero 
1644*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_recv: start timer of thread:%s\n",
1645*10465441SEvalZero                                         thread->name));
1646*10465441SEvalZero 
1647*10465441SEvalZero             /* reset the timeout of thread timer and start it */
1648*10465441SEvalZero             rt_timer_control(&(thread->thread_timer),
1649*10465441SEvalZero                              RT_TIMER_CTRL_SET_TIME,
1650*10465441SEvalZero                              &timeout);
1651*10465441SEvalZero             rt_timer_start(&(thread->thread_timer));
1652*10465441SEvalZero         }
1653*10465441SEvalZero 
1654*10465441SEvalZero         /* enable interrupt */
1655*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1656*10465441SEvalZero 
1657*10465441SEvalZero         /* re-schedule */
1658*10465441SEvalZero         rt_schedule();
1659*10465441SEvalZero 
1660*10465441SEvalZero         /* resume from suspend state */
1661*10465441SEvalZero         if (thread->error != RT_EOK)
1662*10465441SEvalZero         {
1663*10465441SEvalZero             /* return error */
1664*10465441SEvalZero             return thread->error;
1665*10465441SEvalZero         }
1666*10465441SEvalZero 
1667*10465441SEvalZero         /* disable interrupt */
1668*10465441SEvalZero         temp = rt_hw_interrupt_disable();
1669*10465441SEvalZero 
1670*10465441SEvalZero         /* if it's not waiting forever and then re-calculate timeout tick */
1671*10465441SEvalZero         if (timeout > 0)
1672*10465441SEvalZero         {
1673*10465441SEvalZero             tick_delta = rt_tick_get() - tick_delta;
1674*10465441SEvalZero             timeout -= tick_delta;
1675*10465441SEvalZero             if (timeout < 0)
1676*10465441SEvalZero                 timeout = 0;
1677*10465441SEvalZero         }
1678*10465441SEvalZero     }
1679*10465441SEvalZero 
1680*10465441SEvalZero     /* fill ptr */
1681*10465441SEvalZero     *value = mb->msg_pool[mb->out_offset];
1682*10465441SEvalZero 
1683*10465441SEvalZero     /* increase output offset */
1684*10465441SEvalZero     ++ mb->out_offset;
1685*10465441SEvalZero     if (mb->out_offset >= mb->size)
1686*10465441SEvalZero         mb->out_offset = 0;
1687*10465441SEvalZero     /* decrease message entry */
1688*10465441SEvalZero     mb->entry --;
1689*10465441SEvalZero 
1690*10465441SEvalZero     /* resume suspended thread */
1691*10465441SEvalZero     if (!rt_list_isempty(&(mb->suspend_sender_thread)))
1692*10465441SEvalZero     {
1693*10465441SEvalZero         rt_ipc_list_resume(&(mb->suspend_sender_thread));
1694*10465441SEvalZero 
1695*10465441SEvalZero         /* enable interrupt */
1696*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1697*10465441SEvalZero 
1698*10465441SEvalZero         RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));
1699*10465441SEvalZero 
1700*10465441SEvalZero         rt_schedule();
1701*10465441SEvalZero 
1702*10465441SEvalZero         return RT_EOK;
1703*10465441SEvalZero     }
1704*10465441SEvalZero 
1705*10465441SEvalZero     /* enable interrupt */
1706*10465441SEvalZero     rt_hw_interrupt_enable(temp);
1707*10465441SEvalZero 
1708*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));
1709*10465441SEvalZero 
1710*10465441SEvalZero     return RT_EOK;
1711*10465441SEvalZero }
1712*10465441SEvalZero RTM_EXPORT(rt_mb_recv);
1713*10465441SEvalZero 
1714*10465441SEvalZero /**
1715*10465441SEvalZero  * This function can get or set some extra attributions of a mailbox object.
1716*10465441SEvalZero  *
1717*10465441SEvalZero  * @param mb the mailbox object
1718*10465441SEvalZero  * @param cmd the execution command
1719*10465441SEvalZero  * @param arg the execution argument
1720*10465441SEvalZero  *
1721*10465441SEvalZero  * @return the error code
1722*10465441SEvalZero  */
rt_mb_control(rt_mailbox_t mb,int cmd,void * arg)1723*10465441SEvalZero rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg)
1724*10465441SEvalZero {
1725*10465441SEvalZero     rt_ubase_t level;
1726*10465441SEvalZero 
1727*10465441SEvalZero     /* parameter check */
1728*10465441SEvalZero     RT_ASSERT(mb != RT_NULL);
1729*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
1730*10465441SEvalZero 
1731*10465441SEvalZero     if (cmd == RT_IPC_CMD_RESET)
1732*10465441SEvalZero     {
1733*10465441SEvalZero         /* disable interrupt */
1734*10465441SEvalZero         level = rt_hw_interrupt_disable();
1735*10465441SEvalZero 
1736*10465441SEvalZero         /* resume all waiting thread */
1737*10465441SEvalZero         rt_ipc_list_resume_all(&(mb->parent.suspend_thread));
1738*10465441SEvalZero         /* also resume all mailbox private suspended thread */
1739*10465441SEvalZero         rt_ipc_list_resume_all(&(mb->suspend_sender_thread));
1740*10465441SEvalZero 
1741*10465441SEvalZero         /* re-init mailbox */
1742*10465441SEvalZero         mb->entry      = 0;
1743*10465441SEvalZero         mb->in_offset  = 0;
1744*10465441SEvalZero         mb->out_offset = 0;
1745*10465441SEvalZero 
1746*10465441SEvalZero         /* enable interrupt */
1747*10465441SEvalZero         rt_hw_interrupt_enable(level);
1748*10465441SEvalZero 
1749*10465441SEvalZero         rt_schedule();
1750*10465441SEvalZero 
1751*10465441SEvalZero         return RT_EOK;
1752*10465441SEvalZero     }
1753*10465441SEvalZero 
1754*10465441SEvalZero     return -RT_ERROR;
1755*10465441SEvalZero }
1756*10465441SEvalZero RTM_EXPORT(rt_mb_control);
1757*10465441SEvalZero #endif /* end of RT_USING_MAILBOX */
1758*10465441SEvalZero 
1759*10465441SEvalZero #ifdef RT_USING_MESSAGEQUEUE
1760*10465441SEvalZero struct rt_mq_message
1761*10465441SEvalZero {
1762*10465441SEvalZero     struct rt_mq_message *next;
1763*10465441SEvalZero };
1764*10465441SEvalZero 
1765*10465441SEvalZero /**
1766*10465441SEvalZero  * This function will initialize a message queue and put it under control of
1767*10465441SEvalZero  * resource management.
1768*10465441SEvalZero  *
1769*10465441SEvalZero  * @param mq the message object
1770*10465441SEvalZero  * @param name the name of message queue
1771*10465441SEvalZero  * @param msgpool the beginning address of buffer to save messages
1772*10465441SEvalZero  * @param msg_size the maximum size of message
1773*10465441SEvalZero  * @param pool_size the size of buffer to save messages
1774*10465441SEvalZero  * @param flag the flag of message queue
1775*10465441SEvalZero  *
1776*10465441SEvalZero  * @return the operation status, RT_EOK on successful
1777*10465441SEvalZero  */
rt_mq_init(rt_mq_t mq,const char * name,void * msgpool,rt_size_t msg_size,rt_size_t pool_size,rt_uint8_t flag)1778*10465441SEvalZero rt_err_t rt_mq_init(rt_mq_t     mq,
1779*10465441SEvalZero                     const char *name,
1780*10465441SEvalZero                     void       *msgpool,
1781*10465441SEvalZero                     rt_size_t   msg_size,
1782*10465441SEvalZero                     rt_size_t   pool_size,
1783*10465441SEvalZero                     rt_uint8_t  flag)
1784*10465441SEvalZero {
1785*10465441SEvalZero     struct rt_mq_message *head;
1786*10465441SEvalZero     register rt_base_t temp;
1787*10465441SEvalZero 
1788*10465441SEvalZero     /* parameter check */
1789*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
1790*10465441SEvalZero 
1791*10465441SEvalZero     /* init object */
1792*10465441SEvalZero     rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);
1793*10465441SEvalZero 
1794*10465441SEvalZero     /* set parent flag */
1795*10465441SEvalZero     mq->parent.parent.flag = flag;
1796*10465441SEvalZero 
1797*10465441SEvalZero     /* init ipc object */
1798*10465441SEvalZero     rt_ipc_object_init(&(mq->parent));
1799*10465441SEvalZero 
1800*10465441SEvalZero     /* set messasge pool */
1801*10465441SEvalZero     mq->msg_pool = msgpool;
1802*10465441SEvalZero 
1803*10465441SEvalZero     /* get correct message size */
1804*10465441SEvalZero     mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
1805*10465441SEvalZero     mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message));
1806*10465441SEvalZero 
1807*10465441SEvalZero     /* init message list */
1808*10465441SEvalZero     mq->msg_queue_head = RT_NULL;
1809*10465441SEvalZero     mq->msg_queue_tail = RT_NULL;
1810*10465441SEvalZero 
1811*10465441SEvalZero     /* init message empty list */
1812*10465441SEvalZero     mq->msg_queue_free = RT_NULL;
1813*10465441SEvalZero     for (temp = 0; temp < mq->max_msgs; temp ++)
1814*10465441SEvalZero     {
1815*10465441SEvalZero         head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
1816*10465441SEvalZero                                         temp * (mq->msg_size + sizeof(struct rt_mq_message)));
1817*10465441SEvalZero         head->next = mq->msg_queue_free;
1818*10465441SEvalZero         mq->msg_queue_free = head;
1819*10465441SEvalZero     }
1820*10465441SEvalZero 
1821*10465441SEvalZero     /* the initial entry is zero */
1822*10465441SEvalZero     mq->entry = 0;
1823*10465441SEvalZero 
1824*10465441SEvalZero     return RT_EOK;
1825*10465441SEvalZero }
1826*10465441SEvalZero RTM_EXPORT(rt_mq_init);
1827*10465441SEvalZero 
1828*10465441SEvalZero /**
1829*10465441SEvalZero  * This function will detach a message queue object from resource management
1830*10465441SEvalZero  *
1831*10465441SEvalZero  * @param mq the message queue object
1832*10465441SEvalZero  *
1833*10465441SEvalZero  * @return the operation status, RT_EOK on successful
1834*10465441SEvalZero  */
rt_mq_detach(rt_mq_t mq)1835*10465441SEvalZero rt_err_t rt_mq_detach(rt_mq_t mq)
1836*10465441SEvalZero {
1837*10465441SEvalZero     /* parameter check */
1838*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
1839*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
1840*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent));
1841*10465441SEvalZero 
1842*10465441SEvalZero     /* resume all suspended thread */
1843*10465441SEvalZero     rt_ipc_list_resume_all(&mq->parent.suspend_thread);
1844*10465441SEvalZero 
1845*10465441SEvalZero     /* detach message queue object */
1846*10465441SEvalZero     rt_object_detach(&(mq->parent.parent));
1847*10465441SEvalZero 
1848*10465441SEvalZero     return RT_EOK;
1849*10465441SEvalZero }
1850*10465441SEvalZero RTM_EXPORT(rt_mq_detach);
1851*10465441SEvalZero 
1852*10465441SEvalZero #ifdef RT_USING_HEAP
1853*10465441SEvalZero /**
1854*10465441SEvalZero  * This function will create a message queue object from system resource
1855*10465441SEvalZero  *
1856*10465441SEvalZero  * @param name the name of message queue
1857*10465441SEvalZero  * @param msg_size the size of message
1858*10465441SEvalZero  * @param max_msgs the maximum number of message in queue
1859*10465441SEvalZero  * @param flag the flag of message queue
1860*10465441SEvalZero  *
1861*10465441SEvalZero  * @return the created message queue, RT_NULL on error happen
1862*10465441SEvalZero  */
rt_mq_create(const char * name,rt_size_t msg_size,rt_size_t max_msgs,rt_uint8_t flag)1863*10465441SEvalZero rt_mq_t rt_mq_create(const char *name,
1864*10465441SEvalZero                      rt_size_t   msg_size,
1865*10465441SEvalZero                      rt_size_t   max_msgs,
1866*10465441SEvalZero                      rt_uint8_t  flag)
1867*10465441SEvalZero {
1868*10465441SEvalZero     struct rt_messagequeue *mq;
1869*10465441SEvalZero     struct rt_mq_message *head;
1870*10465441SEvalZero     register rt_base_t temp;
1871*10465441SEvalZero 
1872*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
1873*10465441SEvalZero 
1874*10465441SEvalZero     /* allocate object */
1875*10465441SEvalZero     mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name);
1876*10465441SEvalZero     if (mq == RT_NULL)
1877*10465441SEvalZero         return mq;
1878*10465441SEvalZero 
1879*10465441SEvalZero     /* set parent */
1880*10465441SEvalZero     mq->parent.parent.flag = flag;
1881*10465441SEvalZero 
1882*10465441SEvalZero     /* init ipc object */
1883*10465441SEvalZero     rt_ipc_object_init(&(mq->parent));
1884*10465441SEvalZero 
1885*10465441SEvalZero     /* init message queue */
1886*10465441SEvalZero 
1887*10465441SEvalZero     /* get correct message size */
1888*10465441SEvalZero     mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
1889*10465441SEvalZero     mq->max_msgs = max_msgs;
1890*10465441SEvalZero 
1891*10465441SEvalZero     /* allocate message pool */
1892*10465441SEvalZero     mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs);
1893*10465441SEvalZero     if (mq->msg_pool == RT_NULL)
1894*10465441SEvalZero     {
1895*10465441SEvalZero         rt_mq_delete(mq);
1896*10465441SEvalZero 
1897*10465441SEvalZero         return RT_NULL;
1898*10465441SEvalZero     }
1899*10465441SEvalZero 
1900*10465441SEvalZero     /* init message list */
1901*10465441SEvalZero     mq->msg_queue_head = RT_NULL;
1902*10465441SEvalZero     mq->msg_queue_tail = RT_NULL;
1903*10465441SEvalZero 
1904*10465441SEvalZero     /* init message empty list */
1905*10465441SEvalZero     mq->msg_queue_free = RT_NULL;
1906*10465441SEvalZero     for (temp = 0; temp < mq->max_msgs; temp ++)
1907*10465441SEvalZero     {
1908*10465441SEvalZero         head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
1909*10465441SEvalZero                                         temp * (mq->msg_size + sizeof(struct rt_mq_message)));
1910*10465441SEvalZero         head->next = mq->msg_queue_free;
1911*10465441SEvalZero         mq->msg_queue_free = head;
1912*10465441SEvalZero     }
1913*10465441SEvalZero 
1914*10465441SEvalZero     /* the initial entry is zero */
1915*10465441SEvalZero     mq->entry = 0;
1916*10465441SEvalZero 
1917*10465441SEvalZero     return mq;
1918*10465441SEvalZero }
1919*10465441SEvalZero RTM_EXPORT(rt_mq_create);
1920*10465441SEvalZero 
1921*10465441SEvalZero /**
1922*10465441SEvalZero  * This function will delete a message queue object and release the memory
1923*10465441SEvalZero  *
1924*10465441SEvalZero  * @param mq the message queue object
1925*10465441SEvalZero  *
1926*10465441SEvalZero  * @return the error code
1927*10465441SEvalZero  */
rt_mq_delete(rt_mq_t mq)1928*10465441SEvalZero rt_err_t rt_mq_delete(rt_mq_t mq)
1929*10465441SEvalZero {
1930*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
1931*10465441SEvalZero 
1932*10465441SEvalZero     /* parameter check */
1933*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
1934*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
1935*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent) == RT_FALSE);
1936*10465441SEvalZero 
1937*10465441SEvalZero     /* resume all suspended thread */
1938*10465441SEvalZero     rt_ipc_list_resume_all(&(mq->parent.suspend_thread));
1939*10465441SEvalZero 
1940*10465441SEvalZero     /* free message queue pool */
1941*10465441SEvalZero     RT_KERNEL_FREE(mq->msg_pool);
1942*10465441SEvalZero 
1943*10465441SEvalZero     /* delete message queue object */
1944*10465441SEvalZero     rt_object_delete(&(mq->parent.parent));
1945*10465441SEvalZero 
1946*10465441SEvalZero     return RT_EOK;
1947*10465441SEvalZero }
1948*10465441SEvalZero RTM_EXPORT(rt_mq_delete);
1949*10465441SEvalZero #endif
1950*10465441SEvalZero 
1951*10465441SEvalZero /**
1952*10465441SEvalZero  * This function will send a message to message queue object, if there are
1953*10465441SEvalZero  * threads suspended on message queue object, it will be waked up.
1954*10465441SEvalZero  *
1955*10465441SEvalZero  * @param mq the message queue object
1956*10465441SEvalZero  * @param buffer the message
1957*10465441SEvalZero  * @param size the size of buffer
1958*10465441SEvalZero  *
1959*10465441SEvalZero  * @return the error code
1960*10465441SEvalZero  */
rt_mq_send(rt_mq_t mq,void * buffer,rt_size_t size)1961*10465441SEvalZero rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
1962*10465441SEvalZero {
1963*10465441SEvalZero     register rt_ubase_t temp;
1964*10465441SEvalZero     struct rt_mq_message *msg;
1965*10465441SEvalZero 
1966*10465441SEvalZero     /* parameter check */
1967*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
1968*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
1969*10465441SEvalZero     RT_ASSERT(buffer != RT_NULL);
1970*10465441SEvalZero     RT_ASSERT(size != 0);
1971*10465441SEvalZero 
1972*10465441SEvalZero     /* greater than one message size */
1973*10465441SEvalZero     if (size > mq->msg_size)
1974*10465441SEvalZero         return -RT_ERROR;
1975*10465441SEvalZero 
1976*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));
1977*10465441SEvalZero 
1978*10465441SEvalZero     /* disable interrupt */
1979*10465441SEvalZero     temp = rt_hw_interrupt_disable();
1980*10465441SEvalZero 
1981*10465441SEvalZero     /* get a free list, there must be an empty item */
1982*10465441SEvalZero     msg = (struct rt_mq_message *)mq->msg_queue_free;
1983*10465441SEvalZero     /* message queue is full */
1984*10465441SEvalZero     if (msg == RT_NULL)
1985*10465441SEvalZero     {
1986*10465441SEvalZero         /* enable interrupt */
1987*10465441SEvalZero         rt_hw_interrupt_enable(temp);
1988*10465441SEvalZero 
1989*10465441SEvalZero         return -RT_EFULL;
1990*10465441SEvalZero     }
1991*10465441SEvalZero     /* move free list pointer */
1992*10465441SEvalZero     mq->msg_queue_free = msg->next;
1993*10465441SEvalZero 
1994*10465441SEvalZero     /* enable interrupt */
1995*10465441SEvalZero     rt_hw_interrupt_enable(temp);
1996*10465441SEvalZero 
1997*10465441SEvalZero     /* the msg is the new tailer of list, the next shall be NULL */
1998*10465441SEvalZero     msg->next = RT_NULL;
1999*10465441SEvalZero     /* copy buffer */
2000*10465441SEvalZero     rt_memcpy(msg + 1, buffer, size);
2001*10465441SEvalZero 
2002*10465441SEvalZero     /* disable interrupt */
2003*10465441SEvalZero     temp = rt_hw_interrupt_disable();
2004*10465441SEvalZero     /* link msg to message queue */
2005*10465441SEvalZero     if (mq->msg_queue_tail != RT_NULL)
2006*10465441SEvalZero     {
2007*10465441SEvalZero         /* if the tail exists, */
2008*10465441SEvalZero         ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg;
2009*10465441SEvalZero     }
2010*10465441SEvalZero 
2011*10465441SEvalZero     /* set new tail */
2012*10465441SEvalZero     mq->msg_queue_tail = msg;
2013*10465441SEvalZero     /* if the head is empty, set head */
2014*10465441SEvalZero     if (mq->msg_queue_head == RT_NULL)
2015*10465441SEvalZero         mq->msg_queue_head = msg;
2016*10465441SEvalZero 
2017*10465441SEvalZero     /* increase message entry */
2018*10465441SEvalZero     mq->entry ++;
2019*10465441SEvalZero 
2020*10465441SEvalZero     /* resume suspended thread */
2021*10465441SEvalZero     if (!rt_list_isempty(&mq->parent.suspend_thread))
2022*10465441SEvalZero     {
2023*10465441SEvalZero         rt_ipc_list_resume(&(mq->parent.suspend_thread));
2024*10465441SEvalZero 
2025*10465441SEvalZero         /* enable interrupt */
2026*10465441SEvalZero         rt_hw_interrupt_enable(temp);
2027*10465441SEvalZero 
2028*10465441SEvalZero         rt_schedule();
2029*10465441SEvalZero 
2030*10465441SEvalZero         return RT_EOK;
2031*10465441SEvalZero     }
2032*10465441SEvalZero 
2033*10465441SEvalZero     /* enable interrupt */
2034*10465441SEvalZero     rt_hw_interrupt_enable(temp);
2035*10465441SEvalZero 
2036*10465441SEvalZero     return RT_EOK;
2037*10465441SEvalZero }
2038*10465441SEvalZero RTM_EXPORT(rt_mq_send);
2039*10465441SEvalZero 
2040*10465441SEvalZero /**
2041*10465441SEvalZero  * This function will send an urgent message to message queue object, which
2042*10465441SEvalZero  * means the message will be inserted to the head of message queue. If there
2043*10465441SEvalZero  * are threads suspended on message queue object, it will be waked up.
2044*10465441SEvalZero  *
2045*10465441SEvalZero  * @param mq the message queue object
2046*10465441SEvalZero  * @param buffer the message
2047*10465441SEvalZero  * @param size the size of buffer
2048*10465441SEvalZero  *
2049*10465441SEvalZero  * @return the error code
2050*10465441SEvalZero  */
rt_mq_urgent(rt_mq_t mq,void * buffer,rt_size_t size)2051*10465441SEvalZero rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size)
2052*10465441SEvalZero {
2053*10465441SEvalZero     register rt_ubase_t temp;
2054*10465441SEvalZero     struct rt_mq_message *msg;
2055*10465441SEvalZero 
2056*10465441SEvalZero     /* parameter check */
2057*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
2058*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
2059*10465441SEvalZero     RT_ASSERT(buffer != RT_NULL);
2060*10465441SEvalZero     RT_ASSERT(size != 0);
2061*10465441SEvalZero 
2062*10465441SEvalZero     /* greater than one message size */
2063*10465441SEvalZero     if (size > mq->msg_size)
2064*10465441SEvalZero         return -RT_ERROR;
2065*10465441SEvalZero 
2066*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));
2067*10465441SEvalZero 
2068*10465441SEvalZero     /* disable interrupt */
2069*10465441SEvalZero     temp = rt_hw_interrupt_disable();
2070*10465441SEvalZero 
2071*10465441SEvalZero     /* get a free list, there must be an empty item */
2072*10465441SEvalZero     msg = (struct rt_mq_message *)mq->msg_queue_free;
2073*10465441SEvalZero     /* message queue is full */
2074*10465441SEvalZero     if (msg == RT_NULL)
2075*10465441SEvalZero     {
2076*10465441SEvalZero         /* enable interrupt */
2077*10465441SEvalZero         rt_hw_interrupt_enable(temp);
2078*10465441SEvalZero 
2079*10465441SEvalZero         return -RT_EFULL;
2080*10465441SEvalZero     }
2081*10465441SEvalZero     /* move free list pointer */
2082*10465441SEvalZero     mq->msg_queue_free = msg->next;
2083*10465441SEvalZero 
2084*10465441SEvalZero     /* enable interrupt */
2085*10465441SEvalZero     rt_hw_interrupt_enable(temp);
2086*10465441SEvalZero 
2087*10465441SEvalZero     /* copy buffer */
2088*10465441SEvalZero     rt_memcpy(msg + 1, buffer, size);
2089*10465441SEvalZero 
2090*10465441SEvalZero     /* disable interrupt */
2091*10465441SEvalZero     temp = rt_hw_interrupt_disable();
2092*10465441SEvalZero 
2093*10465441SEvalZero     /* link msg to the beginning of message queue */
2094*10465441SEvalZero     msg->next = mq->msg_queue_head;
2095*10465441SEvalZero     mq->msg_queue_head = msg;
2096*10465441SEvalZero 
2097*10465441SEvalZero     /* if there is no tail */
2098*10465441SEvalZero     if (mq->msg_queue_tail == RT_NULL)
2099*10465441SEvalZero         mq->msg_queue_tail = msg;
2100*10465441SEvalZero 
2101*10465441SEvalZero     /* increase message entry */
2102*10465441SEvalZero     mq->entry ++;
2103*10465441SEvalZero 
2104*10465441SEvalZero     /* resume suspended thread */
2105*10465441SEvalZero     if (!rt_list_isempty(&mq->parent.suspend_thread))
2106*10465441SEvalZero     {
2107*10465441SEvalZero         rt_ipc_list_resume(&(mq->parent.suspend_thread));
2108*10465441SEvalZero 
2109*10465441SEvalZero         /* enable interrupt */
2110*10465441SEvalZero         rt_hw_interrupt_enable(temp);
2111*10465441SEvalZero 
2112*10465441SEvalZero         rt_schedule();
2113*10465441SEvalZero 
2114*10465441SEvalZero         return RT_EOK;
2115*10465441SEvalZero     }
2116*10465441SEvalZero 
2117*10465441SEvalZero     /* enable interrupt */
2118*10465441SEvalZero     rt_hw_interrupt_enable(temp);
2119*10465441SEvalZero 
2120*10465441SEvalZero     return RT_EOK;
2121*10465441SEvalZero }
2122*10465441SEvalZero RTM_EXPORT(rt_mq_urgent);
2123*10465441SEvalZero 
2124*10465441SEvalZero /**
2125*10465441SEvalZero  * This function will receive a message from message queue object, if there is
2126*10465441SEvalZero  * no message in message queue object, the thread shall wait for a specified
2127*10465441SEvalZero  * time.
2128*10465441SEvalZero  *
2129*10465441SEvalZero  * @param mq the message queue object
2130*10465441SEvalZero  * @param buffer the received message will be saved in
2131*10465441SEvalZero  * @param size the size of buffer
2132*10465441SEvalZero  * @param timeout the waiting time
2133*10465441SEvalZero  *
2134*10465441SEvalZero  * @return the error code
2135*10465441SEvalZero  */
rt_mq_recv(rt_mq_t mq,void * buffer,rt_size_t size,rt_int32_t timeout)2136*10465441SEvalZero rt_err_t rt_mq_recv(rt_mq_t    mq,
2137*10465441SEvalZero                     void      *buffer,
2138*10465441SEvalZero                     rt_size_t  size,
2139*10465441SEvalZero                     rt_int32_t timeout)
2140*10465441SEvalZero {
2141*10465441SEvalZero     struct rt_thread *thread;
2142*10465441SEvalZero     register rt_ubase_t temp;
2143*10465441SEvalZero     struct rt_mq_message *msg;
2144*10465441SEvalZero     rt_uint32_t tick_delta;
2145*10465441SEvalZero 
2146*10465441SEvalZero     /* parameter check */
2147*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
2148*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
2149*10465441SEvalZero     RT_ASSERT(buffer != RT_NULL);
2150*10465441SEvalZero     RT_ASSERT(size != 0);
2151*10465441SEvalZero 
2152*10465441SEvalZero     /* initialize delta tick */
2153*10465441SEvalZero     tick_delta = 0;
2154*10465441SEvalZero     /* get current thread */
2155*10465441SEvalZero     thread = rt_thread_self();
2156*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mq->parent.parent)));
2157*10465441SEvalZero 
2158*10465441SEvalZero     /* disable interrupt */
2159*10465441SEvalZero     temp = rt_hw_interrupt_disable();
2160*10465441SEvalZero 
2161*10465441SEvalZero     /* for non-blocking call */
2162*10465441SEvalZero     if (mq->entry == 0 && timeout == 0)
2163*10465441SEvalZero     {
2164*10465441SEvalZero         rt_hw_interrupt_enable(temp);
2165*10465441SEvalZero 
2166*10465441SEvalZero         return -RT_ETIMEOUT;
2167*10465441SEvalZero     }
2168*10465441SEvalZero 
2169*10465441SEvalZero     /* message queue is empty */
2170*10465441SEvalZero     while (mq->entry == 0)
2171*10465441SEvalZero     {
2172*10465441SEvalZero         RT_DEBUG_IN_THREAD_CONTEXT;
2173*10465441SEvalZero 
2174*10465441SEvalZero         /* reset error number in thread */
2175*10465441SEvalZero         thread->error = RT_EOK;
2176*10465441SEvalZero 
2177*10465441SEvalZero         /* no waiting, return timeout */
2178*10465441SEvalZero         if (timeout == 0)
2179*10465441SEvalZero         {
2180*10465441SEvalZero             /* enable interrupt */
2181*10465441SEvalZero             rt_hw_interrupt_enable(temp);
2182*10465441SEvalZero 
2183*10465441SEvalZero             thread->error = -RT_ETIMEOUT;
2184*10465441SEvalZero 
2185*10465441SEvalZero             return -RT_ETIMEOUT;
2186*10465441SEvalZero         }
2187*10465441SEvalZero 
2188*10465441SEvalZero         /* suspend current thread */
2189*10465441SEvalZero         rt_ipc_list_suspend(&(mq->parent.suspend_thread),
2190*10465441SEvalZero                             thread,
2191*10465441SEvalZero                             mq->parent.parent.flag);
2192*10465441SEvalZero 
2193*10465441SEvalZero         /* has waiting time, start thread timer */
2194*10465441SEvalZero         if (timeout > 0)
2195*10465441SEvalZero         {
2196*10465441SEvalZero             /* get the start tick of timer */
2197*10465441SEvalZero             tick_delta = rt_tick_get();
2198*10465441SEvalZero 
2199*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
2200*10465441SEvalZero                                         thread->name));
2201*10465441SEvalZero 
2202*10465441SEvalZero             /* reset the timeout of thread timer and start it */
2203*10465441SEvalZero             rt_timer_control(&(thread->thread_timer),
2204*10465441SEvalZero                              RT_TIMER_CTRL_SET_TIME,
2205*10465441SEvalZero                              &timeout);
2206*10465441SEvalZero             rt_timer_start(&(thread->thread_timer));
2207*10465441SEvalZero         }
2208*10465441SEvalZero 
2209*10465441SEvalZero         /* enable interrupt */
2210*10465441SEvalZero         rt_hw_interrupt_enable(temp);
2211*10465441SEvalZero 
2212*10465441SEvalZero         /* re-schedule */
2213*10465441SEvalZero         rt_schedule();
2214*10465441SEvalZero 
2215*10465441SEvalZero         /* recv message */
2216*10465441SEvalZero         if (thread->error != RT_EOK)
2217*10465441SEvalZero         {
2218*10465441SEvalZero             /* return error */
2219*10465441SEvalZero             return thread->error;
2220*10465441SEvalZero         }
2221*10465441SEvalZero 
2222*10465441SEvalZero         /* disable interrupt */
2223*10465441SEvalZero         temp = rt_hw_interrupt_disable();
2224*10465441SEvalZero 
2225*10465441SEvalZero         /* if it's not waiting forever and then re-calculate timeout tick */
2226*10465441SEvalZero         if (timeout > 0)
2227*10465441SEvalZero         {
2228*10465441SEvalZero             tick_delta = rt_tick_get() - tick_delta;
2229*10465441SEvalZero             timeout -= tick_delta;
2230*10465441SEvalZero             if (timeout < 0)
2231*10465441SEvalZero                 timeout = 0;
2232*10465441SEvalZero         }
2233*10465441SEvalZero     }
2234*10465441SEvalZero 
2235*10465441SEvalZero     /* get message from queue */
2236*10465441SEvalZero     msg = (struct rt_mq_message *)mq->msg_queue_head;
2237*10465441SEvalZero 
2238*10465441SEvalZero     /* move message queue head */
2239*10465441SEvalZero     mq->msg_queue_head = msg->next;
2240*10465441SEvalZero     /* reach queue tail, set to NULL */
2241*10465441SEvalZero     if (mq->msg_queue_tail == msg)
2242*10465441SEvalZero         mq->msg_queue_tail = RT_NULL;
2243*10465441SEvalZero 
2244*10465441SEvalZero     /* decrease message entry */
2245*10465441SEvalZero     mq->entry --;
2246*10465441SEvalZero 
2247*10465441SEvalZero     /* enable interrupt */
2248*10465441SEvalZero     rt_hw_interrupt_enable(temp);
2249*10465441SEvalZero 
2250*10465441SEvalZero     /* copy message */
2251*10465441SEvalZero     rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size);
2252*10465441SEvalZero 
2253*10465441SEvalZero     /* disable interrupt */
2254*10465441SEvalZero     temp = rt_hw_interrupt_disable();
2255*10465441SEvalZero     /* put message to free list */
2256*10465441SEvalZero     msg->next = (struct rt_mq_message *)mq->msg_queue_free;
2257*10465441SEvalZero     mq->msg_queue_free = msg;
2258*10465441SEvalZero     /* enable interrupt */
2259*10465441SEvalZero     rt_hw_interrupt_enable(temp);
2260*10465441SEvalZero 
2261*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));
2262*10465441SEvalZero 
2263*10465441SEvalZero     return RT_EOK;
2264*10465441SEvalZero }
2265*10465441SEvalZero RTM_EXPORT(rt_mq_recv);
2266*10465441SEvalZero 
2267*10465441SEvalZero /**
2268*10465441SEvalZero  * This function can get or set some extra attributions of a message queue
2269*10465441SEvalZero  * object.
2270*10465441SEvalZero  *
2271*10465441SEvalZero  * @param mq the message queue object
2272*10465441SEvalZero  * @param cmd the execution command
2273*10465441SEvalZero  * @param arg the execution argument
2274*10465441SEvalZero  *
2275*10465441SEvalZero  * @return the error code
2276*10465441SEvalZero  */
rt_mq_control(rt_mq_t mq,int cmd,void * arg)2277*10465441SEvalZero rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg)
2278*10465441SEvalZero {
2279*10465441SEvalZero     rt_ubase_t level;
2280*10465441SEvalZero     struct rt_mq_message *msg;
2281*10465441SEvalZero 
2282*10465441SEvalZero     /* parameter check */
2283*10465441SEvalZero     RT_ASSERT(mq != RT_NULL);
2284*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
2285*10465441SEvalZero 
2286*10465441SEvalZero     if (cmd == RT_IPC_CMD_RESET)
2287*10465441SEvalZero     {
2288*10465441SEvalZero         /* disable interrupt */
2289*10465441SEvalZero         level = rt_hw_interrupt_disable();
2290*10465441SEvalZero 
2291*10465441SEvalZero         /* resume all waiting thread */
2292*10465441SEvalZero         rt_ipc_list_resume_all(&mq->parent.suspend_thread);
2293*10465441SEvalZero 
2294*10465441SEvalZero         /* release all message in the queue */
2295*10465441SEvalZero         while (mq->msg_queue_head != RT_NULL)
2296*10465441SEvalZero         {
2297*10465441SEvalZero             /* get message from queue */
2298*10465441SEvalZero             msg = (struct rt_mq_message *)mq->msg_queue_head;
2299*10465441SEvalZero 
2300*10465441SEvalZero             /* move message queue head */
2301*10465441SEvalZero             mq->msg_queue_head = msg->next;
2302*10465441SEvalZero             /* reach queue tail, set to NULL */
2303*10465441SEvalZero             if (mq->msg_queue_tail == msg)
2304*10465441SEvalZero                 mq->msg_queue_tail = RT_NULL;
2305*10465441SEvalZero 
2306*10465441SEvalZero             /* put message to free list */
2307*10465441SEvalZero             msg->next = (struct rt_mq_message *)mq->msg_queue_free;
2308*10465441SEvalZero             mq->msg_queue_free = msg;
2309*10465441SEvalZero         }
2310*10465441SEvalZero 
2311*10465441SEvalZero         /* clean entry */
2312*10465441SEvalZero         mq->entry = 0;
2313*10465441SEvalZero 
2314*10465441SEvalZero         /* enable interrupt */
2315*10465441SEvalZero         rt_hw_interrupt_enable(level);
2316*10465441SEvalZero 
2317*10465441SEvalZero         rt_schedule();
2318*10465441SEvalZero 
2319*10465441SEvalZero         return RT_EOK;
2320*10465441SEvalZero     }
2321*10465441SEvalZero 
2322*10465441SEvalZero     return -RT_ERROR;
2323*10465441SEvalZero }
2324*10465441SEvalZero RTM_EXPORT(rt_mq_control);
2325*10465441SEvalZero #endif /* end of RT_USING_MESSAGEQUEUE */
2326*10465441SEvalZero 
2327*10465441SEvalZero /**@}*/
2328