1
/*
1
/*
2
- * Copyright (c) 2006-2023 , RT-Thread Development Team
2
+ * Copyright (c) 2006-2022 , RT-Thread Development Team
3
*
3
*
4
* SPDX-License-Identifier: Apache-2.0
4
* SPDX-License-Identifier: Apache-2.0
5
*
5
*
10
* 2021-08-14 Jackistang add comments for function interface
10
* 2021-08-14 Jackistang add comments for function interface
11
* 2022-01-16 Meco Man add rt_work_urgent()
11
* 2022-01-16 Meco Man add rt_work_urgent()
12
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
12
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
13
+ * 2024-12-21 yuqingli delete timer, using list
13
*/
14
*/
14
15
15
#include <rthw.h>
16
#include <rthw.h>
16
#include <rtdevice.h>
17
#include <rtdevice.h>
17
18
18
#ifdef RT_USING_HEAP
19
#ifdef RT_USING_HEAP
19
20
20
- static void _delayed_work_timeout_handler (void * parameter );
21
-
22
rt_inline rt_err_t _workqueue_work_completion (struct rt_workqueue * queue )
21
rt_inline rt_err_t _workqueue_work_completion (struct rt_workqueue * queue )
23
{
22
{
24
rt_err_t result ;
23
rt_err_t result ;
@@ -50,38 +49,61 @@ rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
50
49
51
static void _workqueue_thread_entry (void * parameter )
50
static void _workqueue_thread_entry (void * parameter )
52
{
51
{
53
- rt_base_t level ;
52
+ rt_base_t level ;
54
- struct rt_work * work ;
53
+ struct rt_work * work ;
55
struct rt_workqueue * queue ;
54
struct rt_workqueue * queue ;
55
+ rt_tick_t current_tick ;
56
+ rt_int32_t delay_tick ;
57
+ void (* work_func )(struct rt_work * work , void * work_data );
58
+ void * work_data ;
56
59
57
- queue = (struct rt_workqueue * ) parameter ;
60
+ queue = (struct rt_workqueue * )parameter ;
58
RT_ASSERT (queue != RT_NULL );
61
RT_ASSERT (queue != RT_NULL );
59
62
60
while (1 )
63
while (1 )
61
{
64
{
62
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
65
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
63
- if (rt_list_isempty (& (queue -> work_list )))
66
+
67
+ /* timer check */
68
+ current_tick = rt_tick_get ();
69
+ delay_tick = RT_WAITING_FOREVER ;
70
+ while (!rt_list_isempty (& (queue -> delayed_list )))
64
{
71
{
65
- /* no software timer exist, suspend self. */
72
+ work = rt_list_entry (queue -> delayed_list .next , struct rt_work , list );
66
- rt_thread_suspend_with_flag (rt_thread_self (), RT_UNINTERRUPTIBLE );
73
+ if ((current_tick - work -> timeout_tick ) < RT_TICK_MAX / 2 )
74
+ {
75
+ rt_list_remove (& (work -> list ));
76
+ rt_list_insert_after (queue -> work_list .prev , & (work -> list ));
77
+ work -> flags &= ~RT_WORK_STATE_SUBMITTING ;
78
+ work -> flags |= RT_WORK_STATE_PENDING ;
79
+ }
80
+ else
81
+ {
82
+ delay_tick = work -> timeout_tick - current_tick ;
83
+ break ;
84
+ }
85
+ }
67
86
68
- /* release lock after suspend so we will not lost any wakeups */
87
+ if (rt_list_isempty (& (queue -> work_list )))
88
+ {
69
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
89
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
70
-
90
+ /* wait for work completion */
71
- rt_schedule ( );
91
+ rt_completion_wait ( & ( queue -> wakeup_completion ), delay_tick );
72
continue ;
92
continue ;
73
}
93
}
74
94
75
/* we have work to do with. */
95
/* we have work to do with. */
76
work = rt_list_entry (queue -> work_list .next , struct rt_work , list );
96
work = rt_list_entry (queue -> work_list .next , struct rt_work , list );
77
rt_list_remove (& (work -> list ));
97
rt_list_remove (& (work -> list ));
78
- queue -> work_current = work ;
98
+ queue -> work_current = work ;
79
- work -> flags &= ~RT_WORK_STATE_PENDING ;
99
+ work -> flags &= ~RT_WORK_STATE_PENDING ;
80
- work -> workqueue = RT_NULL ;
100
+ work -> workqueue = RT_NULL ;
101
+ work_func = work -> work_func ;
102
+ work_data = work -> work_data ;
81
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
103
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
82
104
83
/* do work */
105
/* do work */
84
- work -> work_func (work , work -> work_data );
106
+ work_func (work , work_data );
85
/* clean current work */
107
/* clean current work */
86
queue -> work_current = RT_NULL ;
108
queue -> work_current = RT_NULL ;
87
109
@@ -93,114 +115,72 @@ static void _workqueue_thread_entry(void *parameter)
93
static rt_err_t _workqueue_submit_work (struct rt_workqueue * queue ,
115
static rt_err_t _workqueue_submit_work (struct rt_workqueue * queue ,
94
struct rt_work * work , rt_tick_t ticks )
116
struct rt_work * work , rt_tick_t ticks )
95
{
117
{
96
- rt_base_t level ;
118
+ rt_base_t level ;
97
- rt_err_t err = RT_EOK ;
119
+ rt_err_t err = RT_EOK ;
120
+ struct rt_work * work_tmp ;
121
+ rt_list_t * list_tmp ;
98
122
99
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
123
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
100
-
101
/* remove list */
124
/* remove list */
102
rt_list_remove (& (work -> list ));
125
rt_list_remove (& (work -> list ));
103
- work -> flags &= ~ RT_WORK_STATE_PENDING ;
126
+ work -> flags = 0 ;
104
127
105
if (ticks == 0 )
128
if (ticks == 0 )
106
{
129
{
107
rt_list_insert_after (queue -> work_list .prev , & (work -> list ));
130
rt_list_insert_after (queue -> work_list .prev , & (work -> list ));
108
- work -> flags |= RT_WORK_STATE_PENDING ;
131
+ work -> flags |= RT_WORK_STATE_PENDING ;
109
- work -> workqueue = queue ;
132
+ work -> workqueue = queue ;
110
133
111
- /* whether the workqueue is doing work */
134
+ rt_completion_done (& (queue -> wakeup_completion ));
112
- if (queue -> work_current == RT_NULL )
135
+ err = RT_EOK ;
113
- {
114
- /* resume work thread, and do a re-schedule if succeed */
115
- rt_thread_resume (queue -> work_thread );
116
- }
117
}
136
}
118
else if (ticks < RT_TICK_MAX / 2 )
137
else if (ticks < RT_TICK_MAX / 2 )
119
{
138
{
120
- /* Timer started */
139
+ /* insert delay work list */
121
- if (work -> flags & RT_WORK_STATE_SUBMITTING )
140
+ work -> flags |= RT_WORK_STATE_SUBMITTING ;
122
- {
141
+ work -> workqueue = queue ;
123
- rt_timer_control (& work -> timer , RT_TIMER_CTRL_SET_TIME , & ticks );
142
+ work -> timeout_tick = rt_tick_get () + ticks ;
124
- }
143
+
125
- else
144
+ list_tmp = & (queue -> delayed_list );
145
+ rt_list_for_each_entry (work_tmp , & (queue -> delayed_list ), list )
126
{
146
{
127
- rt_timer_init (& (work -> timer ), "work" , _delayed_work_timeout_handler ,
147
+ if ((work_tmp -> timeout_tick - work -> timeout_tick ) == 0 )
128
- work , ticks , RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER );
148
+ {
129
- work -> flags |= RT_WORK_STATE_SUBMITTING ;
149
+ continue ;
150
+ }
151
+ else if ((work_tmp -> timeout_tick - work -> timeout_tick ) < RT_TICK_MAX / 2 )
152
+ {
153
+ list_tmp = & (work_tmp -> list );
154
+ break ;
155
+ }
130
}
156
}
131
- work -> workqueue = queue ;
157
+ rt_list_insert_before (list_tmp , & (work -> list ));
132
- /* insert delay work list */
133
- rt_list_insert_after (queue -> delayed_list .prev , & (work -> list ));
134
158
135
- err = rt_timer_start (& (work -> timer ));
159
+ rt_completion_done (& (queue -> wakeup_completion ));
160
+ err = RT_EOK ;
136
}
161
}
137
else
162
else
138
{
163
{
139
- err = - RT_ERROR ;
164
+ err = - RT_ERROR ;
140
}
165
}
141
-
142
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
166
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
143
return err ;
167
return err ;
144
}
168
}
145
169
146
static rt_err_t _workqueue_cancel_work (struct rt_workqueue * queue , struct rt_work * work )
170
static rt_err_t _workqueue_cancel_work (struct rt_workqueue * queue , struct rt_work * work )
147
{
171
{
148
rt_base_t level ;
172
rt_base_t level ;
149
- rt_err_t err ;
173
+ rt_err_t err ;
150
174
151
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
175
level = rt_spin_lock_irqsave (& (queue -> spinlock ));
152
rt_list_remove (& (work -> list ));
176
rt_list_remove (& (work -> list ));
153
- work -> flags &= ~RT_WORK_STATE_PENDING ;
177
+ work -> flags = 0 ;
154
- /* Timer started */
178
+ err = queue -> work_current != work ? RT_EOK : - RT_EBUSY ;
155
- if (work -> flags & RT_WORK_STATE_SUBMITTING )
156
- {
157
- if ((err = rt_timer_stop (& (work -> timer ))) != RT_EOK )
158
- {
159
- goto exit ;
160
- }
161
- rt_timer_detach (& (work -> timer ));
162
- work -> flags &= ~RT_WORK_STATE_SUBMITTING ;
163
- }
164
- err = queue -> work_current != work ? RT_EOK : - RT_EBUSY ;
165
work -> workqueue = RT_NULL ;
179
work -> workqueue = RT_NULL ;
166
- exit :
167
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
180
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
168
return err ;
181
return err ;
169
}
182
}
170
183
171
- static void _delayed_work_timeout_handler (void * parameter )
172
- {
173
- struct rt_work * work ;
174
- struct rt_workqueue * queue ;
175
- rt_base_t level ;
176
-
177
- work = (struct rt_work * )parameter ;
178
- queue = work -> workqueue ;
179
-
180
- RT_ASSERT (work -> flags & RT_WORK_STATE_SUBMITTING );
181
- RT_ASSERT (queue != RT_NULL );
182
-
183
- level = rt_spin_lock_irqsave (& (queue -> spinlock ));
184
- rt_timer_detach (& (work -> timer ));
185
- work -> flags &= ~RT_WORK_STATE_SUBMITTING ;
186
- /* remove delay list */
187
- rt_list_remove (& (work -> list ));
188
- /* insert work queue */
189
- if (queue -> work_current != work )
190
- {
191
- rt_list_insert_after (queue -> work_list .prev , & (work -> list ));
192
- work -> flags |= RT_WORK_STATE_PENDING ;
193
- }
194
- /* whether the workqueue is doing work */
195
- if (queue -> work_current == RT_NULL )
196
- {
197
- /* resume work thread, and do a re-schedule if succeed */
198
- rt_thread_resume (queue -> work_thread );
199
- }
200
-
201
- rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
202
- }
203
-
204
/**
184
/**
205
* @brief Initialize a work item, binding with a callback function.
185
* @brief Initialize a work item, binding with a callback function.
206
*
186
*
@@ -221,8 +201,8 @@ void rt_work_init(struct rt_work *work,
221
work -> work_func = work_func ;
201
work -> work_func = work_func ;
222
work -> work_data = work_data ;
202
work -> work_data = work_data ;
223
work -> workqueue = RT_NULL ;
203
work -> workqueue = RT_NULL ;
224
- work -> flags = 0 ;
204
+ work -> flags = 0 ;
225
- work -> type = 0 ;
205
+ work -> type = 0 ;
226
}
206
}
227
207
228
/**
208
/**
@@ -248,6 +228,7 @@ struct rt_workqueue *rt_workqueue_create(const char *name, rt_uint16_t stack_siz
248
rt_list_init (& (queue -> delayed_list ));
228
rt_list_init (& (queue -> delayed_list ));
249
queue -> work_current = RT_NULL ;
229
queue -> work_current = RT_NULL ;
250
rt_sem_init (& (queue -> sem ), "wqueue" , 0 , RT_IPC_FLAG_FIFO );
230
rt_sem_init (& (queue -> sem ), "wqueue" , 0 , RT_IPC_FLAG_FIFO );
231
+ rt_completion_init (& (queue -> wakeup_completion ));
251
232
252
/* create the work thread */
233
/* create the work thread */
253
queue -> work_thread = rt_thread_create (name , _workqueue_thread_entry , queue , stack_size , priority , 10 );
234
queue -> work_thread = rt_thread_create (name , _workqueue_thread_entry , queue , stack_size , priority , 10 );
@@ -346,14 +327,10 @@ rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *wo
346
/* NOTE: the work MUST be initialized firstly */
327
/* NOTE: the work MUST be initialized firstly */
347
rt_list_remove (& (work -> list ));
328
rt_list_remove (& (work -> list ));
348
rt_list_insert_after (& queue -> work_list , & (work -> list ));
329
rt_list_insert_after (& queue -> work_list , & (work -> list ));
349
- /* whether the workqueue is doing work */
350
- if (queue -> work_current == RT_NULL )
351
- {
352
- /* resume work thread, and do a re-schedule if succeed */
353
- rt_thread_resume (queue -> work_thread );
354
- }
355
330
331
+ rt_completion_done (& (queue -> wakeup_completion ));
356
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
332
rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
333
+
357
return RT_EOK ;
334
return RT_EOK ;
358
}
335
}
359
336
0 commit comments