Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18314] ファイルの概要

このコミットは、Go言語のsyscallパッケージにおけるファイルロック関連のAPI変更を扱っています。具体的には、Flock_t構造体のメソッドであったLockを、独立した関数FcntlFlockへとリネームし、そのシグネチャを変更しています。これにより、ファイルロック操作のセマンティクスがより明確になり、Goの慣用的なスタイルに近づけられています。

コミット

commit 367ad4534f2d06e71f0182eb42ffa3e3c58da89a
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Tue Jan 21 16:27:39 2014 -0800

    syscall: rename method Flock_t.Lock to func FcntlFlock
    
    Update #7059
    
    R=rsc
    CC=golang-codereviews
    https://golang.org/cl/55370043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/367ad4534f2d06e71f0182eb42ffa3e3c58da89a

元コミット内容

このコミットの元の内容は、syscallパッケージ内のFlock_t型に定義されていたLockというメソッドを、FcntlFlockという名前の独立した関数に変更することです。

変更前: func (lk *Flock_t) Lock(fd uintptr, cmd int) error

変更後: func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error

この変更は、Issue #7059に関連しています。

変更の背景

この変更の背景には、Go言語のAPI設計における慣用的なパターンと、fcntlシステムコールがファイルディスクリプタ(fd)とコマンド(cmd)を主要な引数として受け取るという性質があります。

元々Flock_t.Lockというメソッドとして定義されていた場合、Flock_tのインスタンスがレシーバとして渡され、そのインスタンスに対してロック操作を行うというセマンティクスを示唆します。しかし、fcntlシステムコールによるファイルロックは、特定のファイルディスクリプタに対して行われる操作であり、Flock_t構造体自体がロック操作の「対象」というよりは、ロックの種類や範囲を記述するための「引数」としての役割が強いです。

メソッドとして定義されていると、Flock_tがロック操作の主体であるかのような誤解を招く可能性があります。これを独立した関数FcntlFlockとして定義し、Flock_tのポインタを引数として明示的に渡す形にすることで、fcntlシステムコールがファイルディスクリプタとコマンドを主軸とし、Flock_tがその補助的な情報を提供するという、より正確なセマンティクスを表現できます。

また、Goの標準ライブラリでは、特定のデータ構造に密接に関連しない汎用的な操作は、メソッドではなく関数として提供されることが多いです。この変更は、GoのAPI設計ガイドラインに沿ったものと言えます。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

1. fcntlシステムコール

fcntl(ファイル制御)は、Unix系オペレーティングシステムにおけるシステムコールの一つで、オープンされたファイルディスクリプタに対して様々な操作を行うために使用されます。その機能は多岐にわたり、ファイルロック、ファイルディスクリプタの複製、ファイルステータスフラグの取得/設定などが含まれます。

fcntlシステムコールの一般的な形式は以下の通りです。 int fcntl(int fd, int cmd, ... /* arg */ );

  • fd: 操作対象のファイルディスクリプタ。
  • cmd: 実行する操作を指定するコマンド。
  • arg: cmdに応じて追加の引数。ファイルロックの場合、flock構造体へのポインタが渡されます。

2. ファイルロック

ファイルロックは、複数のプロセスが同時に同じファイルにアクセスする際に、データの整合性を保つために使用されるメカニズムです。主に以下の2種類があります。

  • 共有ロック (Shared Lock / Read Lock): 複数のプロセスが同時に取得でき、読み取り操作に適しています。
  • 排他ロック (Exclusive Lock / Write Lock): 一度に1つのプロセスしか取得できず、書き込み操作に適しています。

fcntlシステムコールでは、F_GETLK, F_SETLK, F_SETLKWといったコマンドを使用してファイルロックを操作します。

3. flock構造体 (Unix/Linux)

fcntlシステムコールでファイルロックを操作する際に使用される構造体で、ロックの種類、開始オフセット、長さ、プロセスIDなどを指定します。Goのsyscallパッケージでは、これをFlock_tとして抽象化しています。

一般的なflock構造体のメンバーは以下の通りです(システムによって異なる場合があります)。

  • l_type: ロックの種類(F_RDLCK:共有ロック、F_WRLCK:排他ロック、F_UNLCK:ロック解除)。
  • l_whence: ロック範囲の開始オフセットの基準(SEEK_SET:ファイルの先頭から、SEEK_CUR:現在のファイルポインタから、SEEK_END:ファイルの末尾から)。
  • l_start: ロック範囲の開始オフセット。
  • l_len: ロック範囲の長さ。
  • l_pid: ロックを保持しているプロセスのID(F_GETLKで使用)。

