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

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

このコミットは、Go言語のsyscallパッケージにおいて、Linuxシステムコールであるflock()をサポートするために必要な定数を追加するものです。具体的には、LOCK_SH (共有ロック)、LOCK_EX (排他ロック)、LOCK_NB (非ブロックモード)、LOCK_UN (ロック解除) といったflock()に関連する定数が、i386およびamd64アーキテクチャ向けのzerrors_linux_386.gozerrors_linux_amd64.goファイルに追加されました。これらの定数は、mkerrors.shスクリプトによって自動生成されるように設定が更新されています。

コミット

commit 83c30f3ec28cc87b8814fb29c7bd88c311dace58
Author: Andrea Spadaccini <spadaccio@google.com>
Date:   Thu Dec 8 15:12:08 2011 +0900

    syscall: add constants for flock() system call under Linux.
    
    The values have been generated only for the i386 and amd64 architectures.
    
    R=golang-dev, mikioh.mikioh, dsymonds
    CC=bradfitz, dsymonds, golang-dev
    https://golang.org/cl/5452060

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

https://github.com/golang/go/commit/83c30f3ec28cc87b8814fb29c7bd88c311dace58

元コミット内容

Linuxシステムコールflock()のための定数をsyscallパッケージに追加しました。これらの値はi386とamd64アーキテクチャ向けに生成されています。

変更の背景

Go言語の標準ライブラリであるsyscallパッケージは、オペレーティングシステムが提供する低レベルな機能(システムコール)へのアクセスを提供します。flock()はUnix系システムにおけるファイルロックのための重要なシステムコールであり、複数のプロセスが同時にファイルにアクセスする際にデータの整合性を保つために使用されます。

このコミット以前は、GoのsyscallパッケージにはLinuxのflock()システムコールを直接利用するための必要な定数が含まれていませんでした。これにより、Goプログラムからflock()を呼び出す際に、これらの定数を手動で定義するか、あるいはCgoを介してC言語のライブラリを呼び出す必要がありました。これはGoの哲学である「シンプルさ」や「効率性」に反するものであり、またクロスプラットフォーム対応の観点からも望ましくありませんでした。

この変更の背景には、Goプログラムがよりネイティブに、かつ効率的にLinuxのファイルロック機能を利用できるようにするという目的があります。特に、ファイルベースのデータストアや、複数のGoプロセスが共有ファイルにアクセスするようなアプリケーションにおいて、flock()のサポートは不可欠です。

前提知識の解説

flock() システムコール

flock()は、Unix系オペレーティングシステムで提供されるファイルロックのためのシステムコールです。これは、ファイル全体に対するアドバイザリロック(協調ロック)を提供します。アドバイザリロックとは、OSがロックの強制を行わず、アプリケーションがロックの規則に従うことを期待するロックメカニズムです。

flock()には主に以下の2種類のロックがあります。

  • 共有ロック (Shared Lock): LOCK_SH で指定されます。複数のプロセスが同時にファイルに対して共有ロックを取得できます。これは主に読み取りアクセスに使用されます。
  • 排他ロック (Exclusive Lock): LOCK_EX で指定されます。一度に1つのプロセスのみがファイルに対して排他ロックを取得できます。これは主に書き込みアクセスに使用されます。

また、ロックの動作を制御するためのフラグも存在します。

  • 非ブロックモード (Non-blocking): LOCK_NB で指定されます。ロックがすぐに取得できない場合、flock()はブロックせずにエラーを返します。
  • ロック解除 (Unlock): LOCK_UN で指定されます。ファイルから既存のロックを解除します。

flock()は、open()で開かれたファイルディスクリプタに対して適用され、プロセスが終了するか、ファイルディスクリプタが閉じられるか、明示的にLOCK_UNでロックが解除されるまで有効です。

Go言語の syscall パッケージ

Go言語のsyscallパッケージは、低レベルなオペレーティングシステムプリミティブへのインターフェースを提供します。これには、システムコール、プロセス管理、ファイルI/O、ネットワーク操作などが含まれます。このパッケージは、GoプログラムがOS固有の機能に直接アクセスできるようにするために使用されます。

