RT-Thread - Scheduler

RT-Thread 2018-11-15 1.1k

File: scheduler.c

  • components.c 中 的 rtthread_startup() 首先呼叫 rt_system_scheduler_init() 初始化 scheduler
  • rtthread_startup() 的最後呼叫 rt_system_scheduler_start() 開始 scheduler

初始化 scheduler#

功能 回傳值
初始化 scheduler void
102
103
104
105
106
107
108
109
110
/**
* @ingroup SystemInit
* This function will initialize the system scheduler
*/
void rt_system_scheduler_init(void)
{
register rt_base_t offset;

rt_scheduler_lock_nest = 0;
  • rt_scheduler_lock_nest 為 scheduler 的鎖,在進入 critical region 時會 ++,離開時會 --
111
112
113
114
115
116
117
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
RT_THREAD_PRIORITY_MAX));

for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
{
rt_list_init(&rt_thread_priority_table[offset]);
}
  • RT_THREAD_PRIORITY_MAX 根據不同的 BSP 可設定為不同的值,如 256;即優先級為 0~255,數字越小越等級越高
  • 初始化 rt_thread_priority_table
118
119
rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
rt_current_thread = RT_NULL;
  • 設定當前的優先級為最低,及空。
120
121
122
123
124
125
126
127
128
129
130
    /* initialize ready priority group */
rt_thread_ready_priority_group = 0;

#if RT_THREAD_PRIORITY_MAX > 32
/* initialize ready table */
rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table));
#endif

/* initialize thread defunct */
rt_list_init(&rt_thread_defunct);
}
  • 初始化 rt_thread_ready_priority_grouprt_thread_defunct

啟動 scheduler#

  • 此函數會找到一個 priorty 最高的 thread 並執行
功能 回傳值
啟動 scheduler void
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
* @ingroup SystemInit
* This function will startup scheduler. It will select one thread
* with the highest priority level, then switch to it.
*/
void rt_system_scheduler_start(void)
{
register struct rt_thread *to_thread;
register rt_ubase_t highest_ready_priority;

#if RT_THREAD_PRIORITY_MAX > 32
register rt_ubase_t number;

number = __rt_ffs(rt_thread_ready_priority_group) - 1;
highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#else
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#endif
  • 使用 rt_ffs 來尋找 priority 最高的鏈結
153
154
155
156
157
158
159
160
161
162
163
164
    /* get switch to thread */
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);

rt_current_thread = to_thread;

/* switch to new thread */
rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

/* never come back */
}
  • 找到該鏈的第一顆,context switch 至該 thread

Scheduler#

  • 呼叫此函式,系統會重新計算所有 thread 的 priority,如果存在更高的(與呼叫此函式的 thread 比較),系統將會 switch 至該 thread。
功能 回傳值
執行一次調度 void
173
174
175
176
177
178
179
180
181
182
183
184
/**
* This function will perform one schedule. It will select one thread
* with the highest priority level, then switch to it.
*/
void rt_schedule(void)
{
rt_base_t level;
struct rt_thread *to_thread;
struct rt_thread *from_thread;

/* disable interrupt */
level = rt_hw_interrupt_disable();
  • 首先將中斷關閉
185
186
187
188
189
190
191
192
193
194
195
196
197
    /* check the scheduler is enabled or not */
if (rt_scheduler_lock_nest == 0)
{
register rt_ubase_t highest_ready_priority;

#if RT_THREAD_PRIORITY_MAX <= 32
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#else
register rt_ubase_t number;

number = __rt_ffs(rt_thread_ready_priority_group) - 1;
highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#endif
  • 檢查鎖的狀態,並找到 priority 最高的鍊
198
199
200
201
/* get switch to thread */
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);
  • 找到該鏈的第一顆
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
        /* if the destination thread is not the same as current thread */
if (to_thread != rt_current_thread)
{
rt_current_priority = (rt_uint8_t)highest_ready_priority;
from_thread = rt_current_thread;
rt_current_thread = to_thread;

RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));

