<style> u { text-decoration-color: gray; text-decoration-style: wavy; /* 波線 */ } </style> # ghOStFS ghOSt カーネルは cgroups のように sysfs に専用のファイルシステムを作り、疑似ファイルなどを介してカーネルと agent のやり取りを実現している。ここでは、そのファイルシステムの使い方についてまとめる。 # マウントポイント /sys/fs/ghost ghOStFS のマウントポイントは /sys/fs/ghost である。 OS起動時にはまだマウントされていないので、以下のコマンドで ghOStFS をマウントする。 ``` $ sudo mount --source ghost --target /sys/fs/ghost -t ghost ``` 最初、ディレクトリには ctl と version という2つのファイルが置いてある。 ``` $ ls /sys/fs/ghost ctl version ``` $\sf version$ は読み出し専用のファイルで、ghOSt ABI のバージョンを読み出すことができる。 ghOSt はカーネル側とユーザー側が協調して動作するスケジューラのため、互いに異なるインターフェースを参照しないようにする必要がある。そのために、ユーザー側はこのファイルを読み出すことでカーネル側の ABI バージョンを知り、自身が対応した ABI を使用しているかを確認できるようになっているのだ。 ``` $ cat /sys/fs/ghost/version 83 ``` $\tt ctl$ は書き込み専用のファイルで、ここへ以下のようなコマンドを書き込むことでEnclaveを作成できる。 $$ \texttt{create <id> <abi_version> <extra_opts>} $$ $\tt id$ には enclave の番号を指定する。その時点でシステムに存在していない数値を指定する。 $\sf abi\_version$ には ABI バージョンを指定する。カーネル側が対応している ABI バージョンが複数ある場合もあるらしいので、その中のどれかを指定する。 このコマンドをctlへ書き込み後、正常に終了すれば /sys/fs/ghost/enclave_/\<id> というディレクトリが作成される。このディレクトリを介してEnclaveとやり取りを行う。 :::warning これらのファイルへ読み書きをしたときに呼び出されるカーネル側の処理は [top_dirtab](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost_core.c#L182-L194) という変数にまとめられている。 ```c static struct gf_dirent top_dirtab[] = { { .name = "ctl", .mode = 0660, .ops = &gf_ops_top_ctl, }, { .name = "version", .mode = 0444, .ops = &gf_ops_top_version, }, {0} }; ``` これらの引数をたどっていくことで、読み書きの動作に対応したカーネル側の処理を見つけることができる。例えば ctl への書き込みに対応するカーネル側の処理は [gf_top_ctl_write](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost_core.c#L140-L162) 関数である。 ::: # enclave の作成方法 実際に enclave を作成するまでの処理は以下のようになる。 ```bash $ cat /sys/fs/ghost/version # ① abi version の確認 83 $ sudo sh -c "echo create 1 83 > /sys/fs/ghost/ctl" # ② enclave の作成 $ ls /sys/fs/ghost # ③ 新しくenclave_1というディレクトリが作成されていることを確認 ctl enclave_1 version $ ls /sys/fs/ghost/enclave_1/ # ④ enclaveディレクトリの中身の確認 abi_version cpumask live_dangerously tasks agent_online ctl runnable_timeout wake_on_waker_cpu commit_at_tick deliver_agent_runnability status cpu_data deliver_cpu_availability switchto_disabled cpulist deliver_ticks sw_regions ``` :::info 基本的に ghost-kernel や ghost-userspace にはドキュメントが存在しないが、ghOStFSに関するドキュメントだけは存在する ➙ [ghost-userspace/docs/ghostfs.md](https://github.com/google/ghost-userspace/blob/main/docs/ghostfs.md) ::: # enclave ディレクトリ 番号 n で enclave を作成すると /sys/fs/ghost/enclave_n のようなディレクトリが作成される。 この中のファイルに読み書きなどを行うことで enclave の情報を取得したり、制御をしたりできる。 :::warning このディレクトリに含まれるファイルは [`enclave_dirtab`](https://github.com/google/ghost-kernel/blob/b948b132880c21c187eae8b0d2bf83b4d3eb80fc/kernel/sched/ghost.c#L8005-L8092) で定義されている。 ファイル操作時のコールバック関数も一緒に定義されているので、この部分を見てみるとよい。例えば、tasksファイルへファイル操作を行ったときに呼び出されるコールバック関数は [`gf_ops_e_tasks`](https://github.com/google/ghost-kernel/blob/b948b132880c21c187eae8b0d2bf83b4d3eb80fc/kernel/sched/ghost.c#L7967-L7972) で定義されている。 ::: enclave ディレクトリは以下のような要素を含んでいる。 ``` $ ls -l /sys/fs/ghost/enclave_1/ total 0 -r--r--r-- 1 root root 0 11月 22 22:02 abi_version -rw-rw-r-- 1 root root 0 11月 22 12:41 agent_online -rw-rw-r-- 1 root root 0 11月 22 22:02 commit_at_tick -rw-rw---- 1 root root 24576 11月 22 12:41 cpu_data -rw-rw-r-- 1 root root 0 11月 22 22:02 cpulist -rw-rw-r-- 1 root root 0 11月 22 22:02 cpumask -rw-rw-r-- 1 root root 0 11月 22 12:41 ctl -rw-rw-r-- 1 root root 0 11月 22 22:02 deliver_agent_runnability -rw-rw-r-- 1 root root 0 11月 22 22:02 deliver_cpu_availability -rw-rw-r-- 1 root root 0 11月 22 22:02 deliver_ticks -rw-rw-r-- 1 root root 0 11月 22 22:02 live_dangerously -rw-rw-r-- 1 root root 0 11月 22 22:02 runnable_timeout -r--r--r-- 1 root root 0 11月 22 22:02 status -rw-rw-r-- 1 root root 0 11月 22 22:02 switchto_disabled dr-xr-xr-x 2 root root 0 11月 22 12:41 sw_regions -rw-rw-rw- 1 root root 0 11月 22 22:02 tasks -rw-rw-r-- 1 root root 0 11月 22 22:02 wake_on_waker_cpu ``` ## abi_version(0444) カーネル側のghOStのバージョンが書かれている。 ## agent_online 読み書き可能なファイル。 <u>複数の読み出し用 open は可能で、書き込み用に open する場合は単一スレッドのみ、というような排他制御を行っている</u>。 :::warning Readers-Writeロックに似ているなと思ったけど、あるスレッドが書き込みで open しているときに、別のスレッドが読み出し用に open することも可能なので少し違う。 ::: 読み出しデータは "0" または "1" のどちらか。"0" のときは、この enclave に対応するユーザー側のアプリケーション(スケジューラのこと)がまだ存在していないことを表す。"1" のときは enclave に対応したスケジューラが稼働中であることを示す(agent が接続されていることを示すファイルなので agent_online という名前がつけられている)。 "1" の状態で書き込み用に open すると失敗する。 "0" の状態で書き込み用に open すると成功し、その後値は "1" を示すようになる。 なお、書き込みで開いたからといって、このファイルに write しようとすると失敗するので注意。あくまでユーザー側の準備ができたことをカーネル側に知らせるために使用する。 enclave を作成するとカーネル側に enclave 用のデータ構造が生成されるが、それに対応するデータ構造をユーザー側にも作る必要がある。また、1つの enclave に対して複数の対応するデータ構造がユーザー空間に作られないように、排他処理のようなことも行っているのだ。 スケジューラプロセスが書き込み用に open したときの図 ![FEACDABF-8F4F-45C9-880B-633CCD01AD35](https://hackmd.io/_uploads/S1kw35JEa.jpg) :::success :dart: このファイルで読み出した値は、カーネル側の [ghost_enclave.agent_online](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L205) の値に対応する。 :dart: ghost-userspace において、このファイルを書き込みでopenする処理は [LocalEnclave::AdvertiseOnline()](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/enclave.cc#L671-L679) で行われる。これは [Enclave::Ready() の最後](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/enclave.cc#L98)に呼び出されている。 ::: ## ctl(0664) 読み書き(+ioctl)可能なファイル。 読み出し時には enclave の番号が出力される。 ghost の ctl と同様、コマンドを書き込むことでenclaveを制御できる。 コマンドには以下のものがある。 ||| |-|-| | destroy | enclave を削除するコマンド。 | | create sw_region \<id\> \<numa_node> | SW(Status Word)領域を作成するコマンド。このコマンドが成功すると enclave_n/sw_regions/sw_\<id> というROなファイルが作成される。 | become agent \<cpu\> \<qfd\> | agent を enclave に登録するコマンド。agent 自らがこの書き込みを行う。この書き込みに対するカーネル側の処理は [ctl_become_agent](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L7515-L7589) である。 | discover tasks | enclave に属している全てのタスクに対し TASK_NEW メッセージを発行するように要請するコマンド。 | 各コマンドを書き込んだときに実行されるカーネル側の処理は [**gf_ctl_write**](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L7697-L7735) 関数の実装を見ることでわかる。 また ioctl のときの挙動も実装されていて、それに対応するカーネル側の処理は **gf_ctl_ioctl** 関数の実装を見るとわかる。 ||| |-|-| | **SET_DEFAULT_QUEUE** | デフォルトキューを設定する。カーネルは enclave.def_q に指定したキューを設定する。 | | **ASSOC_QUEUE** | ghOSt スレッドを特定のキューに関連付ける。この処理が完了した後は、その ghOSt スレッドに関するメッセージはそのキューにプッシュされる。 | ※ GHOST_IOC_ というプレフィックスは省略している。 ※ IOCに関して詳しくは後半でまとめた:[リンク](#enclave_n/ctlへのIOCTL) ## cpumask enclave が管理しているCPUをビットマスクでやりとりする読み書き可のファイル。 読み出し時には enclave が管理しているCPU情報を得られる。例えばCPU0とCPU1を管理する enclave の場合、読み出しの結果は以下のようになる。 ``` $ cat /sys/fs/ghost/enclave_1/cpumask 03 ``` CPUマスクを書き込むことで enclave が管理するCPUの集合を変更することができる。変更は、元の管理CPUが含まれていてもいいし、含まれていなくてもいい。詳しくはカーネル側で呼ばれる ghost_enclave_set_cpus 関数の実装を見よ。 ![8B55D46D-3877-47B5-8290-3B965E65B823](https://hackmd.io/_uploads/BJj9bj1E6.jpg) ## cpulist cpumask のASCII文字版。 ``` $ cat /sys/fs/ghost/enclave_1/cpulist 0-1,4 ``` ## cpu_data ghost_txnなどのカーネルとagentで共有されるデータを集めて、共有メモリとして提供したもの。agentはこのファイルをmmapすると、共有メモリにアクセスできるようになる。agent ➝ カーネル のトランザクションをするためなどに使われる。 ## deliver_agent_runnability 読み書き可。 [ghost_enclave.deliver_agent_runnability](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L198) の値を設定するファイル。 読み出し時は、このメンバの値を "0" または "1" で出力する。 書き込み時は、"0" または "1" を書き込むことで、書き込んだ値をメンバの値に設定する。 デフォルトは、"0"。 これが "1" のときは **MSG_CPU_AGENT_BLOCKED** メッセージと **MSG_CPU_AGENT_WAKEUP** メッセージが送信されるようになる。 ## deliver_cpu_availability 読み書き可。 [ghost_enclave.deliver_cpu_availability](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L199) の値を設定するファイル。 読み出し時は、このメンバの値を "0" または "1" で出力する。 書き込み時は、"0" または "1" を書き込むことで、書き込んだ値をメンバの値に設定する。 デフォルトは、"0"。 これが "1" のときは **MSG_CPU_AVAILABLE** メッセージと **MSG_CPU_BUSY** メッセージが送信されるようになる。 ## deliver_ticks 読み書き可。 [ghost_enclave.deliver_ticks](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L200) に関するやり取りを行うファイル。 読み出し時は現在の値が "0" か "1" で出力される。 書き込み時は "0" か "1" を書き込む。 この値は、タイマー割り込み時に **MSG_CPU_TICK** メッセージを発行するかどうかを設定する。 ## commit_at_tick 読み書き可。 [ghost_enclave.commit_at_tick](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L197) に関するファイル。 読み出し時は、このメンバの値を "0" または "1" で出力する。 書き込み時は、"0" または "1" を書き込むことで、書き込んだ値をメンバの値に設定する。 デフォルトは、"0"。 これが "1" のときは commit をシステムコール時にだけではなく、タイマー割り込み時にも行うようになる。この機能は ghost-userspace のスケジューラではあまり使われていないっぽい。 ## live_dangerously 読み書き可。 [ghost_enclave.live_dangerously](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L201) に関するファイル。 このメンバはデッドロックの回避のために使用される。 ## tasks ファイル操作に対応するカーネル側の処理は [gf_ops_e_tasks](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L8151-L8156) で定義されている。 ```c static struct kernfs_ops gf_ops_e_tasks = { .open = gf_e_open, .release = gf_e_release, .seq_show = gf_tasks_show, .write = gf_tasks_write, }; ``` 読み出し時は**現在 enclave が管理しているタスクの pid の一覧**が表示される。 書き込み時は、**新しくタスクを enclave の管理化に置く**ことができる。CFSなどの他のポリシーで管理されるスレッドをghOStスレッドに変えるときなどは、ここに pid を書き込むことによって行う。 書き込みとして許されているのは、**0, pid, gtid** の3つである。0を書き込むときは current が選択されるので、<u>自身を ghOSt スレッドにしたいときは 0 を書き込めばいい</u>。 結局、内部で行われている処理は `sched_setscheduler(.., SCHED_GHOST, ..)` である。 :::warning :dart: 実装では **sched_setscheduler システムコールを直接呼び出して ghOSt ポリシーに入ることは許されていない**。必ず enclave を作成したあとに、このファイルへの書き込みによって ghOSt ポリシーへ移動する必要がある。 詳しくは [ghost_setscheduler 実装内のコメント](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost_core.c#L571-L575)を参照。 ::: # enclave_n/ctlへのIOCTL enclave ディレクトリの ctl ファイルへの ioctl システムコールについて詳しく見ていく。 ioctl システムコールは第2引数に指定する値によって処理を変えることができる。第3引数以降は、第2引数で指定された命令ごとに異なるデータ構造を持っていて良い。 第2引数に指定する値は GHOST_IOC_XXX というマクロで以下のように定義されている([ソースコード](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L160-L171))。 ```c #define GHOST_IOC_NULL _IO('g', 0) #define GHOST_IOC_SW_GET_INFO _IOWR('g', 1, struct ghost_ioc_sw_get_info) #define GHOST_IOC_SW_FREE _IOW('g', 2, struct ghost_sw_info) #define GHOST_IOC_CREATE_QUEUE _IOWR('g', 3, struct ghost_ioc_create_queue) #define GHOST_IOC_ASSOC_QUEUE _IOW('g', 4, struct ghost_ioc_assoc_queue) #define GHOST_IOC_SET_DEFAULT_QUEUE _IOW('g', 5, struct ghost_ioc_set_default_queue) #define GHOST_IOC_CONFIG_QUEUE_WAKEUP _IOW('g', 6, struct ghost_ioc_config_queue_wakeup) #define GHOST_IOC_GET_CPU_TIME _IOWR('g', 7, struct ghost_ioc_get_cpu_time) #define GHOST_IOC_COMMIT_TXN _IOW('g', 8, struct ghost_ioc_commit_txn) #define GHOST_IOC_SYNC_GROUP_TXN _IOW('g', 9, struct ghost_ioc_commit_txn) #define GHOST_IOC_TIMERFD_SETTIME _IOWR('g', 10, struct ghost_ioc_timerfd_settime) #define GHOST_IOC_RUN _IOW('g', 11, struct ghost_ioc_run) ``` 論文で紹介されている agent ➝ kernel のシステムコールで紹介されていたAGENT_INIT() や TXN_CREATE() なども ioctl で実現されている。 ctl ファイルへの ioctl が発行されたときに実行されるカーネル側の関数は [gf_ctl_ioctl](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L7778-L7805) であり、そのメイン処理部分は [enclave_ioctl](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L7737-L7776) 関数で行われる。enclave_ioctl 関数の実装は以下のようになっていて、case文によって呼び出す処理を命令ごとに振り分けている。 ```c static long enclave_ioctl(struct ghost_enclave *e, unsigned int cmd, unsigned long arg) { // cmdは第2引数で渡された値 switch (cmd) { case GHOST_IOC_NULL: return 0; case GHOST_IOC_SW_GET_INFO: return ghost_sw_get_info(e, (struct ghost_ioc_sw_get_info __user *)arg); case GHOST_IOC_SW_FREE: return ghost_sw_free(e, (void __user *)arg); ... return -ENOIOCTLCMD; } ``` 以下、ioctlで使われるcmdに指定するマクロごとに処理を分けてまとめる。 ## GHOST_IOC_CREATE_QUEUE メッセージキューを作成する命令。 引数の型は ghost_ioc_create_queue 構造体で定義されている。 ```c struct ghost_ioc_create_queue { int elems; int node; int flags; // 現在フラグは未実装(常に0でいい) ulong mapsize; }; ``` メッセージの要素数・NUMAノードの情報・フラグ、の3つである。 カーネルはこれらの情報を元に、カーネル空間に ghost_queue などのデータ構造を作成する。作成したデータ構造のうち、<u>ユーザー空間にマップする領域を無名ファイルとして作成し、その無名ファイルのfdを返す</u>。agent はその返り値を元に mmap をして共有メモリをユーザー空間にマップする。 カーネル側の処理を詳しく見ていく。 カーネル側では以下のようなデータ構造が作成される。 ![](https://hackmd.io/_uploads/HywiaxLGa.jpg) [ghost_ring](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L505-L517) の構造は以下のように可変長の [ghost_msg](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L252-L257) データでリングバッファを形成している。 ![F38F9A4D-7D73-4948-A94A-B59D657A36E1](https://hackmd.io/_uploads/HybGttjVT.jpg) :::info ここでの nelems は、ghost_ring.msgs のサイズを決定するときに使われる。 ghost_msg 構造体は可変長であるが、ヘッダサイズは8バイトで固定されている。 nelems はヘッダサイズのみを考えたときの要素数で考えられている。 ::: カーネル側で呼び出される関数は[ghost_create_queue](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L3411-L3505)である。 ユーザー側のAPIは[Ghost::CreateQueue](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/ghost.h#L140-L149)である。 ## GHOST_IOC_ASSOC_QUEUE タスクとメッセージキューの関連付けを行うシステムコール。処理が成功すると、タスクが発するメッセージは関連付けられたキューに対してプッシュされるようになる。 引数で渡されるデータ構造は [ghost_ioc_assoc_queue](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L106-L111) である。 ```c struct ghost_ioc_assoc_queue { int fd; struct ghost_msg_src src; uint32_t barrier; int flags; // 現在未実装(故に常に0) }; ``` 各フィールドの説明は以下の通り。 ||| |-|-| | fd | **関連付けを行うメッセージキューのfd**を指定する(メッセージキューはファイルとしてマップしているので、それに対応するfdがあるはず)。 | src | 関連付けを行うタスクを指定する。とはいっても、agentスレッドを指定することはできないので([ソースコード](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L3757-L3759))、src.type は GHOST_TASK であり、taskのgtidを指定してあげる。 | barrier | ghOStスレッドの最新のbarrierを指定する。最新のbarrierとは、最も直近で受け取ったメッセージに書かれていたbarrierの値である。もし、この値がカーネル側の値よりも古かった場合、このシステムコールは失敗する。このようにして、**以前のキューに未処理のメッセージが残されている場合、システムコールが失敗する**ようになっている。 | flags | 今は何も設定できない。 カーネル側で呼び出される関数は [ghost_associate_queue](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L3730-L3849) である。 ユーザー側のAPIは [Ghost::AssociateQueue](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/ghost.h#L184-L198) である。 ## GHOST_IOC_CONFIG_QUEUE_WAKEUP キューにメッセージが届いたときに起こすagentを設定するシステムコール。 設定できるagentの数は [GHOST_MAX_WINFO](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L64) までとなっており、今の実装では2つまでとなっている。 引数に渡すデータ構造([ghost_ioc_config_queue_wakeup](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L117-L122) 構造体)は以下の通り。 ```c #define GHOST_MAX_WINFO 2 struct ghost_agent_wakeup { int cpu; int prio; }; struct ghost_ioc_config_queue_wakeup { int qfd; // キューに対応するfd struct ghost_agent_wakeup *w; // 新しく設定するCPUの番号リスト int ninfo; // w(⇡)が指すリストの要素数 int flags; // 現在未実装 }; ``` カーネル側で呼ばれる関数は [ghost_config_queue_wakeup](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L4025-L4112) である。 ユーザー側のAPIは [Ghost::ConfigQueueWakeup](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/ghost.h#L161-L182) である。 関数の処理を見てみる。 1. 引数で渡された `w` のリストを [`ghost_queue.notifier`](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L2082) に設定する。 2. 対応するagentを起こす(保留されたメッセージがある場合に備えて)。 ここで、agentを起こすときの処理の流れも見ていく。agentを起こすための関数は `ghost_wake_agent_on(cpu)` で定義されている。 1. 引数 `cpu` に対応するランキュー内のいくつかのメンバを確認しに行く。 2. need_resched フラグを立てる(agentタスクの優先度はいかなるタスクよりも高いので、次回 schedule が呼ばれたときに自動で agent に処理が切り替わる、という作戦)。 ## GHOST_IOC_COMMIT_TXN トランザクションをコミットするシステムコール。 引数に渡されるデータ構造は[ghost_ioc_commit_txn](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L129-L137)である。この構造体はCPUリストを表現するために使われ、コミットするCPUの集合を一度に設定することができる。 ```c struct ghost_ioc_commit_txn { #ifdef __KERNEL__ ulong *mask_ptr; // カーネル側に見えているメンバ #else cpu_set_t *mask_ptr; // ユーザー側に見えているメンバ #endif uint32_t mask_len; // cpuマスクの長さ int flags; // 現在使用可能なフラグはない。 }; ``` カーネル側で呼び出される関数は [ioctl_ghost_commit_txn](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L6828-L6964) である。 ## GHOST_IOC_SET_DEFAULT_QUEUE デフォルトのキューを設定するシステムコール。 :::success デフォルトのキューとは、**スレッドがghOStスレッドになったときに、最初に関連付けられるメッセージキュー**のこと(詳しくは [ghost_prep_task](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L3129) の実装などを見ると分かる)。 ::: 具体的な処理としては、カーネル側の [ghost_enclave.def_q](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/sched.h#L178) の値を設定する。 引数のデータ構造([ghost_ioc_set_default_queue](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/include/uapi/linux/ghost.h#L113-L115) 構造体)は以下の通り。 ```c struct ghost_ioc_set_default_queue { int fd; // 開いているメッセージキューのfd }; ``` カーネル側で呼び出される関数は [ghost_set_default_queue](https://github.com/google/ghost-kernel/blob/edd5f9490d82df24c16f90a62f7be05c6c389867/kernel/sched/ghost.c#L3851-L3886) である。 ユーザー側で呼び出される関数は [Ghost::SetDefaultQueue](https://github.com/google/ghost-userspace/blob/9ca0a1fb6ed88f0c4b0b40a5a35502938efa567f/lib/ghost.h#L200-L206) である。