syscallパッケージは、各OSおよびアーキテクチャに特化した定数や関数を多数含んでいます。これらの定数は、通常、C言語のヘッダーファイル(例: /usr/include/sys/file.h)で定義されている値に対応します。Goのビルドシステムは、これらのOS固有の定数を自動生成するためのスクリプト(例: mkerrors.sh)を使用することがよくあります。

mkerrors.sh スクリプトと zerrors_linux_*.go ファイル

Goのsyscallパッケージでは、OSやアーキテクチャに依存する定数やエラーコードを自動生成するために、mkerrors.shのようなスクリプトが使用されます。これらのスクリプトは、C言語のヘッダーファイルを解析し、対応するGoの定数定義を生成します。

生成された定数は、zerrors_linux_386.gozerrors_linux_amd64.goのようなファイルに格納されます。ファイル名のzは、これらのファイルが自動生成されたものであることを示す慣例的なプレフィックスです。linux_386linux_amd64は、それぞれLinuxオペレーティングシステム上の32ビットIntelアーキテクチャ(i386)と64ビットIntelアーキテクチャ(amd64)に対応することを示しています。これにより、Goは異なるOSやCPUアーキテクチャに対して適切なシステムコール定数を提供できます。

技術的詳細

このコミットの技術的な核心は、GoのsyscallパッケージがLinuxのflock()システムコールをネイティブにサポートするために、必要な定数を追加し、その自動生成プロセスを更新した点にあります。

  1. mkerrors.sh の更新: src/pkg/syscall/mkerrors.shスクリプトは、C言語のヘッダーファイルからGoの定数を生成するためのものです。このコミットでは、以下の変更が加えられました。

    • #include <sys/file.h> の追加: flock()に関連する定数(LOCK_SH, LOCK_EXなど)は、通常、C言語のsys/file.hヘッダーファイルで定義されています。この行を追加することで、mkerrors.shがこれらの定数を認識し、その値を抽出できるようになります。
    • $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || の追加: これは正規表現パターンであり、mkerrors.shがCヘッダーファイルから抽出するシンボル名のリストに、LOCK_SHLOCK_EXLOCK_NBLOCK_UNといったパターンに一致する定数を含めるように指示します。これにより、これらのflock()関連定数がGoのsyscallパッケージに自動的に取り込まれるようになります。
  2. zerrors_linux_386.go および zerrors_linux_amd64.go への定数追加: mkerrors.shスクリプトが実行されると、その出力としてzerrors_linux_386.gozerrors_linux_amd64.goファイルが更新されます。これらのファイルには、Linuxのi386およびamd64アーキテクチャにおけるflock()定数の実際の値がGoのconstとして追加されます。

    追加された定数は以下の通りです。

    • LOCK_EX = 0x2 (排他ロック)
    • LOCK_NB = 0x4 (非ブロックモード)
    • LOCK_SH = 0x1 (共有ロック)
    • LOCK_UN = 0x8 (ロック解除)

    これらの16進数の値は、Linuxカーネルの内部で定義されているflock()操作に対応するビットフラグの値と一致します。Goプログラムはこれらの定数を使用することで、syscall.Flock()のような関数を呼び出す際に、適切なロックタイプや動作を指定できるようになります。

この変更により、Go開発者はLinux上でファイルロックを実装する際に、Cgoを介さずにGoのsyscallパッケージを直接利用できるようになり、コードの可読性、移植性、およびパフォーマンスが向上します。

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

src/pkg/syscall/mkerrors.sh

--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -108,6 +108,7 @@ includes_OpenBSD='\
 
 includes='\
 #include <sys/types.h>\
+#include <sys/file.h>\
 #include <fcntl.h>\
 #include <dirent.h>\
 #include <sys/socket.h>\
@@ -153,6 +154,7 @@ ccflags="$@"\
 		$2 ~ /^E[A-Z0-9_]+$/ ||\
 		$2 ~ /^SIG[^_]/ ||\
 		$2 ~ /^IN_/ ||\
+\t\t$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||\
 		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV)_/ ||\
 		$2 == "SOMAXCONN" ||\
 		$2 == "NAME_MAX" ||