4. F_GETLK, F_SETLK, F_SETLKW コマンド

  • F_GETLK: 指定されたロック(flock構造体で記述)が、他のプロセスによってブロックされるかどうかをテストします。ブロックされる場合、そのロックを保持しているプロセスの情報がflock構造体に書き込まれます。ロックが取得可能であれば、l_typeF_UNLCKに設定されます。
  • F_SETLK: 指定されたロックを設定または解除します。ロックがすぐに取得できない場合、エラー(EAGAINまたはEACCES)を返します。非ブロック操作です。
  • F_SETLKW: F_SETLKと同様にロックを設定または解除しますが、ロックがすぐに取得できない場合、ロックが利用可能になるまで呼び出し元のプロセスをブロック(待機)させます。ブロック操作です。

5. Go言語のsyscallパッケージ

Go言語のsyscallパッケージは、低レベルなオペレーティングシステムプリミティブへのアクセスを提供します。これには、システムコール、プロセス管理、ファイルシステム操作などが含まれます。このパッケージは、OS固有の機能に直接アクセスする必要がある場合に使用されますが、通常はより高レベルな標準ライブラリ(例: osパッケージ)を使用することが推奨されます。

技術的詳細

このコミットの技術的な核心は、Goのsyscallパッケージにおけるfcntlシステムコールのラッパー関数の設計変更です。

変更前の設計 (Flock_t.Lock メソッド)

// Lock performs a fcntl syscall for F_GETLK, F_SETLK or F_SETLKW commands.
func (lk *Flock_t) Lock(fd uintptr, cmd int) error {
	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
	if errno == 0 {
		return nil
	}
	return errno
}

変更前は、Flock_t構造体のポインタlkをレシーバとするメソッドLockとして定義されていました。この設計では、Flock_tのインスタンスがロック操作の「主体」であるかのように見えます。しかし、実際のfcntlシステムコールは、ファイルディスクリプタfdとコマンドcmdが主要な引数であり、Flock_tcmdに応じた追加情報を提供する役割です。

変更後の設計 (FcntlFlock 関数)

// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
	if errno == 0 {
		return nil
	}
	return errno
}

変更後は、FcntlFlockという独立した関数として定義され、Flock_tのポインタlkは明示的な引数として渡されます。この変更により、関数シグネチャがfcntlシステムコールの引数の順序(fd, cmd, flock_ptr)とより密接に一致し、APIの意図がより明確になります。

  • fd uintptr: ロック操作を行うファイルディスクリプタ。
  • cmd int: F_GETLK, F_SETLK, F_SETLKWなどのfcntlコマンド。
  • lk *Flock_t: ロックの種類、範囲、その他の詳細を記述するFlock_t構造体へのポインタ。

この変更は、GoのAPI設計原則である「明確さ」と「慣用性」を追求したものです。Flock_tはロック操作のパラメータであり、操作自体はファイルディスクリプタに対して行われるという事実を、関数シグネチャがより正確に反映するようになりました。

また、fcntl64Syscallという変数を使用している点も注目に値します。これは、32ビットシステムでSYS_FCNTL64を使用する必要がある場合に対応するための抽象化です。これにより、異なるアーキテクチャ間での互換性が保たれています。

コアとなるコードの変更箇所

--- a/src/pkg/syscall/flock.go
+++ b/src/pkg/syscall/flock.go
@@ -12,8 +12,8 @@ import "unsafe"
 // systems by flock_linux_32bit.go to be SYS_FCNTL64.
 var fcntl64Syscall uintptr = SYS_FCNTL
 
