88 * 2012-09-30 Bernard first version.
99 * 2021-08-18 chenyingchun add comments
1010 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
11+ * 2024-01-25 Shell reduce resource usage in completion for better synchronization
12+ * and smaller footprint.
1113 */
1214
15+ #define DBG_TAG "drivers.ipc"
16+ #define DBG_LVL DBG_INFO
17+ #include <rtdbg.h>
18+
1319#include <rthw.h>
1420#include <rtdevice.h>
1521
1622#define RT_COMPLETED 1
1723#define RT_UNCOMPLETED 0
24+ #define RT_COMPLETION_FLAG (comp ) ((comp)->susp_thread_n_flag & 1)
25+ #define RT_COMPLETION_THREAD (comp ) ((rt_thread_t)((comp)->susp_thread_n_flag & ~1))
26+ #define RT_COMPLETION_NEW_STAT (thread , flag ) (((flag) & 1) | (((rt_base_t)thread) & ~1))
27+
28+ static struct rt_spinlock _completion_lock = RT_SPINLOCK_INIT ;
1829
1930/**
2031 * @brief This function will initialize a completion object.
2334 */
2435void rt_completion_init (struct rt_completion * completion )
2536{
26- rt_base_t level ;
2737 RT_ASSERT (completion != RT_NULL );
2838
29- rt_spin_lock_init (& (completion -> spinlock ));
30- level = rt_spin_lock_irqsave (& (completion -> spinlock ));
31- completion -> flag = RT_UNCOMPLETED ;
32- rt_list_init (& completion -> suspended_list );
33- rt_spin_unlock_irqrestore (& (completion -> spinlock ), level );
39+ completion -> susp_thread_n_flag = RT_COMPLETION_NEW_STAT (RT_NULL , RT_UNCOMPLETED );
3440}
3541RTM_EXPORT (rt_completion_init );
3642
@@ -64,11 +70,11 @@ rt_err_t rt_completion_wait(struct rt_completion *completion,
6470 result = RT_EOK ;
6571 thread = rt_thread_self ();
6672
67- level = rt_spin_lock_irqsave (& ( completion -> spinlock ) );
68- if (completion -> flag != RT_COMPLETED )
73+ level = rt_spin_lock_irqsave (& _completion_lock );
74+ if (RT_COMPLETION_FLAG ( completion ) != RT_COMPLETED )
6975 {
7076 /* only one thread can suspend on complete */
71- RT_ASSERT (rt_list_isempty ( & ( completion -> suspended_list )) );
77+ RT_ASSERT (RT_COMPLETION_THREAD ( completion ) == RT_NULL );
7278
7379 if (timeout == 0 )
7480 {
@@ -81,40 +87,43 @@ rt_err_t rt_completion_wait(struct rt_completion *completion,
8187 thread -> error = RT_EOK ;
8288
8389 /* suspend thread */
84- rt_thread_suspend_with_flag (thread , RT_UNINTERRUPTIBLE );
85- /* add to suspended list */
86- rt_list_insert_before (& (completion -> suspended_list ),
87- & (thread -> tlist ));
88-
89- /* current context checking */
90- RT_DEBUG_NOT_IN_INTERRUPT ;
91-
92- /* start timer */
93- if (timeout > 0 )
90+ result = rt_thread_suspend_with_flag (thread , RT_UNINTERRUPTIBLE );
91+ if (result == RT_EOK )
9492 {
95- /* reset the timeout of thread timer and start it */
96- rt_timer_control (& (thread -> thread_timer ),
97- RT_TIMER_CTRL_SET_TIME ,
98- & timeout );
99- rt_timer_start (& (thread -> thread_timer ));
93+ /* add to suspended thread */
94+ completion -> susp_thread_n_flag = RT_COMPLETION_NEW_STAT (thread , RT_UNCOMPLETED );
95+
96+ /* current context checking */
97+ RT_DEBUG_NOT_IN_INTERRUPT ;
98+
99+ /* start timer */
100+ if (timeout > 0 )
101+ {
102+ /* reset the timeout of thread timer and start it */
103+ rt_timer_control (& (thread -> thread_timer ),
104+ RT_TIMER_CTRL_SET_TIME ,
105+ & timeout );
106+ rt_timer_start (& (thread -> thread_timer ));
107+ }
108+ /* enable interrupt */
109+ rt_spin_unlock_irqrestore (& _completion_lock , level );
110+
111+ /* do schedule */
112+ rt_schedule ();
113+
114+ /* thread is waked up */
115+ result = thread -> error ;
116+
117+ level = rt_spin_lock_irqsave (& _completion_lock );
100118 }
101- /* enable interrupt */
102- rt_spin_unlock_irqrestore (& (completion -> spinlock ), level );
103-
104- /* do schedule */
105- rt_schedule ();
106-
107- /* thread is waked up */
108- result = thread -> error ;
109-
110- level = rt_spin_lock_irqsave (& (completion -> spinlock ));
111119 }
112120 }
113- /* clean completed flag */
114- completion -> flag = RT_UNCOMPLETED ;
121+
122+ /* clean completed flag & remove susp_thread on the case of waking by timeout */
123+ completion -> susp_thread_n_flag = RT_COMPLETION_NEW_STAT (RT_NULL , RT_UNCOMPLETED );
115124
116125__exit :
117- rt_spin_unlock_irqrestore (& ( completion -> spinlock ) , level );
126+ rt_spin_unlock_irqrestore (& _completion_lock , level );
118127
119128 return result ;
120129}
@@ -128,35 +137,33 @@ RTM_EXPORT(rt_completion_wait);
128137void rt_completion_done (struct rt_completion * completion )
129138{
130139 rt_base_t level ;
140+ rt_err_t error ;
141+ rt_thread_t suspend_thread ;
131142 RT_ASSERT (completion != RT_NULL );
132143
133- if (completion -> flag == RT_COMPLETED )
144+ level = rt_spin_lock_irqsave (& _completion_lock );
145+ if (RT_COMPLETION_FLAG (completion ) == RT_COMPLETED )
146+ {
147+ rt_spin_unlock_irqrestore (& _completion_lock , level );
134148 return ;
149+ }
135150
136- level = rt_spin_lock_irqsave (& (completion -> spinlock ));
137- completion -> flag = RT_COMPLETED ;
138-
139- if (!rt_list_isempty (& (completion -> suspended_list )))
151+ suspend_thread = RT_COMPLETION_THREAD (completion );
152+ if (suspend_thread )
140153 {
141154 /* there is one thread in suspended list */
142- struct rt_thread * thread ;
143-
144- /* get thread entry */
145- thread = rt_list_entry (completion -> suspended_list .next ,
146- struct rt_thread ,
147- tlist );
148155
149156 /* resume it */
150- rt_thread_resume (thread );
151- rt_spin_unlock_irqrestore (& (completion -> spinlock ), level );
152-
153- /* perform a schedule */
154- rt_schedule ();
155- }
156- else
157- {
158- rt_spin_unlock_irqrestore (& (completion -> spinlock ), level );
157+ error = rt_thread_resume (suspend_thread );
158+ if (error )
159+ {
160+ LOG_D ("%s: failed to resume thread" , __func__ );
161+ }
159162 }
163+
164+ completion -> susp_thread_n_flag = RT_COMPLETION_NEW_STAT (RT_NULL , RT_COMPLETED );
165+
166+ rt_spin_unlock_irqrestore (& _completion_lock , level );
160167}
161168RTM_EXPORT (rt_completion_done );
162169
0 commit comments