xref: /nrf52832-nimble/rt-thread/components/drivers/src/completion.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  * 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*10465441SEvalZero void 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*10465441SEvalZero rt_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*10465441SEvalZero void 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