-// Lock performs a fcntl syscall for F_GETLK, F_SETLK or F_SETLKW commands.
-func (lk *Flock_t) Lock(fd uintptr, cmd int) error {
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
 	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
 	if errno == 0 {
 		return nil

コアとなるコードの解説

変更はsrc/pkg/syscall/flock.goファイル内で行われています。

  • 行12-13: コメントが更新され、fcntl64Syscall変数がSYS_FCNTLまたはSYS_FCNTL64のいずれかになることが示されています。これは、異なるシステム(特に32ビットLinuxシステム)でのfcntlシステムコールのバリエーションに対応するためです。
  • 行15 (削除): func (lk *Flock_t) Lock(fd uintptr, cmd int) error { という行が削除されました。これは、Flock_t型のメソッドとしてのLockの定義です。
  • 行16 (追加): func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { という行が追加されました。これは、独立した関数FcntlFlockの定義です。引数の順序が変更され、lk *Flock_tが明示的な引数として追加されています。
  • 行17-21: 関数の本体は変更されていません。Syscall関数を呼び出して実際のfcntlシステムコールを実行し、その結果(エラーコードerrno)を返しています。unsafe.Pointer(lk)は、Flock_t構造体へのポインタをuintptrに変換し、システムコールに渡すために使用されます。

この変更は、APIのセマンティクスを改善し、Goの慣用的なスタイルに合わせるためのリファクタリングです。機能的な変更は伴わず、既存の動作は維持されます。

関連リンク

参考にした情報源リンク

[インデックス 18314] ファイルの概要

このコミットは、Go言語のsyscallパッケージにおけるファイルロック関連のAPI変更を扱っています。具体的には、Flock_t構造体のメソッドであったLockを、独立した関数FcntlFlockへとリネームし、そのシグネチャを変更しています。これにより、ファイルロック操作のセマンティクスがより明確になり、Goの慣用的なスタイルに近づけられています。

コミット

commit 367ad4534f2d06e71f0182eb42ffa3e3c58da89a
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Tue Jan 21 16:27:39 2014 -0800

    syscall: rename method Flock_t.Lock to func FcntlFlock
    
    Update #7059
    
    R=rsc
    CC=golang-codereviews
    https://golang.org/cl/55370043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/367ad4534f2d06e71f0182eb42ffa3e3c58da89a

元コミット内容

このコミットの元の内容は、syscallパッケージ内のFlock_t型に定義されていたLockというメソッドを、FcntlFlockという名前の独立した関数に変更することです。

変更前: func (lk *Flock_t) Lock(fd uintptr, cmd int) error

変更後: func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error

この変更は、Issue #7059に関連しています。

変更の背景

この変更の背景には、Go言語のAPI設計における慣用的なパターンと、fcntlシステムコールがファイルディスクリプタ(fd)とコマンド(cmd)を主要な引数として受け取るという性質があります。

元々Flock_t.Lockというメソッドとして定義されていた場合、Flock_tのインスタンスがレシーバとして渡され、そのインスタンスに対してロック操作を行うというセマンティクスを示唆します。しかし、fcntlシステムコールによるファイルロックは、特定のファイルディスクリプタに対して行われる操作であり、Flock_t構造体自体がロック操作の「対象」というよりは、ロックの種類や範囲を記述するための「引数」としての役割が強いです。

メソッドとして定義されていると、Flock_tがロック操作の主体であるかのような誤解を招く可能性があります。これを独立した関数FcntlFlockとして定義し、Flock_tのポインタを引数として明示的に渡す形にすることで、fcntlシステムコールがファイルディスクリプタとコマンドを主軸とし、Flock_tがその補助的な情報を提供するという、より正確なセマンティクスを表現できます。

また、Goの標準ライブラリでは、特定のデータ構造に密接に関連しない汎用的な操作は、メソッドではなく関数として提供されることが多いです。この変更は、GoのAPI設計ガイドラインに沿ったものと言えます。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

1. fcntlシステムコール

fcntl(ファイル制御)は、Unix系オペレーティングシステムにおけるシステムコールの一つで、オープンされたファイルディスクリプタに対して様々な操作を行うために使用されます。その機能は多岐にわたり、ファイルロック、ファイルディスクリプタの複製、ファイルステータスフラグの取得/設定などが含まれます。

fcntlシステムコールの一般的な形式は以下の通りです。 int fcntl(int fd, int cmd, ... /* arg */ );

  • fd: 操作対象のファイルディスクリプタ。
  • cmd: 実行する操作を指定するコマンド。
  • arg: cmdに応じて追加の引数。ファイルロックの場合、flock構造体へのポインタが渡されます。

2. ファイルロック

ファイルロックは、複数のプロセスが同時に同じファイルにアクセスする際に、データの整合性を保つために使用されるメカニズムです。主に以下の2種類があります。

  • 共有ロック (Shared Lock / Read Lock): 複数のプロセスが同時に取得でき、読み取り操作に適しています。
  • 排他ロック (Exclusive Lock / Write Lock): 一度に1つのプロセスしか取得できず、書き込み操作に適しています。

fcntlシステムコールでは、F_GETLK, F_SETLK, F_SETLKWといったコマンドを使用してファイルロックを操作します。

3. flock構造体 (Unix/Linux)

fcntlシステムコールでファイルロックを操作する際に使用される構造体で、ロックの種類、開始オフセット、長さ、プロセスIDなどを指定します。Goのsyscallパッケージでは、これをFlock_tとして抽象化しています。

一般的なflock構造体のメンバーは以下の通りです(システムによって異なる場合があります)。

  • l_type: ロックの種類(F_RDLCK:共有ロック、F_WRLCK:排他ロック、F_UNLCK:ロック解除)。
  • l_whence: ロック範囲の開始オフセットの基準(SEEK_SET:ファイルの先頭から、SEEK_CUR:現在のファイルポインタから、SEEK_END:ファイルの末尾から)。
  • l_start: ロック範囲の開始オフセット。
  • l_len: ロック範囲の長さ。
  • l_pid: ロックを保持しているプロセスのID(F_GETLKで使用)。

4. F_GETLK, F_SETLK, F_SETLKW コマンド

  • F_GETLK: 指定されたロック(flock構造体で記述)が、他のプロセスによってブロックされるかどうかをテストします。ブロックされる場合、そのロックを保持しているプロセスの情報がflock構造体に書き込まれます。ロックが取得可能であれば、l_typeF_UNLCKに設定されます。
  • F_SETLK: 指定されたロックを設定または解除します。ロックがすぐに取得できない場合、エラー(EAGAINまたはEACCES)を返します。非ブロック操作です。
  • F_SETLKW: F_SETLKと同様にロックを設定または解除しますが、ロックがすぐに取得できない場合、ロックが利用可能になるまで呼び出し元のプロセスをブロック(待機)させます。ブロック操作です。

5. Go言語のsyscallパッケージ

Go言語のsyscallパッケージは、低レベルなオペレーティングシステムプリミティブへのアクセスを提供します。これには、システムコール、プロセス管理、ファイルシステム操作などが含まれます。このパッケージは、OS固有の機能に直接アクセスする必要がある場合に使用されますが、通常はより高レベルな標準ライブラリ(例: osパッケージ)を使用することが推奨されます。

技術的詳細

このコミットの技術的な核心は、Goのsyscallパッケージにおけるfcntlシステムコールのラッパー関数の設計変更です。

変更前の設計 (Flock_t.Lock メソッド)

// Lock performs a fcntl syscall for F_GETLK, F_SETLK or F_SETLKW commands.
func (lk *Flock_t) Lock(fd uintptr, cmd int) error {
	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
	if errno == 0 {
		return nil
	}
	return errno
}

変更前は、Flock_t構造体のポインタlkをレシーバとするメソッドLockとして定義されていました。この設計では、Flock_tのインスタンスがロック操作の「主体」であるかのように見えます。しかし、実際のfcntlシステムコールは、ファイルディスクリプタfdとコマンドcmdが主要な引数であり、Flock_tcmdに応じた追加情報を提供する役割です。

変更後の設計 (FcntlFlock 関数)

// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
	if errno == 0 {
		return nil
	}
	return errno
}

変更後は、FcntlFlockという独立した関数として定義され、Flock_tのポインタlkは明示的な引数として渡されます。この変更により、関数シグネチャがfcntlシステムコールの引数の順序(fd, cmd, flock_ptr)とより密接に一致し、APIの意図がより明確になります。

  • fd uintptr: ロック操作を行うファイルディスクリプタ。
  • cmd int: F_GETLK, F_SETLK, F_SETLKWなどのfcntlコマンド。
  • lk *Flock_t: ロックの種類、範囲、その他の詳細を記述するFlock_t構造体へのポインタ。

この変更は、GoのAPI設計原則である「明確さ」と「慣用性」を追求したものです。Flock_tはロック操作のパラメータであり、操作自体はファイルディスクリプタに対して行われるという事実を、関数シグネチャがより正確に反映するようになりました。

また、fcntl64Syscallという変数を使用している点も注目に値します。これは、32ビットシステムでSYS_FCNTL64を使用する必要がある場合に対応するための抽象化です。これにより、異なるアーキテクチャ間での互換性が保たれています。

コアとなるコードの変更箇所

--- a/src/pkg/syscall/flock.go
+++ b/src/pkg/syscall/flock.go
@@ -12,8 +12,8 @@ import "unsafe"
 // systems by flock_linux_32bit.go to be SYS_FCNTL64.
 var fcntl64Syscall uintptr = SYS_FCNTL
 
-// Lock performs a fcntl syscall for F_GETLK, F_SETLK or F_SETLKW commands.
-func (lk *Flock_t) Lock(fd uintptr, cmd int) error {
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
 	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
 	if errno == 0 {
 		return nil

コアとなるコードの解説

変更はsrc/pkg/syscall/flock.goファイル内で行われています。

  • 行12-13: コメントが更新され、fcntl64Syscall変数がSYS_FCNTLまたはSYS_FCNTL64のいずれかになることが示されています。これは、異なるシステム(特に32ビットLinuxシステム)でのfcntlシステムコールのバリエーションに対応するためです。
  • 行15 (削除): func (lk *Flock_t) Lock(fd uintptr, cmd int) error { という行が削除されました。これは、Flock_t型のメソッドとしてのLockの定義です。
  • 行16 (追加): func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { という行が追加されました。これは、独立した関数FcntlFlockの定義です。引数の順序が変更され、lk *Flock_tが明示的な引数として追加されています。
  • 行17-21: 関数の本体は変更されていません。Syscall関数を呼び出して実際のfcntlシステムコールを実行し、その結果(エラーコードerrno)を返しています。unsafe.Pointer(lk)は、Flock_t構造体へのポインタをuintptrに変換し、システムコールに渡すために使用されます。

この変更は、APIのセマンティクスを改善し、Goの慣用的なスタイルに合わせるためのリファクタリングです。機能的な変更は伴わず、既存の動作は維持されます。

関連リンク

参考にした情報源リンク