5
5
*
6
6
* Change Logs:
7
7
* 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
9
10
*/
10
11
11
- #include <rtthread.h>
12
- #include <rthw.h>
13
12
#include <rtdevice.h>
13
+ #include <rthw.h>
14
+ #include <rtthread.h>
14
15
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 ;
16
18
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 )
18
27
{
19
28
struct rt_cputimer * timer ;
20
29
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 ;
23
41
24
42
if (& _cputimer_list != _cputimer_list .prev )
25
43
{
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
+ }
29
58
}
30
59
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 ))
34
60
{
35
- /* start it */
36
- timer -> parent .flag &= ~RT_TIMER_FLAG_ACTIVATED ;
37
- rt_cputimer_start (timer );
61
+ _cputimer_nowtimer = NULL ;
38
62
}
39
63
}
40
64
41
65
void rt_cputimer_init (rt_cputimer_t timer ,
42
- const char * name ,
66
+ const char * name ,
43
67
void (* timeout )(void * parameter ),
44
- void * parameter ,
68
+ void * parameter ,
45
69
rt_uint64_t tick ,
46
- rt_uint8_t flag )
70
+ rt_uint8_t flag )
47
71
{
48
72
/* parameter check */
49
73
RT_ASSERT (timer != RT_NULL );
50
74
RT_ASSERT (timeout != RT_NULL );
51
75
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
52
76
53
- /* timer object initialization */
54
- rt_object_init (& (timer -> parent ), RT_Object_Class_Timer , name );
55
-
56
77
/* set flag */
57
78
timer -> parent .flag = flag ;
58
79
59
80
/* set deactivated */
60
81
timer -> parent .flag &= ~RT_TIMER_FLAG_ACTIVATED ;
61
-
62
82
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 ;
64
86
65
- timer -> timeout_tick = 0 ;
66
- timer -> init_tick = tick ;
67
87
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 );
80
89
}
81
90
82
91
rt_err_t rt_cputimer_delete (rt_cputimer_t timer )
@@ -85,8 +94,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
85
94
86
95
/* parameter check */
87
96
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 );
90
97
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
91
98
92
99
/* disable interrupt */
@@ -99,7 +106,6 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
99
106
/* enable interrupt */
100
107
rt_hw_interrupt_enable (level );
101
108
102
- rt_object_delete (& (timer -> parent ));
103
109
_set_next_timeout ();
104
110
105
111
return RT_EOK ;
@@ -108,11 +114,10 @@ rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
108
114
rt_err_t rt_cputimer_start (rt_cputimer_t timer )
109
115
{
110
116
rt_list_t * timer_list ;
111
- rt_base_t level ;
117
+ rt_base_t level ;
112
118
113
119
/* parameter check */
114
120
RT_ASSERT (timer != RT_NULL );
115
- RT_ASSERT (rt_object_get_type (& timer -> parent ) == RT_Object_Class_Timer );
116
121
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
117
122
118
123
/* stop timer firstly */
@@ -123,8 +128,6 @@ rt_err_t rt_cputimer_start(rt_cputimer_t timer)
123
128
/* change status of timer */
124
129
timer -> parent .flag &= ~RT_TIMER_FLAG_ACTIVATED ;
125
130
126
- timer -> timeout_tick = clock_cpu_gettime () + timer -> init_tick ;
127
-
128
131
timer_list = & _cputimer_list ;
129
132
130
133
for (; timer_list != _cputimer_list .prev ;
@@ -165,7 +168,6 @@ rt_err_t rt_cputimer_stop(rt_cputimer_t timer)
165
168
166
169
/* timer check */
167
170
RT_ASSERT (timer != RT_NULL );
168
- RT_ASSERT (rt_object_get_type (& timer -> parent ) == RT_Object_Class_Timer );
169
171
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
170
172
171
173
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)
191
193
192
194
/* parameter check */
193
195
RT_ASSERT (timer != RT_NULL );
194
- RT_ASSERT (rt_object_get_type (& timer -> parent ) == RT_Object_Class_Timer );
195
196
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
196
197
197
198
level = rt_hw_interrupt_disable ();
@@ -260,8 +261,6 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
260
261
261
262
/* parameter check */
262
263
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 ));
265
264
RT_ASSERT (clock_cpu_issettimeout () != RT_FALSE );
266
265
267
266
/* disable interrupt */
@@ -275,52 +274,19 @@ rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
275
274
/* enable interrupt */
276
275
rt_hw_interrupt_enable (level );
277
276
278
- rt_object_detach (& (timer -> parent ));
277
+ rt_sem_detach (& (timer -> sem ));
279
278
280
279
return RT_EOK ;
281
280
}
282
281
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
-
314
282
rt_err_t rt_cputime_sleep (rt_uint64_t tick )
315
283
{
316
- rt_base_t level ;
317
- struct rt_thread * thread ;
284
+ rt_base_t level ;
318
285
struct rt_cputimer cputimer ;
319
- int err ;
320
286
321
287
if (!clock_cpu_issettimeout ())
322
288
{
323
- rt_int32_t ms = tick * clock_cpu_getres () / 1000000 ;
289
+ rt_int32_t ms = clock_cpu_millisecond ( tick ) ;
324
290
return rt_thread_delay (rt_tick_from_millisecond (ms ));
325
291
}
326
292
@@ -329,53 +295,24 @@ rt_err_t rt_cputime_sleep(rt_uint64_t tick)
329
295
return - RT_EINVAL ;
330
296
}
331
297
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 );
341
300
342
301
/* disable interrupt */
343
302
level = rt_hw_interrupt_disable ();
344
303
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 );
370
307
371
308
rt_cputimer_detach (& cputimer );
372
- return err ;
309
+ return RT_EOK ;
373
310
}
374
311
375
312
rt_err_t rt_cputime_ndelay (rt_uint64_t ns )
376
313
{
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 );
379
316
}
380
317
381
318
rt_err_t rt_cputime_udelay (rt_uint64_t us )
0 commit comments