11/*
2- * Copyright (c) 2006-2023 , RT-Thread Development Team
2+ * Copyright (c) 2006-2022 , RT-Thread Development Team
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 *
1010 * 2021-08-14 Jackistang add comments for function interface
1111 * 2022-01-16 Meco Man add rt_work_urgent()
1212 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
13+ * 2024-12-21 yuqingli delete timer, using list
1314 */
1415
1516#include <rthw.h>
1617#include <rtdevice.h>
1718
1819#ifdef RT_USING_HEAP
1920
20- static void _delayed_work_timeout_handler (void * parameter );
21-
2221rt_inline rt_err_t _workqueue_work_completion (struct rt_workqueue * queue )
2322{
2423 rt_err_t result ;
@@ -50,38 +49,61 @@ rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
5049
5150static void _workqueue_thread_entry (void * parameter )
5251{
53- rt_base_t level ;
54- struct rt_work * work ;
52+ rt_base_t level ;
53+ struct rt_work * work ;
5554 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 ;
5659
57- queue = (struct rt_workqueue * ) parameter ;
60+ queue = (struct rt_workqueue * )parameter ;
5861 RT_ASSERT (queue != RT_NULL );
5962
6063 while (1 )
6164 {
6265 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 )))
6471 {
65- /* no software timer exist, suspend self. */
66- rt_thread_suspend_with_flag (rt_thread_self (), RT_UNINTERRUPTIBLE );
72+ work = rt_list_entry (queue -> delayed_list .next , struct rt_work , list );
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+ }
6786
68- /* release lock after suspend so we will not lost any wakeups */
87+ if (rt_list_isempty (& (queue -> work_list )))
88+ {
6989 rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
70-
71- rt_schedule ( );
90+ /* wait for work completion */
91+ rt_completion_wait ( & ( queue -> wakeup_completion ), delay_tick );
7292 continue ;
7393 }
7494
7595 /* we have work to do with. */
7696 work = rt_list_entry (queue -> work_list .next , struct rt_work , list );
7797 rt_list_remove (& (work -> list ));
78- queue -> work_current = work ;
79- work -> flags &= ~RT_WORK_STATE_PENDING ;
80- work -> workqueue = RT_NULL ;
98+ queue -> work_current = work ;
99+ work -> flags &= ~RT_WORK_STATE_PENDING ;
100+ work -> workqueue = RT_NULL ;
101+ work_func = work -> work_func ;
102+ work_data = work -> work_data ;
81103 rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
82104
83105 /* do work */
84- work -> work_func (work , work -> work_data );
106+ work_func (work , work_data );
85107 /* clean current work */
86108 queue -> work_current = RT_NULL ;
87109
@@ -93,114 +115,72 @@ static void _workqueue_thread_entry(void *parameter)
93115static rt_err_t _workqueue_submit_work (struct rt_workqueue * queue ,
94116 struct rt_work * work , rt_tick_t ticks )
95117{
96- rt_base_t level ;
97- rt_err_t err = RT_EOK ;
118+ rt_base_t level ;
119+ rt_err_t err = RT_EOK ;
120+ struct rt_work * work_tmp ;
121+ rt_list_t * list_tmp ;
98122
99123 level = rt_spin_lock_irqsave (& (queue -> spinlock ));
100-
101124 /* remove list */
102125 rt_list_remove (& (work -> list ));
103- work -> flags &= ~ RT_WORK_STATE_PENDING ;
126+ work -> flags = 0 ;
104127
105128 if (ticks == 0 )
106129 {
107130 rt_list_insert_after (queue -> work_list .prev , & (work -> list ));
108- work -> flags |= RT_WORK_STATE_PENDING ;
109- work -> workqueue = queue ;
131+ work -> flags |= RT_WORK_STATE_PENDING ;
132+ work -> workqueue = queue ;
110133
111- /* whether the workqueue is doing work */
112- if (queue -> work_current == RT_NULL )
113- {
114- /* resume work thread, and do a re-schedule if succeed */
115- rt_thread_resume (queue -> work_thread );
116- }
134+ rt_completion_done (& (queue -> wakeup_completion ));
135+ err = RT_EOK ;
117136 }
118137 else if (ticks < RT_TICK_MAX / 2 )
119138 {
120- /* Timer started */
121- if (work -> flags & RT_WORK_STATE_SUBMITTING )
122- {
123- rt_timer_control (& work -> timer , RT_TIMER_CTRL_SET_TIME , & ticks );
124- }
125- else
139+ /* insert delay work list */
140+ work -> flags |= RT_WORK_STATE_SUBMITTING ;
141+ work -> workqueue = queue ;
142+ work -> timeout_tick = rt_tick_get () + ticks ;
143+
144+ list_tmp = & (queue -> delayed_list );
145+ rt_list_for_each_entry (work_tmp , & (queue -> delayed_list ), list )
126146 {
127- rt_timer_init (& (work -> timer ), "work" , _delayed_work_timeout_handler ,
128- work , ticks , RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER );
129- work -> flags |= RT_WORK_STATE_SUBMITTING ;
147+ if ((work_tmp -> timeout_tick - work -> timeout_tick ) == 0 )
148+ {
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+ }
130156 }
131- work -> workqueue = queue ;
132- /* insert delay work list */
133- rt_list_insert_after (queue -> delayed_list .prev , & (work -> list ));
157+ rt_list_insert_before (list_tmp , & (work -> list ));
134158
135- err = rt_timer_start (& (work -> timer ));
159+ rt_completion_done (& (queue -> wakeup_completion ));
160+ err = RT_EOK ;
136161 }
137162 else
138163 {
139- err = - RT_ERROR ;
164+ err = - RT_ERROR ;
140165 }
141-
142166 rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
143167 return err ;
144168}
145169
146170static rt_err_t _workqueue_cancel_work (struct rt_workqueue * queue , struct rt_work * work )
147171{
148172 rt_base_t level ;
149- rt_err_t err ;
173+ rt_err_t err ;
150174
151175 level = rt_spin_lock_irqsave (& (queue -> spinlock ));
152176 rt_list_remove (& (work -> list ));
153- work -> flags &= ~RT_WORK_STATE_PENDING ;
154- /* Timer started */
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 ;
177+ work -> flags = 0 ;
178+ err = queue -> work_current != work ? RT_EOK : - RT_EBUSY ;
165179 work -> workqueue = RT_NULL ;
166- exit :
167180 rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
168181 return err ;
169182}
170183
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-
204184/**
205185 * @brief Initialize a work item, binding with a callback function.
206186 *
@@ -221,8 +201,8 @@ void rt_work_init(struct rt_work *work,
221201 work -> work_func = work_func ;
222202 work -> work_data = work_data ;
223203 work -> workqueue = RT_NULL ;
224- work -> flags = 0 ;
225- work -> type = 0 ;
204+ work -> flags = 0 ;
205+ work -> type = 0 ;
226206}
227207
228208/**
@@ -248,6 +228,7 @@ struct rt_workqueue *rt_workqueue_create(const char *name, rt_uint16_t stack_siz
248228 rt_list_init (& (queue -> delayed_list ));
249229 queue -> work_current = RT_NULL ;
250230 rt_sem_init (& (queue -> sem ), "wqueue" , 0 , RT_IPC_FLAG_FIFO );
231+ rt_completion_init (& (queue -> wakeup_completion ));
251232
252233 /* create the work thread */
253234 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
346327 /* NOTE: the work MUST be initialized firstly */
347328 rt_list_remove (& (work -> list ));
348329 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- }
355330
331+ rt_completion_done (& (queue -> wakeup_completion ));
356332 rt_spin_unlock_irqrestore (& (queue -> spinlock ), level );
333+
357334 return RT_EOK ;
358335}
359336
0 commit comments