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