<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 したときの図

:::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 関数の実装を見よ。

## 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 をして共有メモリをユーザー空間にマップする。
カーネル側の処理を詳しく見ていく。
カーネル側では以下のようなデータ構造が作成される。

[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) データでリングバッファを形成している。

:::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) である。