completion.c
4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-09-30 Bernard first version.
* 2021-08-18 chenyingchun add comments
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#define RT_COMPLETED 1
#define RT_UNCOMPLETED 0
/**
* @brief This function will initialize a completion object.
*
* @param completion is a pointer to a completion object.
*/
void rt_completion_init(struct rt_completion *completion)
{
rt_base_t level;
RT_ASSERT(completion != RT_NULL);
level = rt_hw_interrupt_disable();
completion->flag = RT_UNCOMPLETED;
rt_list_init(&completion->suspended_list);
rt_hw_interrupt_enable(level);
}
RTM_EXPORT(rt_completion_init);
/**
* @brief This function will wait for a completion, if the completion is unavailable, the thread shall wait for
* the completion up to a specified time.
*
* @param completion is a pointer to a completion object.
*
* @param timeout is a timeout period (unit: OS ticks). If the completion is unavailable, the thread will wait for
* the completion done up to the amount of time specified by the argument.
* NOTE: Generally, we use the macro RT_WAITING_FOREVER to set this parameter, which means that when the
* completion is unavailable, the thread will be waitting forever.
*
* @return Return the operation status. ONLY when the return value is RT_EOK, the operation is successful.
* If the return value is any other values, it means that the completion wait failed.
*
* @warning This function can ONLY be called in the thread context. It MUST NOT be called in interrupt context.
*/
rt_err_t rt_completion_wait(struct rt_completion *completion,
rt_int32_t timeout)
{
rt_err_t result;
rt_base_t level;
rt_thread_t thread;
RT_ASSERT(completion != RT_NULL);
/* current context checking */
RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
result = RT_EOK;
thread = rt_thread_self();
level = rt_hw_interrupt_disable();
if (completion->flag != RT_COMPLETED)
{
/* only one thread can suspend on complete */
RT_ASSERT(rt_list_isempty(&(completion->suspended_list)));
if (timeout == 0)
{
result = -RT_ETIMEOUT;
goto __exit;
}
else
{
/* reset thread error number */
thread->error = RT_EOK;
/* suspend thread */
rt_thread_suspend(thread);
/* add to suspended list */
rt_list_insert_before(&(completion->suspended_list),
&(thread->tlist));
/* start timer */
if (timeout > 0)
{
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
rt_timer_start(&(thread->thread_timer));
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* do schedule */
rt_schedule();
/* thread is waked up */
result = thread->error;
level = rt_hw_interrupt_disable();
}
}
/* clean completed flag */
completion->flag = RT_UNCOMPLETED;
__exit:
rt_hw_interrupt_enable(level);
return result;
}
RTM_EXPORT(rt_completion_wait);
/**
* @brief This function indicates a completion has done.
*
* @param completion is a pointer to a completion object.
*/
void rt_completion_done(struct rt_completion *completion)
{
rt_base_t level;
RT_ASSERT(completion != RT_NULL);
if (completion->flag == RT_COMPLETED)
return;
level = rt_hw_interrupt_disable();
completion->flag = RT_COMPLETED;
if (!rt_list_isempty(&(completion->suspended_list)))
{
/* there is one thread in suspended list */
struct rt_thread *thread;
/* get thread entry */
thread = rt_list_entry(completion->suspended_list.next,
struct rt_thread,
tlist);
/* resume it */
rt_thread_resume(thread);
rt_hw_interrupt_enable(level);
/* perform a schedule */
rt_schedule();
}
else
{
rt_hw_interrupt_enable(level);
}
}
RTM_EXPORT(rt_completion_done);