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 * 2012-09-30 Bernard first version. 9 */ 10 11 #include <rthw.h> 12 #include <rtthread.h> 13 #include <rtdevice.h> 14 15 #define RT_COMPLETED 1 16 #define RT_UNCOMPLETED 0 17 rt_completion_init(struct rt_completion * completion)18void rt_completion_init(struct rt_completion *completion) 19 { 20 rt_base_t level; 21 RT_ASSERT(completion != RT_NULL); 22 23 level = rt_hw_interrupt_disable(); 24 completion->flag = RT_UNCOMPLETED; 25 rt_list_init(&completion->suspended_list); 26 rt_hw_interrupt_enable(level); 27 } 28 RTM_EXPORT(rt_completion_init); 29 rt_completion_wait(struct rt_completion * completion,rt_int32_t timeout)30rt_err_t rt_completion_wait(struct rt_completion *completion, 31 rt_int32_t timeout) 32 { 33 rt_err_t result; 34 rt_base_t level; 35 rt_thread_t thread; 36 RT_ASSERT(completion != RT_NULL); 37 38 result = RT_EOK; 39 thread = rt_thread_self(); 40 41 level = rt_hw_interrupt_disable(); 42 if (completion->flag != RT_COMPLETED) 43 { 44 /* only one thread can suspend on complete */ 45 RT_ASSERT(rt_list_isempty(&(completion->suspended_list))); 46 47 if (timeout == 0) 48 { 49 result = -RT_ETIMEOUT; 50 goto __exit; 51 } 52 else 53 { 54 /* reset thread error number */ 55 thread->error = RT_EOK; 56 57 /* suspend thread */ 58 rt_thread_suspend(thread); 59 /* add to suspended list */ 60 rt_list_insert_before(&(completion->suspended_list), 61 &(thread->tlist)); 62 63 /* current context checking */ 64 RT_DEBUG_NOT_IN_INTERRUPT; 65 66 /* start timer */ 67 if (timeout > 0) 68 { 69 /* reset the timeout of thread timer and start it */ 70 rt_timer_control(&(thread->thread_timer), 71 RT_TIMER_CTRL_SET_TIME, 72 &timeout); 73 rt_timer_start(&(thread->thread_timer)); 74 } 75 /* enable interrupt */ 76 rt_hw_interrupt_enable(level); 77 78 /* do schedule */ 79 rt_schedule(); 80 81 /* thread is waked up */ 82 result = thread->error; 83 84 level = rt_hw_interrupt_disable(); 85 } 86 } 87 /* clean completed flag */ 88 completion->flag = RT_UNCOMPLETED; 89 90 __exit: 91 rt_hw_interrupt_enable(level); 92 93 return result; 94 } 95 RTM_EXPORT(rt_completion_wait); 96 rt_completion_done(struct rt_completion * completion)97void rt_completion_done(struct rt_completion *completion) 98 { 99 rt_base_t level; 100 RT_ASSERT(completion != RT_NULL); 101 102 if (completion->flag == RT_COMPLETED) 103 return; 104 105 level = rt_hw_interrupt_disable(); 106 completion->flag = RT_COMPLETED; 107 108 if (!rt_list_isempty(&(completion->suspended_list))) 109 { 110 /* there is one thread in suspended list */ 111 struct rt_thread *thread; 112 113 /* get thread entry */ 114 thread = rt_list_entry(completion->suspended_list.next, 115 struct rt_thread, 116 tlist); 117 118 /* resume it */ 119 rt_thread_resume(thread); 120 rt_hw_interrupt_enable(level); 121 122 /* perform a schedule */ 123 rt_schedule(); 124 } 125 else 126 { 127 rt_hw_interrupt_enable(level); 128 } 129 } 130 RTM_EXPORT(rt_completion_done); 131 132