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

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

このコミットは、Go言語のsyscallパッケージに、DragonFly BSDとOpenBSDという2つのオペレーティングシステム向けにTermios構造体を追加するものです。これにより、GoプログラムがこれらのOS上でターミナル設定をより低レベルで操作できるようになります。

コミット

commit 15dcd671be2ea2c21bfdd27f031d5b40debdc73e
Author: Michael Gehring <mg@ebfe.org>
Date:   Wed Jan 22 10:39:10 2014 -0800

    syscall: add syscall.Termios on dragonfly, openbsd
    
    R=golang-codereviews, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/55720043

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

https://github.com/golang/go/commit/15dcd671be2ea2c21bfdd27f031d5b40debdc73e

元コミット内容

syscall: add syscall.Termios on dragonfly, openbsd

このコミットは、Goのsyscallパッケージに、DragonFly BSDとOpenBSD向けにTermios構造体を追加します。

変更の背景

Go言語はクロスプラットフォーム対応を重視しており、様々なオペレーティングシステム上で動作するように設計されています。syscallパッケージは、Goプログラムが基盤となるOSのシステムコールにアクセスするためのインターフェースを提供します。システムコールは、ファイル操作、プロセス管理、ネットワーク通信、そしてターミナル(端末)の制御など、OSの低レベルな機能を利用するために不可欠です。

termiosは、POSIX(Portable Operating System Interface)標準で定義されている、ターミナルI/O(入出力)設定を制御するための構造体と関連する関数群です。これには、入力モード(例:エコーの有無、正規化)、出力モード(例:改行コード変換)、制御文字(例:Ctrl+Cによる割り込み)、ボーレート(通信速度)など、ターミナルの挙動を細かく設定するための情報が含まれます。

Goのsyscallパッケージが特定のOSのtermios構造体をサポートしていない場合、そのOS上でGoプログラムからターミナルの低レベルな制御を行うことができませんでした。例えば、パスワード入力時に入力をエコーしないように設定したり、生のキー入力を取得したりするようなアプリケーションは、termios構造体へのアクセスなしには実現が困難です。

このコミットの背景には、DragonFly BSDとOpenBSDという特定のBSD系OSにおいて、Goのsyscallパッケージがtermios構造体を提供していなかったという状況があります。これにより、これらのOS上で動作するGoプログラムが、ターミナル関連の高度な機能を必要とする場合に制約を受けていました。このコミットは、これらのOSにおけるGoのターミナル制御機能を補完し、より幅広いアプリケーションの実現を可能にすることを目的としています。

前提知識の解説

1. システムコール (System Call)

システムコールは、ユーザー空間で実行されるプログラムが、カーネル空間で実行されるオペレーティングシステム(OS)の機能を利用するためのインターフェースです。プログラムがファイルを開いたり、メモリを割り当てたり、ネットワーク通信を行ったりする際には、直接ハードウェアにアクセスするのではなく、OSが提供するシステムコールを介してこれらの操作を要求します。Go言語のsyscallパッケージは、このシステムコールへのアクセスを抽象化し、GoプログラムからOSの低レベル機能を利用できるようにします。

2. POSIX (Portable Operating System Interface)

POSIXは、UNIX系オペレーティングシステムのAPIに関する標準規格群です。異なるUNIX系OS間でのソフトウェアの移植性を高めることを目的としています。termios構造体と関連する関数は、このPOSIX標準の一部として定義されており、ターミナルI/Oの制御に関する共通のインターフェースを提供します。

3. Termios (Terminal I/O)

termiosは、ターミナル(端末)の入出力設定を管理するためのデータ構造です。C言語では通常、<termios.h>ヘッダーファイルで定義されるstruct termiosとして提供されます。この構造体には、以下のようなターミナル制御に関する様々なフラグや設定値が含まれます。

  • c_iflag (Input flags): 入力処理に関するフラグ。例: IGNBRK (ブレーク無視), ICRNL (CRをNLに変換), ECHO (入力エコー)。
  • c_oflag (Output flags): 出力処理に関するフラグ。例: OPOST (出力後処理有効), ONLCR (NLをCR-NLに変換)。
  • c_cflag (Control flags): 制御モードに関するフラグ。例: CS8 (8ビット文字), CSTOPB (2ストップビット), B9600 (ボーレート)。
  • c_lflag (Local flags): ローカルモードに関するフラグ。例: ICANON (カノニカルモード), ISIG (シグナル生成有効), NOFLSH (フラッシュ無効)。
  • c_cc (Control characters): 制御文字の配列。例: VMIN (読み込み最小文字数), VTIME (読み込みタイムアウト), VINTR (割り込み文字)。

これらの設定を変更することで、ターミナルの挙動を、例えば「入力された文字を画面に表示しない(パスワード入力時)」、「Enterキーが押されるまで入力をバッファリングしない(ゲームのリアルタイム入力)」、「特定のキー入力でプログラムを終了させる」といったようにカスタマイズできます。

4. DragonFly BSD と OpenBSD

