Skip to content

Commit 970c7c6

Browse files
authored
🐞 fix(components/drivers): fix cpu timer in multithreading (#7222)
* 🐞 fix(components/drivers): fix cpu timer in multithreading * 🎈 perf(components): change double to uint64_t * 🎈 perf(components): add UL suffix
1 parent 590e603 commit 970c7c6

File tree

7 files changed

+90
-152
lines changed

7 files changed

+90
-152
lines changed

Diff for: components/drivers/cputime/cputime.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ static const struct rt_clock_cputime_ops *_cputime_ops = RT_NULL;
1818
* The clock_cpu_getres() function shall return the resolution of CPU time, the
1919
* number of nanosecond per tick.
2020
*
21-
* @return the number of nanosecond per tick
21+
* @return the number of nanosecond per tick(x (1000UL * 1000))
2222
*/
23-
double clock_cpu_getres(void)
23+
uint64_t clock_cpu_getres(void)
2424
{
2525
if (_cputime_ops)
2626
return _cputime_ops->cputime_getres();
@@ -78,9 +78,9 @@ int clock_cpu_issettimeout(void)
7878
*/
7979
uint64_t clock_cpu_microsecond(uint64_t cpu_tick)
8080
{
81-
double unit = clock_cpu_getres();
81+
uint64_t unit = clock_cpu_getres();
8282

83-
return (uint64_t)((cpu_tick * unit) / 1000);
83+
return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / 1000);
8484
}
8585

8686
/**
@@ -93,9 +93,9 @@ uint64_t clock_cpu_microsecond(uint64_t cpu_tick)
9393
*/
9494
uint64_t clock_cpu_millisecond(uint64_t cpu_tick)
9595
{
96-
double unit = clock_cpu_getres();
96+
uint64_t unit = clock_cpu_getres();
9797

98-
return (uint64_t)((cpu_tick * unit) / (1000 * 1000));
98+
return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / (1000UL * 1000));
9999
}
100100

101101
/**

Diff for: components/drivers/cputime/cputime_cortexm.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
#endif
2020

2121
/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
22-
static double cortexm_cputime_getres(void)
22+
static uint64_t cortexm_cputime_getres(void)
2323
{
24-
double ret = 1000UL * 1000 * 1000;
24+
uint64_t ret = 1000UL * 1000 * 1000;
2525

26-
ret = ret / SystemCoreClock;
26+
ret = (ret * (1000UL * 1000)) / SystemCoreClock;
2727
return ret;
2828
}
2929

Diff for: components/drivers/cputime/cputime_riscv.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
88

9-
static double riscv_cputime_getres(void)
9+
static uint64_t riscv_cputime_getres(void)
1010
{
11-
double ret = 1000UL * 1000 * 1000;
11+
uint64_t ret = 1000UL * 1000 * 1000;
1212

13-
ret = ret / CPUTIME_TIMER_FREQ;
13+
ret = (ret * (1000UL * 1000)) / CPUTIME_TIMER_FREQ;
1414
return ret;
1515
}
1616

Diff for: components/drivers/cputime/cputimer.c

+59-122
Original file line numberDiff line numberDiff line change
@@ -5,78 +5,87 @@
55
*
66
* Change Logs:
77
* Date Author Notes
8-
* 2023-02-13 zhkag first version
8+
* 2023-02-13 zhkag first version
9+
* 2023-04-03 xqyjlj fix cputimer in multithreading
910
*/
1011

11-
#include <rtthread.h>
12-
#include <rthw.h>
1312
#include <rtdevice.h>
13+
#include <rthw.h>
14+
#include <rtthread.h>
1415

15-
static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list);
16+
static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list);
17+
static struct rt_cputimer *_cputimer_nowtimer = RT_NULL;
1618