src/pkg/syscall/zerrors_linux_386.go

--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -478,6 +478,10 @@ const (
 	LINUX_REBOOT_CMD_SW_SUSPEND      = 0xd000fce2
 	LINUX_REBOOT_MAGIC1              = 0xfee1dead
 	LINUX_REBOOT_MAGIC2              = 0x28121969
+	LOCK_EX                          = 0x2
+	LOCK_NB                          = 0x4
+	LOCK_SH                          = 0x1
+	LOCK_UN                          = 0x8
 	MADV_DOFORK                      = 0xb
 	MADV_DONTFORK                    = 0xa
 	MADV_DONTNEED                    = 0x4

src/pkg/syscall/zerrors_linux_amd64.go

--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -478,6 +478,10 @@ const (
 	LINUX_REBOOT_CMD_SW_SUSPEND      = 0xd000fce2
 	LINUX_REBOOT_MAGIC1              = 0xfee1dead
 	LINUX_REBOOT_MAGIC2              = 0x28121969
+	LOCK_EX                          = 0x2
+	LOCK_NB                          = 0x4
+	LOCK_SH                          = 0x1
+	LOCK_UN                          = 0x8
 	MADV_DOFORK                      = 0xb
 	MADV_DONTFORK                    = 0xa
 	MADV_DONTNEED                    = 0x4

コアとなるコードの解説

src/pkg/syscall/mkerrors.sh の変更

  • #include <sys/file.h> の追加: この行は、mkerrors.shスクリプトがC言語のヘッダーファイルを解析する際に、sys/file.hの内容も読み込むように指示します。flock()システムコールに関連する定数(LOCK_SH, LOCK_EX, LOCK_NB, LOCK_UN)は、このヘッダーファイルで定義されているため、これを含めることでスクリプトがこれらの定数の値を取得できるようになります。

  • $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || の追加: これは、mkerrors.shスクリプト内の正規表現パターンを拡張するものです。スクリプトはCヘッダーファイルから様々な定数を抽出しますが、このパターンを追加することで、LOCK_で始まり、その後にSHEXNBUNのいずれかが続く定数名も抽出対象に含めるようになります。これにより、flock()に必要な定数がGoのコードに自動的にマッピングされるようになります。

src/pkg/syscall/zerrors_linux_386.go および src/pkg/syscall/zerrors_linux_amd64.go の変更

これらのファイルは、mkerrors.shスクリプトによって自動生成されるGoのソースファイルであり、Linuxシステムコールに関連する定数が定義されています。このコミットにより、以下のflock()関連定数が追加されました。

  • LOCK_EX = 0x2: 排他ロックの定数。ファイルに対して書き込みアクセスを行う際に使用され、他のプロセスが同時にロックを取得することを防ぎます。
  • LOCK_NB = 0x4: 非ブロックモードの定数。flock()呼び出し時にこのフラグを指定すると、ロックがすぐに取得できない場合にブロックせずにエラーを返します。
  • LOCK_SH = 0x1: 共有ロックの定数。ファイルに対して読み取りアクセスを行う際に使用され、複数のプロセスが同時に共有ロックを取得できます。
  • LOCK_UN = 0x8: ロック解除の定数。ファイルに設定されているロックを明示的に解除するために使用されます。

これらの定数がGoのsyscallパッケージに直接追加されたことで、Goプログラムはこれらのシンボリックな定数名を使用してflock()システムコールを呼び出すことが可能になり、コードの可読性と保守性が向上します。また、これらの値はLinuxカーネルが期待する正確な値であるため、GoプログラムがLinuxのファイルロック機能を正しく利用できるようになります。

関連リンク

参考にした情報源リンク