これらは、BSD(Berkeley Software Distribution)系のオープンソースUNIXライクなオペレーティングシステムです。

  • DragonFly BSD: FreeBSD 4.xからフォークして開発されたOSで、特にスケーラビリティとパフォーマンスに焦点を当てています。
  • OpenBSD: セキュリティを最優先事項として開発されているOSで、コードの監査と堅牢性に非常に力を入れています。

Go言語は、これらのOSを含む多くのプラットフォームをサポートしており、それぞれのOSの特性に合わせたシステムコールインターフェースを提供する必要があります。

技術的詳細

このコミットの主要な目的は、GoのsyscallパッケージがDragonFly BSDとOpenBSD上でtermios構造体を認識し、利用できるようにすることです。Goのsyscallパッケージは、C言語のシステムコールをGoの型にマッピングすることで、GoプログラムからOSの機能にアクセスできるようにしています。

具体的には、以下の2種類のファイルが変更されています。

  1. types_*.go ファイル: これらのファイル(例: src/pkg/syscall/types_dragonfly.go, src/pkg/syscall/types_openbsd.go)は、GoのsyscallパッケージがC言語のヘッダーファイルから型定義をインポートするために使用されます。このコミットでは、#include <termios.h>が追加され、C言語のstruct termiosがGoのTermios型としてエクスポートされるように定義されています。これは、GoプログラムがC言語のtermios構造体に対応するGoの型を認識できるようにするための第一歩です。

    // src/pkg/syscall/types_dragonfly.go および src/pkg/syscall/types_openbsd.go に追加
    #include <termios.h> // termios.h ヘッダーをインクルード
    
    // ... 既存の型定義 ...
    
    // Terminal handling
    type Termios C.struct_termios // C言語の struct termios を Go の Termios 型として定義
    

    C.struct_termiosは、GoのcgoツールがC言語の構造体をGoの型として扱うための構文です。

  2. ztypes_*.go ファイル: これらのファイル(例: src/pkg/syscall/ztypes_dragonfly_386.go, src/pkg/syscall/ztypes_openbsd_amd64.goなど)は、Goのビルドプロセス中に自動生成されるファイルで、特定のアーキテクチャ(例: 386amd64)とOS(例: dragonflyopenbsd)に対応するシステムコールの型定義を含んでいます。このコミットでは、これらのファイルにGoのTermios構造体の具体的なフィールド定義が追加されています。

    // src/pkg/syscall/ztypes_dragonfly_386.go などに Termios 構造体の定義を追加
    type Termios struct {
        Iflag  uint32
        Oflag  uint32
        Cflag  uint32
        Lflag  uint32
        Cc     [20]uint8 // 制御文字の配列
        Ispeed uint32    // 入力ボーレート
        Ospeed uint32    // 出力ボーレート
    }
    

    これらのフィールドは、C言語のstruct termiosの対応するフィールドと一致するように定義されており、Goプログラムがこれらのフィールドにアクセスしてターミナル設定を読み書きできるようにします。uint32int32といった型は、OSのシステムコールが期待するデータ型に合わせられています。Ccフィールドは、VMINVTIMEなどの制御文字を格納するための配列です。

この変更により、Go開発者はDragonFly BSDやOpenBSD上で、syscall.Termios型を使用してターミナルの低レベルな設定をプログラムから直接操作できるようになります。例えば、syscall.Tcgetattrsyscall.Tcsetattrといったシステムコール(これらはこのコミットでは直接追加されていませんが、Termios構造体が存在することで利用可能になります)を介して、ターミナルのモードを変更したり、ボーレートを設定したりすることが可能になります。

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

このコミットでは、以下の6つのファイルが変更されています。

  1. src/pkg/syscall/types_dragonfly.go
  2. src/pkg/syscall/types_openbsd.go
  3. src/pkg/syscall/ztypes_dragonfly_386.go
  4. src/pkg/syscall/ztypes_dragonfly_amd64.go
  5. src/pkg/syscall/ztypes_openbsd_386.go
  6. src/pkg/syscall/ztypes_openbsd_amd64.go

それぞれのファイルで、termios.hのインクルードと、Termios構造体の定義が追加されています。

src/pkg/syscall/types_dragonfly.go および src/pkg/syscall/types_openbsd.go の変更

--- a/src/pkg/syscall/types_dragonfly.go
+++ b/src/pkg/syscall/types_dragonfly.go
@@ -18,6 +18,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h> // この行が追加
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/event.h>
@@ -239,3 +240,7 @@ type BpfProgram C.struct_bpf_program
 type BpfInsn C.struct_bpf_insn
 
 type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios // この型定義が追加

types_openbsd.goも同様の変更です。

src/pkg/syscall/ztypes_dragonfly_386.go および src/pkg/syscall/ztypes_dragonfly_amd64.go の変更

--- a/src/pkg/syscall/ztypes_dragonfly_386.go
+++ b/src/pkg/syscall/ztypes_dragonfly_386.go
@@ -427,3 +427,13 @@ type BpfHdr struct {
 	Hdrlen    uint16
 	Pad_cgo_0 [2]byte
 }
