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

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

このコミットは、Go言語のsyscallパッケージにFreeBSDシステム(386およびamd64アーキテクチャ)向けのTermios構造体を追加するものです。これにより、GoプログラムからFreeBSDのターミナルI/O制御機能にアクセスできるようになります。

コミット

commit 5ce3e6a1efd834189057002e6b28180dee5657d4
Author: Michael Gehring <mg@ebfe.org>
Date:   Mon Jan 13 13:57:38 2014 -0800

    syscall: add syscall.Termios on freebsd/{386,amd64}
    
    R=golang-codereviews, bradfitz, mg
    CC=golang-codereviews
    https://golang.org/cl/51580044

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

https://github.com/golang/go/commit/5ce3e6a1efd834189057002e6b28180dee5657d4

元コミット内容

syscall: add syscall.Termios on freebsd/{386,amd64}

このコミットは、FreeBSDの32ビット(386)および64ビット(amd64)アーキテクチャにおいて、syscallパッケージにTermios構造体を追加します。

変更の背景

Go言語のsyscallパッケージは、オペレーティングシステムが提供する低レベルのシステムコールへのインターフェースを提供します。これにより、GoプログラムはOSのカーネル機能に直接アクセスできます。ターミナル(TTY)のI/O制御は、プログラムがユーザーとの対話において、入力のエコー、行バッファリング、特殊文字の処理などを細かく制御するために不可欠な機能です。

FreeBSDを含む多くのUnix系システムでは、ターミナル設定はtermios構造体と関連する関数(tcgetattr, tcsetattrなど)を通じて行われます。GoプログラムがこれらのOSレベルのターミナル制御機能を利用するためには、Goの型システムに対応するtermios構造体の定義が必要でした。このコミットは、FreeBSD環境でGoプログラムがターミナル設定を操作できるように、この重要な構造体をsyscallパッケージに追加することを目的としています。

前提知識の解説

システムコール (System Call)

システムコールは、ユーザー空間で実行されるプログラムが、カーネル空間で提供されるサービス(ファイルI/O、プロセス管理、メモリ管理、ネットワーク通信など)を要求するためのインターフェースです。Goのsyscallパッケージは、これらのOS固有のシステムコールをGoの関数としてラップし、Goプログラムから安全かつ効率的に呼び出せるようにします。

ターミナルI/O制御 (Terminal I/O Control)

ターミナルI/O制御は、シリアルポートや仮想ターミナルデバイスを介したデータの送受信方法を管理するメカニズムです。これには以下のような設定が含まれます。

  • 入力モード (Input Modes): 入力文字の処理方法(例: エコーの有無、行バッファリングの有無、特殊文字の解釈)。
  • 出力モード (Output Modes): 出力文字の処理方法(例: 改行コードの変換)。
  • 制御モード (Control Modes): ハードウェア制御(例: ボーレート、データビット、パリティ)。
  • ローカルモード (Local Modes): 端末ドライバの動作(例: シグナル生成、フロー制御)。
  • 特殊文字 (Special Characters): EOF、中断、サスペンドなどの特殊な制御文字。

これらの設定は、通常、C言語のtermios.hヘッダーファイルで定義されているstruct termios構造体を通じて行われます。

termios構造体

termios構造体は、ターミナルデバイスの現在の設定を保持するためのデータ構造です。主要なメンバーは以下の通りです。

  • c_iflag (input flags): 入力モードフラグ
  • c_oflag (output flags): 出力モードフラグ
  • c_cflag (control flags): 制御モードフラグ
  • c_lflag (local flags): ローカルモードフラグ
  • c_cc (control characters): 特殊制御文字の配列

これらのフラグはビットマスクとして機能し、複数の設定を同時に有効または無効にできます。

FreeBSD

FreeBSDは、UNIXをベースとしたオープンソースのオペレーティングシステムです。堅牢性、高性能、セキュリティに優れており、サーバー、組み込みシステム、デスクトップなど幅広い用途で利用されています。Go言語は、FreeBSDを含む複数のOSをサポートしており、各OSのシステムコールにアクセスするためのプラットフォーム固有のコードをsyscallパッケージ内に持っています。

技術的詳細

