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