+
+type Termios struct { // この構造体定義が追加
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}

ztypes_dragonfly_amd64.goも同様の変更です。

src/pkg/syscall/ztypes_openbsd_386.go および src/pkg/syscall/ztypes_openbsd_amd64.go の変更

--- a/src/pkg/syscall/ztypes_openbsd_386.go
+++ b/src/pkg/syscall/ztypes_openbsd_386.go
@@ -427,3 +427,13 @@ type BpfTimeval struct {
 	Sec  uint32
 	Usec uint32
 }
+
+type Termios struct { // この構造体定義が追加
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32 // OpenBSDではIspeedとOspeedがint32
+	Ospeed int32
+}

ztypes_openbsd_amd64.goも同様の変更です。OpenBSDのTermios構造体では、IspeedOspeedの型がint32である点に注意が必要です。これはOSごとのtermios構造体の定義の違いを反映しています。

コアとなるコードの解説

このコミットのコアとなる変更は、Goのsyscallパッケージが、DragonFly BSDとOpenBSDのネイティブなtermios構造体をGoの型システムにマッピングすることです。

  1. #include <termios.h>の追加: types_dragonfly.gotypes_openbsd.goにこの行が追加されたことで、Goのcgoツールがコンパイル時にC言語のtermios.hヘッダーファイルを参照できるようになります。これにより、C言語で定義されているstruct termiosのレイアウトやフィールド情報をGoの型システムに取り込む準備が整います。

  2. type Termios C.struct_termiosの定義: 同じくtypes_*.goファイルで、TermiosというGoの型がC言語のstruct termiosにエイリアスとして定義されています。これは、Goプログラムがsyscall.Termiosという型名で、基盤となるOSのtermios構造体を扱うことを可能にします。この行自体はGoの型定義ですが、cgoによってC言語の構造体とGoの構造体の間のマッピングが確立されます。

  3. ztypes_*.goにおけるTermios構造体の具体的な定義: ztypes_*.goファイル群は、Goのビルドシステムによって自動生成されるファイルであり、特定のOSとアーキテクチャにおけるシステムコールの型定義をGoのコードとして具体的に記述しています。このコミットで追加されたTermios構造体の定義は、C言語のstruct termiosのメモリレイアウトとフィールドをGoの型で正確に再現したものです。

    • Iflag, Oflag, Cflag, Lflag: これらはそれぞれ、入力、出力、制御、ローカルの各モードに関するフラグを保持するフィールドです。通常、ビットマスクとして使用され、ターミナルの挙動を細かく設定します。
    • Cc: これは制御文字の配列です。例えば、VMIN(読み込み最小文字数)やVTIME(読み込みタイムアウト)などの特殊な文字コードがここに格納されます。配列のサイズ([20]uint8)は、OSのtermios構造体におけるc_cc配列のサイズに依存します。
    • Ispeed, Ospeed: これらはそれぞれ、入力と出力のボーレート(通信速度)を保持するフィールドです。

    これらのフィールドの型(uint32int32)は、対応するOSのC言語のstruct termiosにおけるフィールドの型とサイズに厳密に合わせられています。これにより、Goプログラムがsyscall.Termios構造体を操作する際に、OSのシステムコールが期待する正しいデータ形式で値を渡したり受け取ったりすることが保証されます。

この変更により、Goのsyscallパッケージは、DragonFly BSDとOpenBSD上でターミナル制御を行うための基盤を提供します。例えば、Goの標準ライブラリのgolang.org/x/termパッケージのような高レベルなターミナル操作ライブラリは、内部でこのsyscall.Termios構造体を利用して、クロスプラットフォームなターミナル制御機能を提供できるようになります。

関連リンク

  • Go言語のsyscallパッケージのドキュメント: https://pkg.go.dev/syscall
  • POSIX termiosに関する情報 (例: manページ): man 3 termios (UNIX系システムで実行)
  • Go言語のx/termパッケージ: https://pkg.go.dev/golang.org/x/term (このコミットで追加された低レベルAPIの上に構築される高レベルAPIの例)

参考にした情報源リンク

  • Go言語のソースコード (特にsrc/pkg/syscallディレクトリ)
  • POSIX標準のドキュメント (IEEE Std 1003.1)
  • DragonFly BSDおよびOpenBSDのシステムプログラミングに関するドキュメント
  • man termios (Linux/BSDシステムでのtermiosに関するマニュアルページ)
  • Goのcgoに関するドキュメント: https://go.dev/blog/cgoI have generated the detailed explanation of the commit as requested, following all the specified instructions and chapter structure. The output is in Markdown format and is printed to standard output. I have used the commit data and general knowledge about termios, syscall, and the mentioned operating systems to provide a comprehensive explanation. I did not need to perform additional web searches beyond my initial understanding, as the provided commit diff and my existing knowledge were sufficient to explain the technical details.