17-
static void _cputime_timeout(void *parameter)
19+
static void _cputime_sleep_timeout(void *parameter)
20+
{
21+
struct rt_semaphore *sem;
22+
sem = (struct rt_semaphore *)parameter;
23+
rt_sem_release(sem);
24+
}
25+
26+
static void _cputime_timeout_callback(void *parameter)
1827
{
1928
struct rt_cputimer *timer;
2029
timer = (struct rt_cputimer *)parameter;
21-
timer->timeout_func(timer->parameter);
22-
rt_list_remove(&timer->row);
30+
rt_base_t level;
31+
level = rt_hw_interrupt_disable();
32+
_cputimer_nowtimer = RT_NULL;
33+
rt_list_remove(&(timer->row));
34+
rt_hw_interrupt_enable(level);
35+
timer->timeout_func(&(timer->sem));
36+
}
37+
38+
static void _set_next_timeout()
39+
{
40+
struct rt_cputimer *t;
2341

2442
if (&_cputimer_list != _cputimer_list.prev)
2543
{
26-
struct rt_cputimer *t;
27-
t = rt_list_entry(_cputimer_list.next, struct rt_cputimer, row);
28-
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout, t);
44+
t = rt_list_entry((&_cputimer_list)->next, struct rt_cputimer, row);
45+
if (_cputimer_nowtimer != RT_NULL)
46+
{
47+
if (t != _cputimer_nowtimer && t->timeout_tick < _cputimer_nowtimer->timeout_tick)
48+
{
49+
_cputimer_nowtimer = t;
50+
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t);
51+
}
52+
}
53+
else
54+
{
55+
_cputimer_nowtimer = t;
56+
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t);
57+
}
2958
}
3059
else
31-
clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
32-
if ((timer->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
33-
(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
3460
{
35-
/* start it */
36-
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
37-
rt_cputimer_start(timer);
61+
_cputimer_nowtimer = NULL;
3862
}
3963
}
4064

4165
void rt_cputimer_init(rt_cputimer_t timer,
42-
const char *name,
66+
const char *name,
4367
void (*timeout)(void *parameter),
44-
void *parameter,
68+
void *parameter,
4569
rt_uint64_t tick,
46-
rt_uint8_t flag)
70+
rt_uint8_t flag)
4771
{
4872
/* parameter check */
4973
RT_ASSERT(timer != RT_NULL);
5074
RT_ASSERT(timeout != RT_NULL);
5175
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
5276

53-
/* timer object initialization */
54-
rt_object_init(&(timer->parent), RT_Object_Class_Timer, name);
55-
5677
/* set flag */
5778
timer->parent.flag = flag;
5879

5980
/* set deactivated */
6081
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
61-
6282
timer->timeout_func = timeout;
63-
timer->parameter = parameter;
83+
timer->parameter = parameter;
84+
timer->timeout_tick = tick + clock_cpu_gettime();
85+
timer->init_tick = tick;
6486

65-
timer->timeout_tick = 0;
66-
timer->init_tick = tick;
6787
rt_list_init(&(timer->row));
68-
}
69-
70-
static void _set_next_timeout()
71-
{
72-
struct rt_cputimer *t;
73-
if (&_cputimer_list != _cputimer_list.prev)
74-
{
75-
t = rt_list_entry((&_cputimer_list)->next, struct rt_cputimer, row);
76-
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout, t);
77-
}
78-
else
79-
clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
88+
rt_sem_init(&(timer->sem), "cputime", 0, RT_IPC_FLAG_PRIO);
8089
}
8190

8291
rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
@@ -85,8 +94,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
8594

8695
/* parameter check */
8796
RT_ASSERT(timer != RT_NULL);
88-
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
89-
RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
9097
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
9198

9299
/* disable interrupt */
@@ -99,7 +106,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
99106
/* enable interrupt */
100107
rt_hw_interrupt_enable(level);
101108

102-
rt_object_delete(&(timer->parent));
103109
_set_next_timeout();
104110

105111
return RT_EOK;
@@ -108,11 +114,10 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
108114
rt_err_t rt_cputimer_start(rt_cputimer_t timer)
109115
{
110116
rt_list_t *timer_list;
111-
rt_base_t level;
117+
rt_base_t level;
112118

113119
/* parameter check */
114120
RT_ASSERT(timer != RT_NULL);
115-
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
116121
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
117122

118123
/* stop timer firstly */
@@ -123,8 +128,6 @@ rt_err_t rt_cputimer_start(rt_cputimer_t timer)
123128
/* change status of timer */
124129
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
125130

126-
timer->timeout_tick = clock_cpu_gettime() + timer->init_tick;
127-
128131
timer_list = &_cputimer_list;
129132

130133
for (; timer_list != _cputimer_list.prev;
@@ -165,7 +168,6 @@ rt_err_t rt_cputimer_stop(rt_cputimer_t timer)
165168

166169
/* timer check */
167170
RT_ASSERT(timer != RT_NULL);
168-
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
169171
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
170172

171173
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
@@ -191,7 +193,6 @@ rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg)
191193

192194
/* parameter check */
193195
RT_ASSERT(timer != RT_NULL);
194-
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
195196
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
196197

197198
level = rt_hw_interrupt_disable();
@@ -260,8 +261,6 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
260261

261262
/* parameter check */
262263
RT_ASSERT(timer != RT_NULL);
263-
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
264-
RT_ASSERT(rt_object_is_systemobject(&timer->parent));
265264
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
266265

267266
/* disable interrupt */
@@ -275,52 +274,19 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
275274
/* enable interrupt */
276275
rt_hw_interrupt_enable(level);
277276

278-
rt_object_detach(&(timer->parent));
277+
rt_sem_detach(&(timer->sem));
279278

280279
return RT_EOK;
281280
}
282281

