コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2020年10月5日 >>> 2020年10月5日
link もっと後

2020年10月5日

Zephyr OSで遊ぼう その18 - SMP対応の準備、コンテキストスイッチの実装、後編3、プリエンプション

目次: Zephyr

前回はRISC-Vの2つあるコンテキストスイッチのうち、明示的なコンテキストスイッチを実装しました。今回はもう一方のプリエンプションを実装します。

対応方針(再掲)

従来と新形式のコンテキストスイッチで大きく異なるのは、下記の要素です。

明示的コンテキストスイッチ 従来 新形式
割り込まれた処理の返り値 設定必要(thread->arch.swap_return_value) 設定不要(do_swap() がやってくれる)
切り替え元スレッド _kernel.cpu[0].current a1レジスタ(引数old_thread->switch_handle)
切り替え先スレッド _kernel.ready_q.cache a0レジスタ(引数new_thread->switch_handle)

プリエンプション 従来 新形式
割り込まれた処理の返り値 設定必要(thread->arch.swap_return_value) 設定不要(do_swap() がやってくれる)
切り替え元スレッド _kernel.cpu[0].current _kernel.cpu[n].current(※)
切り替え先スレッド _kernel.ready_q.cache z_get_next_switch_handle() の返り値

(※)初めは切り替え元スレッドですが、z_get_next_switch_handle() を呼ぶと、切り替え先のスレッドに変わります。

割り込まれた処理の返り値

明示的プリエンプションと共通の部分のため、改めて直す必要はないです。

切り替え元/切り替え先スレッド

かなり処理が変わるため、#ifdefだとごちゃごちゃしてしまいます。スレッド取得の専用マクロを作ります。

切り替え元、切り替え先スレッドの取得

// zephyr/arch/riscv/core/isr.S

/*
 * xcpu: pointer of _kernel.cpus[n]
 * xold: (result) old thread
 * xnew: (result) next thread to schedule
 *
 * after this function a0 is broken
 */
.macro z_riscv_get_next_switch_handle xcpu, xold, xnew
#ifdef CONFIG_USE_SWITCH
	addi sp, sp, -RV_REGSIZE*2               //★新たな処理★
	RV_OP_STOREREG ra, RV_REGSIZE(sp)
	addi a0, sp, 0                           //★スタックの先頭へのポインタを第一引数old_threadとする★
	jal ra, z_arch_get_next_switch_handle    //★(2) この関数内で _currentがnew_threadに設定される★
	addi xnew, a0, 0                        //★a0が返り値、切り替え先のスレッドが入っている★
	RV_OP_LOADREG xold, 0(sp)               //★スタック先頭に切り替え元のスレッドが入っている★
	RV_OP_LOADREG ra, RV_REGSIZE(sp)
	addi sp, sp, RV_REGSIZE*2
#else
	/* Get pointer to _kernel.current */                           //★従来処理★
	RV_OP_LOADREG xold, _kernel_offset_to_current(xcpu)          //★切り替え元スレッド★

	RV_OP_LOADREG xnew, _kernel_offset_to_ready_q_cache(xcpu)    //★切り替え先スレッド★
#endif
.endm


// zephyr/arch/riscv/core/thread.c

#ifdef CONFIG_USE_SWITCH
void *z_arch_get_next_switch_handle(struct k_thread **old_thread)
{
	*old_thread =  _current;    //★スタックの先頭に現在のスレッド(= 切り替え元のスレッド)を保存★

	return z_get_next_switch_handle(*old_thread);
}
#endif

わざわざスタックのポインタを経由して書き込むなんてややこしいことをせず、RV_OP_LOADREG xold, _kernel_offset_to_current(xcpu) で良いのでは?と思うかもしれませんが、z_arch_get_next_switch_handle() の呼び出しでどのレジスタが壊れるかわかりませんから、結局 xoldをスタックに退避する必要があります。

明示的コンテキストスイッチと処理を共有しているため、ちょっとわかりにくいですが、プリエンプションの中心となる処理はこの辺りです。

プリエンプション処理の差分

// zephyr/arch/riscv/core/isr.S

 #ifdef CONFIG_PREEMPT_ENABLED
-	/*
-	 * Check if we need to perform a reschedule
-	 */
-
-	/* Get pointer to _kernel.current */
-	RV_OP_LOADREG t2, _kernel_offset_to_current(t1)
-
 	/*
 	 * Check if next thread to schedule is current thread.
 	 * If yes do not perform a reschedule
 	 */
-	RV_OP_LOADREG t3, _kernel_offset_to_ready_q_cache(t1)
+	z_riscv_get_next_switch_handle t1, t2, t3
 	beq t3, t2, no_reschedule
+
+#ifdef CONFIG_USE_SWITCH
+	/* Set old thread to t1 */
+	addi t1, t2, 0             //★(1) t1レジスタにold_threadを設定する★
+#endif
+

前回決めたとおり、合流地点(reschedule)に辿り着く前に切り替え元(old_thread)、切り替え先スレッド(new_thread)を取得し _currentにnew_threadを設定し, t1レジスタにold_threadを設定します。

処理 (1) でnew_threadを _currentに設定していて、処理 (2) でold_threadをt1レジスタに設定してから、rescheduleに到達します。プリエンプション処理のすぐ後にrescheduleラベルがあるので、ジャンプは不要です。

とても長くなってしまいましたが、新しい形式のコンテキストスイッチを実装できました。苦労の割に動作の見た目は何も変わりませんが、本命のSMP対応に活用するためなので我慢です。

編集者:すずき(2023/09/24 12:09)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2020年10月5日 >>> 2020年10月5日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<10>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年4月25日
    すずき (04/26 16:49)
    「[AVIFの変換] AVIFが読めないアプリケーションがたまにあるので、AVIF(AV1 Image File Format)...」
  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/26 16:49