[インデックス 16527] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにLinux向けのSetpriority
およびGetpriority
システムコールを追加し、それらの一貫性テストを導入するものです。これにより、Goプログラムからプロセスのスケジューリング優先度を操作できるようになります。
コミット
commit 46e30c7d70fd30b5d67b93625cf97110dc751f68
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Tue Jun 11 02:47:04 2013 +0800
syscall: add {Set,Get}priority for Linux, and consistency tests
R=golang-dev, iant, bradfitz, dave
CC=golang-dev
https://golang.org/cl/7430044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/46e30c7d70fd30b5d67b93625cf97110dc751f68
元コミット内容
syscall: add {Set,Get}priority for Linux, and consistency tests
R=golang-dev, iant, bradfitz, dave
CC=golang-dev
https://golang.org/cl/7430044
変更の背景
Go言語のsyscall
パッケージは、オペレーティングシステムが提供する低レベルなシステムコールへのインターフェースを提供します。これにより、GoプログラムはOSの機能を直接利用できます。このコミットが作成された背景には、Linux環境においてプロセスのスケジューリング優先度をプログラムから動的に制御する機能が不足していたことが挙げられます。
Setpriority
およびGetpriority
システムコールは、Unix系OSにおいてプロセス、プロセスグループ、またはユーザーのスケジューリング優先度(nice値)を設定・取得するために使用されます。これらのシステムコールがGoのsyscall
パッケージに統合されることで、Goで記述されたアプリケーションが、例えば以下のような高度なシステム管理タスクを実行できるようになります。
- リソース管理: 重要なバックグラウンドプロセスやリアルタイム処理を行うアプリケーションの優先度を上げ、システムリソースをより多く割り当てる。
- 負荷分散: 優先度の低いタスクのnice値を上げて、CPU使用率を抑える。
- システム監視: 実行中のプロセスやユーザーの現在の優先度を監視し、システムのパフォーマンスボトルネックを特定する。
この機能の追加は、Goがより広範なシステムプログラミングのユースケースに対応するための重要なステップでした。特に、Linux環境でのよりきめ細やかなプロセス制御を可能にすることで、Goアプリケーションの適用範囲が広がります。
前提知識の解説
システムコール (System Call)
システムコールは、オペレーティングシステム (OS) のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など、OSの根幹をなす機能はシステムコールを通じて提供されます。プログラムがこれらの機能を利用する際には、直接ハードウェアにアクセスするのではなく、システムコールを介してカーネルに処理を依頼します。これにより、システムの安定性とセキュリティが保たれます。
Go言語のsyscall
パッケージは、GoプログラムからこれらのOSネイティブなシステムコールを呼び出すための薄いラッパーを提供します。これにより、Goは低レベルなシステムプログラミングも可能にしています。
プロセスのスケジューリング優先度 (nice値)
Unix系OSでは、プロセスの実行優先度を制御するために「nice値」という概念が用いられます。nice値は、プロセスのスケジューリング優先度に対するヒントとしてカーネルに与えられます。
- nice値の範囲: 通常、-20から+19までの整数値を取ります。
- 値の意味:
- 低いnice値 (例: -20): 優先度が高いことを意味し、より多くのCPU時間を割り当てられやすくなります。ただし、nice値を下げる(優先度を上げる)操作は、通常root権限が必要です。
- 高いnice値 (例: +19): 優先度が低いことを意味し、他のプロセスにCPU時間を譲りやすくなります。これは、バックグラウンドで実行される非緊急なタスクに適しています。
setpriority
/getpriority
システムコール:setpriority(which, who, prio)
: 指定されたwhich
(プロセス、プロセスグループ、ユーザー)とwho
(ID)に対して、prio
(nice値)を設定します。getpriority(which, who)
: 指定されたwhich
とwho
の現在のnice値を取得します。
which
引数:PRIO_PROCESS
: 個別のプロセスに対して優先度を設定/取得します。who
はプロセスID (PID) です。PRIO_PGRP
: プロセスグループに対して優先度を設定/取得します。who
はプロセスグループID (PGID) です。PRIO_USER
: 特定のユーザーが所有するすべてのプロセスに対して優先度を設定/取得します。who
はユーザーID (UID) です。
これらのシステムコールは、システム管理者や特定のアプリケーションが、システムリソースの割り当てを最適化するために利用されます。
zerrors_*.go
および zsyscall_*.go
ファイル
Goのsyscall
パッケージでは、OS固有の定数やシステムコール関数が自動生成されています。
zerrors_*.go
: これらのファイルは、OS固有のエラーコードや定数(例:PRIO_PROCESS
,PRIO_PGRP
,PRIO_USER
など)を定義しています。これらは通常、C言語のヘッダーファイルからスクリプトによって自動生成されます。zsyscall_*.go
: これらのファイルは、OS固有のシステムコール関数を定義しています。Goの関数シグネチャから、対応するCのシステムコールを呼び出すためのラッパーコードが自動生成されます。
これらの自動生成ファイルは、Goが様々なOSアーキテクチャで動作するために不可欠であり、手動でのメンテナンスの手間を省き、一貫性を保つ役割を担っています。
技術的詳細
このコミットの技術的な核心は、Linuxカーネルが提供するsetpriority(2)
およびgetpriority(2)
システムコールをGoのsyscall
パッケージに統合することです。
-
システムコール関数の追加:
src/pkg/syscall/syscall_linux.go
: このファイルに、Getpriority
とSetpriority
のGo言語側の関数シグネチャが追加されます。これらは//sys
ディレクティブによって、後述のzsyscall_linux_*.go
ファイルに実際のシステムコール呼び出しコードが自動生成されることを示します。src/pkg/syscall/zsyscall_linux_386.go
,src/pkg/syscall/zsyscall_linux_amd64.go
,src/pkg/syscall/zsyscall_linux_arm.go
: これらのファイルは、mksyscall.sh
スクリプトによって自動生成されます。このコミットでは、Getpriority
とSetpriority
に対応する実際のシステムコール呼び出し(Syscall
またはRawSyscall
を使用)が、各アーキテクチャ(386, amd64, arm)向けに追加されています。例えば、Getpriority
はSYS_GETPRIORITY
システムコール番号を使用してカーネルを呼び出し、戻り値から優先度とエラーを取得します。
-
定数の追加:
src/pkg/syscall/mkerrors.sh
: このスクリプトは、OS固有の定数を生成するために使用されます。このコミットでは、PRIO_PROCESS
,PRIO_PGRP
,PRIO_USER
といった優先度設定の対象を示す定数が、このスクリプトによって生成されるように変更が加えられています。具体的には、#include <sys/time.h>
が追加され、PRIO_
で始まる定数が含まれるように正規表現が更新されています。src/pkg/syscall/zerrors_*.go
:mkerrors.sh
スクリプトの実行により、zerrors_darwin_386.go
,zerrors_linux_amd64.go
など、各OSおよびアーキテクチャ固有のzerrors_*.go
ファイルにPRIO_PGRP
,PRIO_PROCESS
,PRIO_USER
の定数定義が追加されます。これらの定数は、Setpriority
やGetpriority
関数を呼び出す際に、どのエンティティ(プロセス、プロセスグループ、ユーザー)の優先度を操作するかを指定するために使用されます。
-
一貫性テストの追加:
src/pkg/syscall/consistency_unix_test.go
: 新しいテストファイルが追加されています。このテストは、Setpriority
とGetpriority
関数、および関連する定数(PRIO_USER
,PRIO_PROCESS
,PRIO_PGRP
)が、FreeBSD, Darwin (macOS), Linux, NetBSD, OpenBSDといった主要なUnix系OSで一貫して利用可能であることを確認します。これは、Goのクロスプラットフォーム互換性を維持するための重要なテストです。このテストは、実際にシステムコールを実行するのではなく、コンパイル時にこれらの関数と定数が存在し、正しい型シグネチャを持っていることを検証するものです。
これらの変更により、GoプログラムはLinux上でプロセスの優先度を安全かつ効率的に操作できるようになります。また、他のUnix系OSとの互換性も考慮されており、Goのsyscall
パッケージの堅牢性が向上しています。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
-
src/pkg/syscall/consistency_unix_test.go
:- 新規追加されたテストファイル。
Setpriority
、Getpriority
関数、およびPRIO_USER
,PRIO_PROCESS
,PRIO_PGRP
定数が、Unix系OS(FreeBSD, Darwin, Linux, NetBSD, OpenBSD)で利用可能であることをコンパイル時に検証する。
// +build freebsd darwin linux netbsd openbsd package syscall_test import "syscall" // {Set,Get}priority and needed constants for them func _() { var ( _ func(int, int, int) error = syscall.Setpriority _ func(int, int) (int, error) = syscall.Getpriority ) const ( _ int = syscall.PRIO_USER _ int = syscall.PRIO_PROCESS _ int = syscall.PRIO_PGRP ) }
-
src/pkg/syscall/mkerrors.sh
:sys/time.h
のインクルードを追加。PRIO_
で始まる定数(PRIO_PROCESS
,PRIO_PGRP
,PRIO_USER
)がエラー定数として認識され、zerrors_*.go
ファイルに生成されるように正規表現を更新。
--- a/src/pkg/syscall/mkerrors.sh +++ b/src/pkg/syscall/mkerrors.sh @@ -71,6 +71,7 @@ includes_Linux='\ #include <sys/prctl.h>\ #include <sys/stat.h>\ #include <sys/types.h>\ +#include <sys/time.h>\ #include <sys/socket.h>\ #include <linux/if_addr.h>\ #include <linux/if_ether.h>\ @@ -222,6 +223,7 @@ ccflags="$@"\ $2 ~ /^BIOC/ ||\ $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||\ $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||\ +\t\t$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||\ $2 !~ /^(BPF_TIMEVAL)$/ &&\ $2 ~ /^(BPF|DLT)_/ ||\ $2 !~ "WMESGLEN" &&
-
src/pkg/syscall/syscall_linux.go
:Getpriority
とSetpriority
のGo言語側の関数シグネチャを追加。//sys
ディレクティブにより、対応するシステムコールが自動生成されることを示す。- 既存のコメントから
Getpriority
とSetpriority
のエントリを削除(重複を避けるため)。
--- a/src/pkg/syscall/syscall_linux.go +++ b/src/pkg/syscall/syscall_linux.go @@ -926,6 +926,7 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri //sysnb Getpgrp() (pid int)\ //sysnb Getpid() (pid int)\ //sysnb Getppid() (ppid int)\ +//sys Getpriority(which int, who int) (prio int, err error)\ //sysnb Getrusage(who int, rusage *Rusage) (err error)\ //sysnb Gettid() (tid int)\ //sys Getxattr(path string, attr string, dest []byte) (sz int, err error)\ @@ -957,6 +958,7 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri //sysnb Setsid() (pid int, err error)\ //sysnb Settimeofday(tv *Timeval) (err error)\ //sysnb Setuid(uid int) (err error)\ +//sys Setpriority(which int, who int, prio int) (err error)\ //sys Setxattr(path string, attr string, data []byte, flags int) (err error)\ //sys Symlink(oldpath string, newpath string) (err error)\ //sys Sync()\ @@ -1036,7 +1038,6 @@ func Munmap(b []byte) (err error) {\ // GetThreadArea\ // Getitimer\ // Getpmsg\ -// Getpriority\ // IoCancel\ // IoDestroy\ // IoGetevents\ @@ -1112,7 +1113,6 @@ func Munmap(b []byte) (err error) {\ // SetRobustList\ // SetThreadArea\ // SetTidAddress\ -// Setpriority\ // Shmat\ // Shmctl\ // Shmdt\
-
src/pkg/syscall/zerrors_*.go
(例:zerrors_linux_amd64.go
):mkerrors.sh
の実行により、PRIO_PGRP
,PRIO_PROCESS
,PRIO_USER
の定数定義が追加。
--- a/src/pkg/syscall/zerrors_linux_amd64.go +++ b/src/pkg/syscall/zerrors_linux_amd64.go @@ -658,6 +658,9 @@ const (\ PACKET_RECV_OUTPUT = 0x3\ PACKET_RX_RING = 0x5\ PACKET_STATISTICS = 0x6\ +\tPRIO_PGRP = 0x1\ +\tPRIO_PROCESS = 0x0\ +\tPRIO_USER = 0x2\ PROT_EXEC = 0x4\ PROT_GROWSDOWN = 0x1000000\ PROT_GROWSUP = 0x2000000\
-
src/pkg/syscall/zsyscall_linux_*.go
(例:zsyscall_linux_amd64.go
):Getpriority
とSetpriority
の実際のシステムコール呼び出しラッパー関数が追加。
--- a/src/pkg/syscall/zsyscall_linux_amd64.go +++ b/src/pkg/syscall/zsyscall_linux_amd64.go @@ -534,6 +534,17 @@ func Getppid() (ppid int) {\ \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\ \n\ +func Getpriority(which int, who int) (prio int, err error) {\ +\tr0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)\ +\tprio = int(r0)\ +\tif e1 != 0 {\ +\t\terr = e1\ +\t}\ +\treturn\ +}\ +\n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\ \n func Getrusage(who int, rusage *Rusage) (err error) {\ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)\ \tif e1 != 0 {\ @@ -994,6 +1005,16 @@ func Setuid(uid int) (err error) {\ \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\ \n\ +func Setpriority(which int, who int, prio int) (err error) {\ +\t_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))\ +\tif e1 != 0 {\ +\t\terr = e1\ +\t}\ +\treturn\ +}\ +\n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\ \n func Setxattr(path string, attr string, data []byte, flags int) (err error) {\ var _p0 *byte\ _p0, err = BytePtrFromString(path)\
コアとなるコードの解説
src/pkg/syscall/consistency_unix_test.go
このファイルは、Goのクロスプラットフォーム互換性を保証するための重要な役割を担っています。// +build freebsd darwin linux netbsd openbsd
というビルドタグは、このファイルが指定されたUnix系OSでのみコンパイルされることを意味します。
テスト関数_()
は、実際にSetpriority
やGetpriority
を呼び出すわけではありません。その代わりに、これらの関数と関連する定数(PRIO_USER
, PRIO_PROCESS
, PRIO_PGRP
)が、Goのsyscall
パッケージ内で期待される型シグネチャと値で存在するかどうかをコンパイル時に検証します。
_ func(int, int, int) error = syscall.Setpriority
:syscall.Setpriority
がfunc(int, int, int) error
というシグネチャを持つ関数であることを確認します。_ func(int, int) (int, error) = syscall.Getpriority
:syscall.Getpriority
がfunc(int, int) (int, error)
というシグネチャを持つ関数であることを確認します。_ int = syscall.PRIO_USER
:syscall.PRIO_USER
がint
型であることを確認します。他のPRIO_PROCESS
とPRIO_PGRP
も同様です。
この「コンパイル時テスト」は、異なるOSやアーキテクチャでGoのsyscall
パッケージが正しく生成され、必要なインターフェースを提供していることを保証する、効率的かつ効果的な方法です。
src/pkg/syscall/mkerrors.sh
このシェルスクリプトは、Goのsyscall
パッケージで使用されるOS固有の定数を自動生成するためのものです。C言語のヘッダーファイルを解析し、Goのソースコードとして出力します。
変更点である#include <sys/time.h>
の追加は、getpriority
やsetpriority
に関連する定数(PRIO_PROCESS
など)が定義されているヘッダーファイルが、Linux環境で正しく読み込まれるようにするために必要です。
また、$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
という行の追加は、スクリプトがCヘッダーファイルからPRIO_PROCESS
、PRIO_PGRP
、PRIO_USER
といった定数を抽出し、Goのzerrors_*.go
ファイルに含めるように指示しています。これにより、Goプログラムからこれらの定数を直接参照できるようになります。
src/pkg/syscall/syscall_linux.go
このファイルは、Linux固有のシステムコールに対するGo言語のインターフェースを定義しています。//sys
ディレクティブは、Goのツールチェーンがこの行を解析し、対応するシステムコールラッパー関数をzsyscall_linux_*.go
ファイルに自動生成するためのマーカーです。
//sys Getpriority(which int, who int) (prio int, err error)
:Getpriority
関数が、which
とwho
という2つのint
型引数を取り、prio
というint
型とerr
というerror
型を返すことを宣言しています。//sys Setpriority(which int, who int, prio int) (err error)
:Setpriority
関数が、which
,who
,prio
という3つのint
型引数を取り、err
というerror
型を返すことを宣言しています。
これらの宣言により、Go開発者はGoの通常の関数呼び出し構文でシステムコールを利用できるようになり、低レベルなシステムコール番号やレジスタ操作を意識する必要がなくなります。
src/pkg/syscall/zsyscall_linux_*.go
(例: zsyscall_linux_amd64.go
)
これらのファイルは、syscall_linux.go
の//sys
ディレクティブに基づいて自動生成される、実際のシステムコール呼び出しを行うGoコードを含んでいます。
Getpriority
関数の実装例(amd64アーキテクチャの場合):
func Getpriority(which int, who int) (prio int, err error) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
if e1 != 0 {
err = e1
}
return
}
Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
: これは、Linuxカーネルのgetpriority
システムコールを呼び出す部分です。SYS_GETPRIORITY
:getpriority
システムコールに対応するシステムコール番号です。これはOSとアーキテクチャによって異なります。uintptr(which)
,uintptr(who)
: システムコールに渡される引数は、通常uintptr
型にキャストされます。r0, _, e1
: システムコールからの戻り値を受け取ります。r0
はプライマリな戻り値(この場合は優先度)、e1
はエラーコードです。
prio = int(r0)
: システムコールからの戻り値r0
をint
型に変換してprio
変数に格納します。if e1 != 0 { err = e1 }
: エラーコードe1
が0でない場合、エラーが発生したことを示し、err
変数に設定します。
Setpriority
関数も同様に、SYS_SETPRIORITY
システムコールを呼び出し、引数としてwhich
, who
, prio
を渡します。
これらの自動生成されたラッパー関数は、GoプログラムがOSの低レベルな機能にアクセスするための安全で型付けされたインターフェースを提供し、Goのポータビリティとシステムプログラミング能力を向上させています。
関連リンク
getpriority(2)
man page: https://man7.org/linux/man-pages/man2/getpriority.2.htmlsetpriority(2)
man page: https://man7.org/linux/man-pages/man2/setpriority.2.html- Go
syscall
package documentation: https://pkg.go.dev/syscall
参考にした情報源リンク
- Go
syscall
package source code (relevant files):src/pkg/syscall/consistency_unix_test.go
src/pkg/syscall/mkerrors.sh
src/pkg/syscall/syscall_linux.go
src/pkg/syscall/zerrors_linux_amd64.go
(and otherzerrors_*.go
files)src/pkg/syscall/zsyscall_linux_amd64.go
(and otherzsyscall_*.go
files)
- Linux man pages for
getpriority
andsetpriority
. - Go CL 7430044: https://golang.org/cl/7430044
- Go issue tracker (related issues, if any, would be linked from the CL or commit message).
- General knowledge about Unix system programming and Go's
syscall
package.