-
Notifications
You must be signed in to change notification settings - Fork 5.1k
/
Copy pathclock.c
245 lines (211 loc) · 5.75 KB
/
clock.c
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-03-12 Bernard first version
* 2006-05-27 Bernard add support for same priority thread schedule
* 2006-08-10 Bernard remove the last rt_schedule in rt_tick_increase
* 2010-03-08 Bernard remove rt_passed_second
* 2010-05-20 Bernard fix the tick exceeds the maximum limits
* 2010-07-13 Bernard fix rt_tick_from_millisecond issue found by kuronca
* 2011-06-26 Bernard add rt_tick_set function.
* 2018-11-22 Jesven add per cpu tick
* 2020-12-29 Meco Man implement rt_tick_get_millisecond()
* 2021-06-01 Meco Man add critical section projection for rt_tick_increase()
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
* 2023-10-16 RiceChen fix: only the main core detection rt_timer_check(), in SMP mode
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtatomic.h>
#if defined(RT_USING_SMART) && defined(RT_USING_VDSO)
#include <vdso.h>
#endif
#ifdef RT_USING_SMP
#define rt_tick rt_cpu_index(0)->tick
#else
static volatile rt_atomic_t rt_tick = 0;
#endif /* RT_USING_SMP */
#if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
static void (*rt_tick_hook)(void);
/**
* @addtogroup group_Hook
*/
/**@{*/
/**
* @brief This function will set a hook function, which will be invoked when tick increase
*
*
* @param hook the hook function
*/
void rt_tick_sethook(void (*hook)(void))
{
rt_tick_hook = hook;
}
/**@}*/
#endif /* RT_USING_HOOK */
/**
* @addtogroup group_Clock
*/
/**@{*/
/**
* @brief This function will return current tick from operating system startup.
*
* @return Return current tick.
*/
rt_tick_t rt_tick_get(void)
{
/* return the global tick */
return (rt_tick_t)rt_atomic_load(&(rt_tick));
}
RTM_EXPORT(rt_tick_get);
/**
* @brief This function will set current tick.
*
* @param tick is the value that you will set.
*/
void rt_tick_set(rt_tick_t tick)
{
rt_atomic_store(&(rt_tick), tick);
}
#ifdef RT_USING_CPU_USAGE_TRACER
static void _update_process_times(rt_tick_t tick)
{
struct rt_thread *thread = rt_thread_self();
struct rt_cpu *pcpu = rt_cpu_self();
if (!LWP_IS_USER_MODE(thread))
{
thread->user_time += tick;
pcpu->cpu_stat.user += tick;
}
else
{
thread->system_time += tick;
if (thread == pcpu->idle_thread)
{
pcpu->cpu_stat.idle += tick;
}
else
{
pcpu->cpu_stat.system += tick;
}
}
}
#else
#define _update_process_times(tick)
#endif /* RT_USING_CPU_USAGE_TRACER */
/**
* @brief This function will notify kernel there is one tick passed.
* Normally, this function is invoked by clock ISR.
*/
void rt_tick_increase(void)
{
RT_ASSERT(rt_interrupt_get_nest() > 0);
RT_OBJECT_HOOK_CALL(rt_tick_hook, ());
/* tracing cpu usage */
_update_process_times(1);
/* increase the global tick */
#ifdef RT_USING_SMP
/* get percpu and increase the tick */
rt_atomic_add(&(rt_cpu_self()->tick), 1);
#else
rt_atomic_add(&(rt_tick), 1);
#endif /* RT_USING_SMP */
/* check time slice */
rt_sched_tick_increase(1);
/* check timer */
#ifdef RT_USING_SMP
if (rt_cpu_get_id() != 0)
{
return;
}
#endif
rt_timer_check();
}
/**
* @brief This function will notify kernel there is n tick passed.
* Normally, this function is invoked by clock ISR.
*/
void rt_tick_increase_tick(rt_tick_t tick)
{
RT_ASSERT(rt_interrupt_get_nest() > 0);
RT_OBJECT_HOOK_CALL(rt_tick_hook, ());
/* tracing cpu usage */
_update_process_times(tick);
/* increase the global tick */
#ifdef RT_USING_SMP
/* get percpu and increase the tick */
rt_atomic_add(&(rt_cpu_self()->tick), tick);
#else
rt_atomic_add(&(rt_tick), tick);
#endif /* RT_USING_SMP */
/* check time slice */
rt_sched_tick_increase(tick);
/* check timer */
#ifdef RT_USING_SMP
if (rt_cpu_get_id() != 0)
{
return;
}
#endif
rt_timer_check();
#ifdef RT_USING_VDSO
rt_vdso_update_glob_time();
#endif
}
/**
* @brief This function will calculate the tick from millisecond.
*
* @param ms is the specified millisecond.
* - Negative Number wait forever
* - Zero not wait
* - Max 0x7fffffff
*
* @return Return the calculated tick.
*/
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms)
{
rt_tick_t tick;
if (ms < 0)
{
tick = (rt_tick_t)RT_WAITING_FOREVER;
}
else
{
#if RT_TICK_PER_SECOND == 1000u
tick = ms;
#else
tick = RT_TICK_PER_SECOND * (ms / 1000);
tick += (RT_TICK_PER_SECOND * (ms % 1000) + 999) / 1000;
#endif /* RT_TICK_PER_SECOND == 1000u */
}
/* return the calculated tick */
return tick;
}
RTM_EXPORT(rt_tick_from_millisecond);
/**
* @brief This function will return the passed millisecond from boot.
*
* @note if the value of RT_TICK_PER_SECOND is lower than 1000 or
* is not an integral multiple of 1000, this function will not
* provide the correct 1ms-based tick.
*
* @return Return passed millisecond from boot.
*/
rt_weak rt_tick_t rt_tick_get_millisecond(void)
{
#if RT_TICK_PER_SECOND == 0 /* make cppcheck happy*/
#error "RT_TICK_PER_SECOND must be greater than zero"
#endif
#if 1000 % RT_TICK_PER_SECOND == 0u
return rt_tick_get() * (1000u / RT_TICK_PER_SECOND);
#else
#warning "rt-thread cannot provide a correct 1ms-based tick any longer,\
please redefine this function in another file by using a high-precision hard-timer."
return 0;
#endif /* 1000 % RT_TICK_PER_SECOND == 0u */
}
/**@}*/