2018/9/12 勉強会
【画像引用元】What is file descriptor?
ulimit -n
というコマンドで確認できる/etc/security/limits.conf
らへんをいじるsleep 365d > /dev/null &
とか)ps
コマンドでそのプロセスのPIDを確認ls /proc/<PID>/fd -o
でファイルディスクリプタの一覧とそれぞれがどこを指しているのかが見れるシステムコールが発行されると、ユーザーモードからカーネルモードへのコンテキストスイッチが起こり、高い特権レベルで実行される(しすぱふぉ本p89)
ユーザーアプリケーションは抽象キー( = ファイル記述子 )をシステムコール経由でカーネルに渡し、カーネルはそのキーに対応するファイルにアクセスする(wiki)
// Create creates the named file with mode 0666 (before umask), truncating
// it if it already exists. If successful, methods on the returned
// File can be used for I/O; the associated file descriptor has mode
// O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) // ←ここに入る
}
Create()
はOpenFile()
を使いやすくする便利関数のようなもの// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm (before umask), if applicable. If successful,
// methods on the returned File can be used for I/O.
// If there is an error, it will be of type *PathError.
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
testlog.Open(name)
return openFileNolog(name, flag, perm) // ←ここに入る
}
OpenFile()関数は一般化されたオープンコールです。ほとんどのユーザーはOpen()またはCreate()を代わりに使用します。該当する場合には、指定されたフラグ(O_RDONLYなど)とperm(umaskの前)で名前付きファイルを開きます。成功した場合は、返されたFileのメソッドをI /Oに使用できます。エラーがある場合、* PathError型になります。
// openFileNolog is the Unix implementation of OpenFile.
func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
setSticky := false
if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
if _, err := Stat(name); IsNotExist(err) {
setSticky = true
}
}
var r int
for {
var e error
r, e = syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) // ←ここに入る
if e == nil {
break
}
..
..
..
OpenFile()
のUnix実装版syscall.Open()
という関数を実行している部分がある// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Open(path string, mode int, perm uint32) (fd int, err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) // ←ここに入る
fd = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno);
TEXT ·Syscall(SB),NOSPLIT,$0-56
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
ADDQ $0x2000000, AX
SYSCALL // ←ここでシステムコール!
JCC ok
MOVQ $-1, r1+32(FP)
MOVQ $0, r2+40(FP)
MOVQ AX, err+48(FP)
CALL runtime·exitsyscall(SB)
RET
ok:
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
MOVQ $0, err+48(FP)
CALL runtime·exitsyscall(SB)
RET
entersyscall()
関数とexitsyscall()
関数が呼ばれるGoならわかるシステムプログラミング
絵で見てわかる
おもろい