jmp
命令で次の処理に移動する__code
で宣言する__code cbc_read(__code (*next)(int ret)){
struct file *f;
int n;
char *p;
if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0) {
goto next(-1);
}
goto cbc_fileread(f, p, n, next);
}
read
システムコールの例cbc_read_stub
内で必要な引数をcontextから取り出す
__code cbc_read_stub(struct Context* cbc_context, enum Code next) {
goto cbc_read(cbc_context, next);
}
goto
文で呼び出す
void syscall(void)
{
int num;
int ret;
if((num >= NELEM(syscalls)) && (num <= NELEM(cbccodes)) && cbccodes[num]) {
proc->cbc_arg.cbc_console_arg.num = num;
goto (cbccodes[num])(cbc_ret);
}
void syscall(void)
{
int num;
int ret;
if((num >= NELEM(syscalls)) && (num <= NELEM(cbccodes)) && cbccodes[num]) {
proc->cbc_arg.cbc_console_arg.num = num;
goto (cbccodes[num])(cbc_ret);
}
goto trapreturn()
ユーザープログラムにディスパッチするgoto panic()
致命的なエラーとしてOSを止めるgoto err()
システムコールのエラー処理
goto
文を利用する場合はcontextからデータを参照するtype
によって継続先を変更する__code cbc_fileread (struct file *f, char *addr, int n, __code (*next)(int ret))
{
if (f->readable == 0) {
goto next(-1);
}
if (f->type == FD_PIPE) {
goto cbc_piperead(f->pipe, addr, n, next);
}
if (f->type == FD_INODE) {
ilock(f->ip);
proc->cbc_arg.cbc_console_arg.f = f;
goto cbc_readi(f->ip, addr, f->off, n, cbc_fileread1);
}
goto cbc_panic("fileread");
}
cbc_fileread
CodeGearなどは複数のCodeGearの集合となっている
fs.c
やvm.c
などfs.c
のAPIからCodeGearの集合を定義する
typedef struct fs<Type,Impl> {
__code readsb(Impl* fs, uint dev, struct superblock* sb, __code next(...));
__code iinit(Impl* fs, __code next(...));
__code ialloc(Impl* fs, uint dev, short type, __code next(...));
__code iupdate(Impl* fs, struct inode* ip, __code next(...));
__code idup(Impl* fs, struct inode* ip, __code next(...));
__code ilock(Impl* fs, struct inode* ip, __code next(...));
__code iunlock(Impl* fs, struct inode* ip, __code next(...));
__code iput(Impl* fs, struct inode* ip, __code next(...));
....
} fs;
ialloc
関数を書き換えたstruct inode* ialloc (uint dev, short type)
{
readsb(dev, &sb);
for (inum = 1; inum < sb.ninodes; inum++) {
bp = bread(dev, IBLOCK(inum));
dip = (struct dinode*) bp->data + inum % IPB;
if (dip->type == 0) { // a free inode
memset(dip, 0, sizeof(*dip));
...
return iget(dev, inum);
}
brelse(bp);
}
panic("ialloc: no inodes");
}
iget
でポインタを返すstruct inode* ialloc (uint dev, short type)
{
readsb(dev, &sb);
for (inum = 1; inum < sb.ninodes; inum++) {
bp = bread(dev, IBLOCK(inum));
dip = (struct dinode*) bp->data + inum % IPB;
if (dip->type == 0) { // a free inode
memset(dip, 0, sizeof(*dip));
...
return iget(dev, inum);
}
brelse(bp);
}
panic("ialloc: no inodes");
}
for (inum = 1; inum < sb.ninodes; inum++)
に対応する__code allocinode_loopcheck(struct fs_impl* fs_impl, uint inum, struct superblock* sb, __code next(...)){
if( inum < sb->ninodes){
goto allocinode_loop(fs_impl, next(...));
}
char* msg = "failed allocinode...";
struct Err* err = createKernelError(&kernel->cbc_context);
goto err->panic(msg);
}
dip->type == 0)
で継続を分岐させる
__code allocinode_loop(struct fs_impl* fs_impl, uint inum, short type, __code next(...)){
bp = bread(dev, IBLOCK(inum));
dip = (struct dinode*) bp->data + inum % IPB;
if(dip->type == 0){
goto allocinode_loopexit(fs_impl, inum, bp, dip, next(...));
}
brelse(bp);
inum++;
goto allocinode_loopcheck(fs_impl, next(...));
}