xref: /nrf52832-nimble/rt-thread/components/drivers/src/completion.c (revision 104654410c56c573564690304ae786df310c91fc)
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)18 void 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)30 rt_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)97 void 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