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

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

このコミットは、Go言語のテスト環境設定スクリプト src/run.bash において、NetBSD-current 環境でのスレッド数制限 (ulimit -T) を適切に設定するための変更を導入しています。これにより、NetBSD上でのGoのテスト実行時におけるスレッド関連の問題が解消され、より安定したテスト環境が提供されます。

コミット

  • コミットハッシュ: 8a4efed63c02f18c14b3e445f399d421d23dfa32
  • Author: Benny Siegert bsiegert@gmail.com
  • Date: Mon Jun 17 19:31:58 2013 +1000

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

https://github.com/golang/go/commit/8a4efed63c02f18c14b3e445f399d421d23dfa32

元コミット内容

    run.bash: raise ulimit for the number of threads.
    
    This is needed on NetBSD-current. Support for
    ulimit -T in bash was added in 4.2nb3.
    
    R=golang-dev, minux.ma, rsc, dave
    CC=golang-dev
    https://golang.org/cl/10078047

変更の背景

この変更は、NetBSD-current 環境でGoのテストスイートを実行する際に発生していた問題に対処するために行われました。Goのランタイムは、多数のゴルーチン(Goの軽量スレッド)を効率的に管理するために、基盤となるオペレーティングシステムのスレッドを多用します。特定のOS、特にNetBSDのようなシステムでは、プロセスが作成できるスレッドの数にシステムレベルの制限(ulimit)が設けられている場合があります。

コミットメッセージによると、NetBSD-currentでは、デフォルトのスレッド数制限がGoのテスト実行に必要な数よりも低く設定されており、これがテストの失敗や不安定性の原因となっていました。この問題を解決するためには、テスト実行前にスレッド数制限を緩和する必要がありました。

また、ulimit -T というスレッド数制限を設定するためのオプションが、bash シェルの特定のバージョン(4.2nb3 以降)でサポートされるようになったことも、この変更の背景にあります。これにより、src/run.bash スクリプト内でこの新しい ulimit オプションを利用して、動的にスレッド数制限を調整することが可能になりました。

前提知識の解説

ulimit

ulimit は、Unix系オペレーティングシステムにおいて、ユーザーがプロセスに対して設定できるリソースの制限を管理するためのコマンドです。これにより、プロセスが消費できるCPU時間、ファイルサイズ、オープンできるファイルの数、メモリ使用量、そしてこのコミットで関連するスレッド数などのリソースを制御できます。システム全体の安定性を保ち、単一のプロセスが過剰なリソースを消費するのを防ぐために使用されます。

ulimit には、ソフトリミット(ulimit -S)とハードリミット(ulimit -H)の2種類があります。

  • ソフトリミット: 現在適用されている制限で、ユーザーはこれをハードリミットの範囲内で引き上げることができます。
  • ハードリミット: ユーザーが設定できるソフトリミットの最大値で、一般ユーザーはこれを引き上げることはできません(rootユーザーのみ可能)。

ulimit -T (RLIMIT_NTHR)

ulimit -T は、NetBSDにおける RLIMIT_NTHR リソース制限に対応します。この制限は、ユーザーIDが同時に持つことができるスレッド(軽量プロセス)の最大数を指定します。カーネルスレッドや各プロセスの初期スレッドは、この制限にはカウントされません。Goのランタイムは、内部でOSスレッドを生成してゴルーチンをスケジューリングするため、このスレッド数制限がGoプログラムの動作に直接影響を与える可能性があります。特に、多数のゴルーチンを同時に実行するテストシナリオでは、この制限に達してしまい、テストが失敗する原因となることがあります。

Goの並行性モデル (Goroutines vs. OS Threads)

Go言語は、並行処理を非常に効率的に扱うために「ゴルーチン(goroutine)」という独自の軽量な並行処理単位を提供しています。ゴルーチンはOSのスレッドよりもはるかに軽量であり、数千、数万といった単位で簡単に生成できます。

Goランタイムは、これらのゴルーチンを「OSスレッド」に多重化(M:Nスケジューリングモデル)して実行します。ここでいうOSスレッドは、オペレーティングシステムが管理する実際のスレッドであり、CPUコア上で実行されます。Goランタイムのスケジューラは、利用可能なCPUコア数に応じてOSスレッドを生成し、その上でゴルーチンを効率的に実行します。もしゴルーチンがI/O操作などでブロックされた場合、Goランタイムは自動的にそのゴルーチンをOSスレッドから切り離し、別の実行可能なゴルーチンをそのOSスレッドに割り当てます。これにより、OSスレッドが常に有効活用され、高い並行性を実現します。

このモデルにおいて、OSがプロセスに課すスレッド数制限は重要です。GoランタイムがOSスレッドを生成する際に、この制限に抵触すると、Goプログラムの実行が妨げられる可能性があります。

src/run.bash

src/run.bash は、Goプロジェクトのテストやツールを実行するための環境をセットアップするシェルスクリプトです。このスクリプトは、Goのテストが正しく機能するために必要な環境変数(例: GOROOT, GOPATH)の設定、エラーハンドリング、そして特定のオペレーティングシステム(OS XやNetBSD/OpenBSDなど)におけるシステムリソース制限(ulimit)の調整など、様々な重要なタスクを実行します。このスクリプトの目的は、Goのテストが安定して実行されるための、一貫した機能的な環境を保証することにあります。

