今回はsys_pipe()を読む
カーネルのバージョンはlinux-4.5
UNIXで利用できるプロセス間通信の仕組み
###UNIXで使用されているプロセス間通信のざっくり分類
- パイプとFIFO ←今回はココについて書くよ!
- セマフォ
- IPC(systemV)
- メッセージ
- 共有メモリリージョン
- ソケット
- 19章では、ほぼ解説なし?
###パイプ処理にあたり重要な関数
- pipe() ←とりまコレを読む
- popen() ←pipe()を使用してる
- pclose()
- fork()
- close()
- dup2()
- execve()
- dup3()
POSIXでは片方向のパイプしか定義していない
→双方向通信が必要な場合はpipe()を2回行う
##pipe()を読む
pipe()のシステムコールを見つけたくてsys_pipe
でgrepしたらこんなコードが見つかった
SYSCALL_DEFINE1(pipe, int __user *, fildes)
{
return sys_pipe2(fildes, 0);
}
sys_pipe2は arch/x86/entry/syscalls/syscall_32.tbl
331 i386 pipe2 sys_pipe2
にこんな感じで書かれてる
で?どこにsys_pipe2があんの?
gtagsで定義元にジャンプしようとしても"sys_pipe2: tag not found"と言われてしまった
linux-2.6.0ばっかりよんでたのでsys_pipe2でgrepして見つからないと途方にくれてしまう、、、、
実はSYSCALL_DEFINE1(pipe, int __user *, fildes)
の真上にこんな関数がある
これがsys_pipe2の正体っぽい
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{
struct file *files[2];
int fd[2];
int error;
error = __do_pipe_flags(fd, files, flags);
if (!error) {
if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
fput(files[0]);
fput(files[1]);
put_unused_fd(fd[0]);
put_unused_fd(fd[1]);
error = -EFAULT;
} else {
fd_install(fd[0], files[0]);
fd_install(fd[1], files[1]);
}
}
return error;
}
どうやら2.6とは違いsys_*でシステムコールを定義しなくなったらしい
で、このSYSCALL_DEFINEが何なのかについては素晴らしいサイトがあったのでそちらを見てください(丸投げ)
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
を例にザックリ説明すると
属性 | 意味 |
---|---|
SYSCALL_DEFINE2 | 2はシステムコールの引数の数 1,3もあるよ |
pipe2 | システムコール名 sys_システムコール名を定義する |
int __user * | ??? |
fildes | 引数1 |
int, flags | SYSCALL_DEFINEでは型名と引数名を,で区切る |
こんな感じ |
sys_pipe2のザックリ概要のコメントを書いたのがコチラ
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{
struct file *files[2];
int fd[2];
int error;
//flagsを見てerrorかどうか判定とかしてる
error = __do_pipe_flags(fd, files, flags);
if (!error) {
if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
fput(files[0]);
fput(files[1]);
put_unused_fd(fd[0]);
put_unused_fd(fd[1]);
error = -EFAULT;
} else {
fd_install(fd[0], files[0]);
fd_install(fd[1], files[1]);
}
}
return error;
}
このlinuxのsys_pipeですが、xv6のpipe()とっても近い
int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
} else {
write(p[1], "hello world\n", 12);
close(p[0]);
close(p[1]);
}