このコミットの技術的な核心は、FreeBSDのC言語ヘッダーファイルで定義されているstruct termiosを、Go言語の型システムにマッピングすることです。

  1. src/pkg/syscall/types_freebsd.goの変更:

    • #include <termios.h>が追加されました。これにより、GoのCgoメカニズムを通じて、C言語のtermios構造体の定義がGoのビルドプロセスに利用可能になります。
    • type Termios C.struct_termiosというエイリアスが追加されました。これは、C言語のstruct termiosをGoのTermios型として利用できるようにするためのものです。Goのsyscallパッケージでは、C言語の構造体を直接Goの型として扱うために、このようなエイリアスが一般的に使用されます。
  2. src/pkg/syscall/ztypes_freebsd_386.goおよびsrc/pkg/syscall/ztypes_freebsd_amd64.goの変更:

    • これらのファイルは、Goのビルドプロセス中に自動生成されることが多い、プラットフォーム固有の型定義を含んでいます。このコミットでは、Termios構造体のGo言語での具体的なレイアウトが、386(32ビット)とamd64(64ビット)の両アーキテクチャ向けに定義されました。
    • 定義されたTermios構造体は、C言語のstruct termiosのメンバーに対応するGoのフィールドを持っています。
      • Iflag, Oflag, Cflag, Lflag: これらはそれぞれC言語のc_iflag, c_oflag, c_cflag, c_lflagに対応し、ターミナルモードのフラグを保持します。Goでは通常、Cのunsigned intlonguint32またはuint64にマッピングされます。FreeBSDのtermiosではこれらはtcflag_t型であり、通常はunsigned longまたはunsigned intです。
      • Cc [20]uint8: これはC言語のc_cc配列に対応します。c_ccは特殊制御文字を格納するための配列で、そのサイズはシステムによって異なりますが、FreeBSDでは通常NCCSマクロで定義され、20バイトが一般的です。
      • Ispeed, Ospeed: これらはそれぞれ入力および出力ボーレートを保持します。C言語ではspeed_t型であり、通常はunsigned intです。

これらの変更により、GoプログラムはFreeBSD上でsyscall.Termios型を使用してターミナル設定を取得、変更できるようになり、例えば、パスワード入力時のエコーを無効にしたり、非カノニカルモードで文字単位の入力を処理したりするような高度なターミナルアプリケーションを開発することが可能になります。

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

src/pkg/syscall/types_freebsd.go

--- a/src/pkg/syscall/types_freebsd.go
+++ b/src/pkg/syscall/types_freebsd.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>
@@ -248,3 +249,7 @@ type BpfInsn C.struct_bpf_insn
 type BpfHdr C.struct_bpf_hdr
 
 type BpfZbufHeader C.struct_bpf_zbuf_header
+
+// Terminal handling
+
+type Termios C.struct_termios

src/pkg/syscall/ztypes_freebsd_386.go

--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -443,3 +443,13 @@ type BpfZbufHeader struct {
 	User_gen   uint32
 	X_bzh_pad  [5]uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}

src/pkg/syscall/ztypes_freebsd_amd64.go

--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -446,3 +446,13 @@ type BpfZbufHeader struct {
 	User_gen   uint32
 	X_bzh_pad  [5]uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}

コアとなるコードの解説

src/pkg/syscall/types_freebsd.go

このファイルは、FreeBSDシステムコールに関連するGoの型定義の基盤となります。

  • #include <termios.h>: Cgoディレクティブにより、C言語のtermios.hヘッダーファイルがインクルードされます。これにより、GoのビルドツールはC言語のstruct termiosの定義を認識し、Goの型にマッピングできるようになります。
  • type Termios C.struct_termios: これはGoの型エイリアスです。C言語のstruct termiosをGoのTermios型として利用できるようにします。Goのsyscallパッケージでは、OS固有のC構造体をGoの型として公開する際にこのパターンがよく用いられます。これにより、GoプログラムはC言語の構造体と互換性のあるメモリレイアウトを持つGoの構造体を扱うことができます。

src/pkg/syscall/ztypes_freebsd_386.go および src/pkg/syscall/ztypes_freebsd_amd64.go

これらのファイルは、Goのgo tool cgoによって生成される、プラットフォームおよびアーキテクチャ固有の型定義を含んでいます。これらは、C言語の構造体のメモリレイアウトをGoの構造体として正確に再現するために必要です。

  • type Termios struct { ... }:
    • Iflag, Oflag, Cflag, Lflag: これらはそれぞれ、入力、出力、制御、ローカルの各モードフラグに対応します。Goではuint32型として定義されており、これはFreeBSDのtcflag_t型(通常はunsigned intまたはunsigned long)のサイズとアラインメントに合致するように選択されています。これらのフィールドは、ターミナルの動作を制御するビットマスクを保持します。
    • Cc [20]uint8: これは、特殊制御文字(例: EOF、行削除、中断など)を格納するための配列です。FreeBSDのtermios構造体におけるc_cc配列のサイズ(NCCSマクロで定義)が20バイトであることに対応しています。uint8の配列として定義することで、各バイトが制御文字を表します。
    • Ispeed, Ospeed: これらはそれぞれ、入力および出力のボーレート(通信速度)を保持します。Goではuint32型として定義されており、FreeBSDのspeed_t型(通常はunsigned int)に対応します。

これらの定義により、GoプログラムはFreeBSDのシステムコール(例: syscall.Tcgetattr, syscall.Tcsetattr)を呼び出す際に、このTermios構造体を引数として渡し、ターミナル設定の取得や変更を行うことができるようになります。これは、GoでインタラクティブなCLIツールやシェルを開発する上で不可欠な機能です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • FreeBSDの公式マニュアルページ
  • Unix系システムのターミナルI/O制御に関する一般的な情報源 (例: POSIX標準)
  • GitHub上のGo言語リポジトリのソースコード
  • Go言語のコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/51580044