bash 4.2nb3

bash 4.2nb3 は、GNU Bourne-Again Shell (Bash) の特定のバージョンを指します。nb3 という接尾辞は、NetBSD Packages Collection (pkgsrc) におけるNetBSD固有のビルドまたはパッチレベルを示します。このコミットの時点では、ulimit -T オプションがこのバージョン以降のBashでサポートされるようになったため、このバージョンが言及されています。これは、特定のOS環境におけるシェル機能の進化が、Goのようなクロスプラットフォームなプロジェクトのテスト環境設定に影響を与える一例です。

技術的詳細

このコミットの技術的詳細は、src/run.bash スクリプトに ulimit -T オプションを用いたスレッド数制限の調整ロジックを追加した点にあります。

変更されたコードは以下のステップで動作します。

  1. ulimit -T のサポートチェック: if ulimit -T &> /dev/null; then この行は、現在のシェル環境が ulimit -T オプションをサポートしているかどうかをチェックします。ulimit -T を実行し、その標準出力と標準エラー出力を /dev/null にリダイレクトすることで、コマンドの実行結果(成功/失敗)のみを確認します。コマンドが成功すれば(終了ステータスが0)、ulimit -T がサポートされていると判断されます。これにより、ulimit -T をサポートしない古いバージョンのBashや、RLIMIT_NTHR を持たない他のOS上でもスクリプトがエラーなく動作するようになります。

  2. スレッド数制限の設定: [ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T) この行は、ulimit -T がサポートされている場合にのみ実行されます。

    • ulimit -H -T: 現在のハードリミットのスレッド数を取得します。
    • "$(ulimit -H -T)" == "unlimited": ハードリミットが「unlimited」(無制限)であるかどうかをチェックします。
    • ||: 論理OR演算子です。左側のコマンドが失敗した場合(つまり、ハードリミットが unlimited でない場合)にのみ、右側のコマンドが実行されます。
    • ulimit -S -T $(ulimit -H -T): ソフトリミットのスレッド数を、ハードリミットの値に設定します。これにより、プロセスが利用できるスレッドの最大数が、システムが許容する最大値まで引き上げられます。これは、Goのテストが多数のゴルーチンを生成し、それらがOSスレッドにマッピングされる際に、スレッド数制限に達してテストが失敗するのを防ぐために重要です。

この変更により、NetBSD-currentのような特定の環境でGoのテストがより堅牢に実行されるようになります。

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

--- a/src/run.bash
+++ b/src/run.bash
@@ -20,6 +20,11 @@ ulimit -c 0
 [ "$(ulimit -H -n)" == "unlimited" ] || ulimit -S -n $(ulimit -H -n)
 [ "$(ulimit -H -d)" == "unlimited" ] || ulimit -S -d $(ulimit -H -d)
 
+# Thread count limit on NetBSD 7.
+if ulimit -T &> /dev/null; then
+	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
+fi
+
 # allow all.bash to avoid double-build of everything
 rebuild=true
 if [ "$1" = "--no-rebuild" ]; then

コアとなるコードの解説

追加されたコードブロックは、src/run.bash スクリプトの既存の ulimit 設定セクションに組み込まれています。

# Thread count limit on NetBSD 7.
if ulimit -T &> /dev/null; then
	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
fi
  1. # Thread count limit on NetBSD 7. これはコメントであり、このコードブロックがNetBSD 7におけるスレッド数制限に対処するためのものであることを示しています。

  2. if ulimit -T &> /dev/null; then ... fi この if 文は、現在のシェル環境が ulimit -T オプションをサポートしているかどうかをチェックします。

    • ulimit -T: スレッド数制限に関する ulimit コマンドの呼び出し。
    • &> /dev/null: コマンドの標準出力と標準エラー出力を /dev/null にリダイレクトします。これにより、画面に何も表示されず、コマンドの成功/失敗(終了ステータス)のみが評価されます。
    • もし ulimit -T が成功すれば(つまり、サポートされていれば)、then ブロック内のコードが実行されます。これにより、ulimit -T をサポートしないシステムでスクリプトがエラーになるのを防ぎます。
  3. [ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T) この行は、ulimit -T がサポートされている場合に実行されます。

    • $(ulimit -H -T): スレッド数のハードリミットを取得します。
    • [ ... == "unlimited" ]: 取得したハードリミットが文字列 "unlimited" と等しいかどうかをテストします。
    • ||: 論理OR演算子です。左側の条件が偽(false)の場合、つまりハードリミットが "unlimited" でない場合にのみ、右側のコマンドが実行されます。
    • ulimit -S -T $(ulimit -H -T): スレッド数のソフトリミットを、現在のハードリミットの値に設定します。これにより、Goのテストが利用できるスレッドの最大数が、システムが許容する最大値まで引き上げられ、スレッド不足による問題が回避されます。

この変更は、Goのテスト環境の堅牢性を高め、特定のOS環境での互換性問題を解決するために不可欠なものです。

関連リンク

参考にした情報源リンク