/* switch to new thread */
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
("[%d]switch to priority#%d "
"thread:%.*s(sp:0x%p), "
"from thread:%.*s(sp: 0x%p)\n",
rt_interrupt_nest, highest_ready_priority,
RT_NAME_MAX, to_thread->name, to_thread->sp,
RT_NAME_MAX, from_thread->name, from_thread->sp));

#ifdef RT_USING_OVERFLOW_CHECK
_rt_scheduler_stack_check(to_thread);
#endif

if (rt_interrupt_nest == 0)
{
extern void rt_thread_handle_sig(rt_bool_t clean_state);

rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
(rt_uint32_t)&to_thread->sp);

/* enable interrupt */
rt_hw_interrupt_enable(level);

#ifdef RT_USING_SIGNALS
/* check signal status */
rt_thread_handle_sig(RT_TRUE);
#endif
}
  • 如果找到的 thread 與當前的 thread 不相符,且 rt_interrupt_nest == 0,即這次調度不是在中斷下運作的,直接 switch 至該 thread
  • 最後恢復中斷
239
240
241
242
243
244
245
246
247
248
    else
{
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,
(rt_uint32_t)&to_thread->sp);
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
}
  • 如果 rt_interrupt_nest != 0,即這次調度是在中斷下運作的,則用中斷 switch 至該 thread
  • 最後恢復中斷
249
250
251
252
253
254
255
256
257
258
259
260
        else
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
}
else
{
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
}
  • 如果找到的一樣,或是沒要到鎖,直接開啟中斷,結束調度

插入 thread#

功能 回傳值 *thread
將 thread 插入 list void 欲插入的 thread
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/**
* This function will insert a thread to system ready queue. The state of
* thread will be set as READY and remove from suspend queue.
*
* @param thread the thread to be inserted
* @note Please do not invoke this function in user application.
*/
void rt_schedule_insert_thread(struct rt_thread * thread)
{
register rt_base_t temp;

RT_ASSERT(thread != RT_NULL);

/* disable interrupt */
temp = rt_hw_interrupt_disable();

/* change stat */
thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
  • 首先關閉中斷,及更改 thread 的狀態為 RT_THREAD_READY
283
284
285
/* insert thread to ready list */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
  • 接著呼叫 rt_list_insert_before 將 thread 插到第一顆
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    /* set priority mask */
#if RT_THREAD_PRIORITY_MAX <= 32
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
RT_NAME_MAX, thread->name, thread->current_priority));
#else
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
("insert thread[%.*s], the priority: %d 0x%x %d\n",
RT_NAME_MAX,
thread->name,
thread->number,
thread->number_mask,
thread->high_mask));
#endif

#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] |= thread->high_mask;
#endif
rt_thread_ready_priority_group |= thread->number_mask;

/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
  • 最後恢復中斷

移除 thread#

功能 回傳值 *thread
從 list 中移除 thread void 欲移除的 thread
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/**
* This function will remove a thread from system ready queue.
*
* @param thread the thread to be removed
*
* @note Please do not invoke this function in user application.
*/
void rt_schedule_remove_thread(struct rt_thread *thread)
{
register rt_base_t temp;

RT_ASSERT(thread != RT_NULL);

/* disable interrupt */
temp = rt_hw_interrupt_disable();

#if RT_THREAD_PRIORITY_MAX <= 32
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
RT_NAME_MAX, thread->name,
thread->current_priority));
#else
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
("remove thread[%.*s], the priority: %d 0x%x %d\n",
RT_NAME_MAX,
thread->name,
thread->number,
thread->number_mask,
thread->high_mask));
#endif

/* remove thread from ready list */
rt_list_remove(&(thread->tlist));
  • 先關閉中斷,再呼叫 rt_list_remove 來刪除第一顆
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
{
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] &= ~thread->high_mask;
if (rt_thread_ready_table[thread->number] == 0)
{
rt_thread_ready_priority_group &= ~thread->number_mask;
}
#else
rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
}

/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
  • 如果刪除後,原本的鏈為空,就修改一些參數(在 thread 會討論)
  • 最後開啟中斷