283-
static void _cputime_sleep_timeout(void *parameter)
284-
{
285-
struct rt_thread *thread;
286-
rt_base_t level;
287-
288-
thread = (struct rt_thread *)parameter;
289-
290-
/* parameter check */
291-
RT_ASSERT(thread != RT_NULL);
292-
RT_ASSERT((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK);
293-
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
294-
295-
/* disable interrupt */
296-
level = rt_hw_interrupt_disable();
297-
298-
/* set error number */
299-
thread->error = -RT_ETIMEOUT;
300-
301-
/* remove from suspend list */
302-
rt_list_remove(&(thread->tlist));
303-
304-
/* insert to schedule ready list */
305-
rt_schedule_insert_thread(thread);
306-
307-
/* enable interrupt */
308-
rt_hw_interrupt_enable(level);
309-
310-
/* do schedule */
311-
rt_schedule();
312-
}
313-
314282
rt_err_t rt_cputime_sleep(rt_uint64_t tick)
315283
{
316-
rt_base_t level;
317-
struct rt_thread *thread;
284+
rt_base_t level;
318285
struct rt_cputimer cputimer;
319-
int err;
320286

321287
if (!clock_cpu_issettimeout())
322288
{
323-
rt_int32_t ms = tick * clock_cpu_getres() / 1000000;
289+
rt_int32_t ms = clock_cpu_millisecond(tick);
324290
return rt_thread_delay(rt_tick_from_millisecond(ms));
325291
}
326292

@@ -329,53 +295,24 @@ rt_err_t rt_cputime_sleep(rt_uint64_t tick)
329295
return -RT_EINVAL;
330296
}
331297

332-
/* set to current thread */
333-
thread = rt_thread_self();
334-
RT_ASSERT(thread != RT_NULL);
335-
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
336-
337-
/* current context checking */
338-
RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
339-
340-
rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, thread, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
298+
rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, &(cputimer.sem), tick,
299+
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
341300

342301
/* disable interrupt */
343302
level = rt_hw_interrupt_disable();
344303

345-
/* reset thread error */
346-
thread->error = RT_EOK;
347-
348-
/* suspend thread */
349-
err = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
350-
351-
/* reset the timeout of thread timer and start it */
352-
if (err == RT_EOK)
353-
{
354-
rt_cputimer_control(&cputimer, RT_TIMER_CTRL_SET_TIME, &tick);
355-
rt_cputimer_start(&cputimer);
356-
357-
/* enable interrupt */
358-
rt_hw_interrupt_enable(level);
359-
360-
thread->error = -RT_EINTR;
361-
362-
rt_schedule();
363-
if (thread->error == -RT_ETIMEOUT)
364-
thread->error = RT_EOK;
365-
}
366-
else
367-
{
368-
rt_hw_interrupt_enable(level);
369-
}
304+
rt_cputimer_start(&cputimer); /* reset the timeout of thread timer and start it */
305+
rt_hw_interrupt_enable(level);
306+
rt_sem_take_interruptible(&(cputimer.sem), RT_WAITING_FOREVER);
370307

371308
rt_cputimer_detach(&cputimer);
372-
return err;
309+
return RT_EOK;
373310
}
374311

375312
rt_err_t rt_cputime_ndelay(rt_uint64_t ns)
376313
{
377-
double unit = clock_cpu_getres();
378-
return rt_cputime_sleep(ns / unit);
314+
uint64_t unit = clock_cpu_getres();
315+
return rt_cputime_sleep(ns * (1000UL * 1000) / unit);
379316
}
380317

381318
rt_err_t rt_cputime_udelay(rt_uint64_t us)

Diff for: components/drivers/include/drivers/cputime.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
struct rt_clock_cputime_ops
1818
{
19-
double (*cputime_getres)(void);
19+
uint64_t (*cputime_getres)(void);
2020
uint64_t (*cputime_gettime)(void);
2121
int (*cputime_settimeout)(uint64_t tick, void (*timeout)(void *param), void *param);
2222
};
2323

24-
double clock_cpu_getres(void);
24+
uint64_t clock_cpu_getres(void);
2525
uint64_t clock_cpu_gettime(void);
2626
int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *param);
2727
int clock_cpu_issettimeout(void);

Diff for: components/drivers/include/drivers/cputimer.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct rt_cputimer
2121
void *parameter;
2222
rt_uint64_t init_tick;
2323
rt_uint64_t timeout_tick;
24+
struct rt_semaphore sem;
2425
};
2526
typedef struct rt_cputimer *rt_cputimer_t;
2627

0 commit comments

Comments
 (0)