---
# System prepended metadata

title: ghOStFS
tags: [ghOSt]

---

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