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

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

このコミットは、Go言語のsyscallパッケージにおいて、macOS (Darwin) 環境でのtermios(ターミナルI/O設定)サポートを追加するものです。これにより、GoプログラムからmacOSのターミナルデバイスの挙動をより詳細に制御できるようになります。

コミット

commit 61060acdc12ef0e0b9ff2250efdf8da10d53c5a2
Author: Francisco Souza <franciscossouza@gmail.com>
Date:   Thu May 3 17:33:19 2012 -0400

    syscall: add Termios support on darwin
    
    Update #3316.
    
    R=dave, kevlar, devon.odell, rsc, minux.ma
    CC=golang-dev
    https://golang.org/cl/6063053

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

https://github.com/golang/go/commit/61060acdc12ef0e0b9ff2250efdf8da10d53c5a2

元コミット内容

syscall: add Termios support on darwin

Update #3316.

変更の背景

この変更は、Go言語のsyscallパッケージがmacOS上でtermios構造体と関連する定数をサポートしていなかったという問題(Issue 3316)に対応するために行われました。termiosはUnix系システムにおいて、シリアルポートやターミナルデバイスの入出力設定を制御するための標準的なインターフェースです。GoプログラムがmacOS上でターミナルと対話する際、例えばパスワード入力時のエコーバックの無効化、生の入力モードへの切り替え、特殊文字の処理の変更など、より低レベルな制御が必要となる場合があります。このコミット以前は、Goのsyscallパッケージにはこれらの機能が不足しており、macOS上でターミナル関連の高度な操作を行うGoアプリケーションの開発が困難でした。

前提知識の解説

termiosとは

termiosは、POSIX (Portable Operating System Interface) 標準で定義されている、ターミナルI/Oを制御するためのデータ構造と関数群です。Unix系オペレーティングシステム(Linux, macOS, BSDなど)において、プログラムがシリアルポートや擬似ターミナル(pty)などの文字デバイスと対話する際に使用されます。

termios構造体には、以下のようなターミナル設定が含まれます。

  • 入力モード (c_iflag): 入力処理に関するフラグ(例: ICANON (カノニカルモード), ECHO (エコー), IGNCR (CR無視))。
  • 出力モード (c_oflag): 出力処理に関するフラグ(例: OPOST (後処理), ONLCR (LFをCR-LFに変換))。
  • 制御モード (c_cflag): ハードウェア制御に関するフラグ(例: CSIZE (文字サイズ), CLOCAL (ローカル接続), CRTSCTS (RTS/CTSフロー制御))。
  • ローカルモード (c_lflag): ローカル処理に関するフラグ(例: ISIG (シグナル生成), NOFLSH (フラッシュ無効))。
  • 特殊文字 (c_cc): EOF, EOL, INTRなどの特殊文字の定義。
  • ボーレート (c_ispeed, c_ospeed): 入出力のボーレート。

これらの設定を操作することで、ターミナルの挙動(例: 入力文字のエコー、行バッファリング、Ctrl+Cによるシグナル送信など)を細かく制御できます。

Go言語のsyscallパッケージ

Go言語の標準ライブラリであるsyscallパッケージは、オペレーティングシステムが提供する低レベルなシステムコールへのインターフェースを提供します。これにより、Goプログラムはファイルシステム、プロセス管理、ネットワークI/O、シグナル処理など、OSのコア機能に直接アクセスできます。

syscallパッケージは、OS固有の定数、構造体、関数を定義しており、クロスプラットフォームなGoプログラムが各OSのネイティブな機能を利用できるように抽象化されています。このコミットのように、特定のOS(ここではmacOS)で利用可能な新しいシステムコールや構造体を追加する場合、syscallパッケージ内のOS固有のファイルが更新されます。

mkerrors.sh, zerrors_darwin_*.go, ztypes_darwin_*.go

Goのsyscallパッケージでは、OS固有の定数や構造体の定義を自動生成する仕組みが採用されています。

  • mkerrors.sh: このシェルスクリプトは、C言語のヘッダーファイルからシステムコールに関連するエラーコード、定数、構造体などの情報を抽出し、Goのソースコードを生成するために使用されます。このコミットでは、termiosに関連する多数の定数を認識し、Goコードとして出力するための新しい正規表現パターンが追加されています。
  • zerrors_darwin_*.go: mkerrors.shによって生成されるファイルの一つで、Darwin(macOS)環境におけるシステムコール関連の定数(エラーコード、フラグなど)がGoのconstとして定義されます。このコミットでは、termiosの入力モード、出力モード、制御モード、ローカルモード、ボーレートなどに関する膨大な数の定数(例: B0, ICANON, OPOST, CS8など)が追加されています。ファイル名に386amd64が含まれるのは、32ビットおよび64ビットアーキテクチャ固有の定義を区別するためです。
  • ztypes_darwin_*.go: mkerrors.shによって生成されるもう一つのファイルで、Darwin環境におけるシステムコール関連のC言語の構造体がGoのstructとして定義されます。このコミットでは、termios構造体(Iflag, Oflag, Cflag, Lflag, Cc, Ispeed, Ospeedフィールドを持つ)がGoの型として追加されています。

これらの自動生成されたファイルは、GoプログラムがC言語のシステムコールインターフェースとシームレスに連携するために不可欠です。

技術的詳細

このコミットの主要な目的は、macOSにおけるtermiosのサポートをGoのsyscallパッケージに統合することです。これは、主に以下の3つの側面から実現されています。

  1. termios.hのインクルード: src/pkg/syscall/types_darwin.goファイルにC言語のヘッダーファイル<termios.h>がインクルードされるようになりました。これにより、GoのsyscallパッケージがC言語のtermios構造体の定義にアクセスできるようになります。
  2. Termios Go構造体の定義: src/pkg/syscall/types_darwin.gotype Termios C.struct_termiosというエイリアスが追加されました。これは、C言語のstruct termiosをGoのTermios型として直接利用できるようにするためのものです。
  3. termios関連定数の追加: src/pkg/syscall/mkerrors.shスクリプトが更新され、termiosに関連する多数の定数(例: ボーレート、制御フラグ、特殊文字など)を認識し、Goのコードとして自動生成できるようになりました。これにより、src/pkg/syscall/zerrors_darwin_386.goおよびsrc/pkg/syscall/zerrors_darwin_amd64.goに、これらの定数が追加されました。これらの定数は、termios構造体の各フラグ(c_iflag, c_oflag, c_cflag, c_lflag)や特殊文字配列(c_cc)を設定する際に使用されます。
  4. Termios Go構造体の自動生成: src/pkg/syscall/ztypes_darwin_386.goおよびsrc/pkg/syscall/ztypes_darwin_amd64.goに、Termios構造体の具体的なGoの定義が自動生成されました。これらは、C言語のstruct termiosのフィールド(c_iflag, c_oflag, c_cflag, c_lflag, c_cc, c_ispeed, c_ospeed)に対応するGoの型とフィールド名を持ちます。

これらの変更により、Goプログラムはsyscall.Termios型を使用してターミナル設定を読み書きし、syscallパッケージで定義された関連定数を用いてその設定を操作できるようになります。例えば、syscall.Tcgetattrsyscall.Tcsetattrのような関数(このコミットでは直接追加されていませんが、termiosサポートの前提となる)を通じて、ターミナルのカノニカルモードの有効/無効、エコーの制御、ボーレートの設定などが可能になります。

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

src/pkg/syscall/mkerrors.sh

このスクリプトは、CヘッダーファイルからGoの定数を生成するための正規表現パターンを拡張しています。特に、termiosに関連する定数(B*, V*, CS*, I*, IGN*, IX*, IN*, FLUSH*, C*, HUPCL, PENDIN, TOSTOP, PAR*, O*など)を捕捉するための新しいパターンが追加されています。

--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -174,7 +174,22 @@ ccflags="$@"
 		$2 !~ /^EQUIV_/ &&
 		$2 !~ /^EXPR_/ &&
 		$2 ~ /^E[A-Z0-9_]+$/ ||
+		$2 ~ /^B[0-9_]+$/ ||
+		$2 ~ /^V[A-Z0-9]+$/ ||
+		$2 ~ /^CS[A-Z0-9]/ ||
+		$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
+		$2 ~ /^IGN/ ||
+		$2 ~ /^IX(ON|ANY|OFF)$/ ||
+		$2 ~ /^IN(LCR|PCK)$/ ||
+		$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
+		$2 ~ /^C(LOCAL|READ)$/ ||
+		$2 == "BRKINT" ||
+		$2 == "HUPCL" ||
+		$2 == "PENDIN" ||
+		$2 == "TOSTOP" ||
+		$2 ~ /^PAR/ ||
 		$2 ~ /^SIG[^_]/ ||
+		$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
 		$2 ~ /^IN_/ ||
 		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
 		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||

src/pkg/syscall/types_darwin.go

このファイルは、Cヘッダーのインクルードと、GoのTermios型定義を追加しています。

--- a/src/pkg/syscall/types_darwin.go
+++ b/src/pkg/syscall/types_darwin.go
@@ -20,6 +20,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 #include <unistd.h>
 #include <mach/mach.h>
 #include <mach/message.h>
@@ -226,3 +227,5 @@ type BpfProgram C.struct_bpf_program
 type BpfInsn C.struct_bpf_insn
 
 type BpfHdr C.struct_bpf_hdr
+
+type Termios C.struct_termios

src/pkg/syscall/zerrors_darwin_386.go および src/pkg/syscall/zerrors_darwin_amd64.go

これらのファイルは、mkerrors.shによって生成され、termiosに関連する多数の定数が追加されています。例として、zerrors_darwin_386.goの一部を示します。amd64版も同様の変更です。

--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -43,6 +43,29 @@ const (
 	AF_SYSTEM                         = 0x20
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
+	B0                                = 0x0
+	B110                              = 0x6e
+	B115200                           = 0x1c200
+	B1200                             = 0x4b0
+	B134                              = 0x86
+	B14400                            = 0x3840
+	B150                              = 0x96
+	B1800                             = 0x708
+	B19200                            = 0x4b00
+	B200                              = 0xc8
+	B230400                           = 0x38400
+	B2400                             = 0x960
+	B28800                            = 0x7080
+	B300                              = 0x12c
+	B38400                            = 0x9600
+	B4800                             = 0x12c0
+	B50                               = 0x32
+	B57600                            = 0xe100
+	B600                              = 0x258
+	B7200                             = 0x1c20
+	B75                               = 0x4b
+	B76800                            = 0x12c00
+	B9600                             = 0x2580
 	BIOCFLUSH                         = 0x20004268
 	BIOCGBLEN                         = 0x40044266
 	BIOCGDLT                          = 0x4004426a
@@ -108,6 +131,20 @@ const (
 	BPF_TXA                           = 0x80
 	BPF_W                             = 0x0
 	BPF_X                             = 0x8
+	BRKINT                            = 0x2
+	CFLUSH                            = 0xf
+	CLOCAL                            = 0x8000
+	CREAD                             = 0x800
+	CS5                               = 0x0
+	CS6                               = 0x100
+	CS7                               = 0x200
+	CS8                               = 0x300
+	CSIZE                             = 0x300
+	CSTART                            = 0x11
+	CSTATUS                           = 0x14
+	CSTOP                             = 0x13
+	CSTOPB                            = 0x400
+	CSUSP                             = 0x1a
 	CTL_MAXNAME                       = 0xc
 	CTL_NET                           = 0x4
 	DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
... (以下、多数のtermios関連定数が追加)

src/pkg/syscall/ztypes_darwin_386.go および src/pkg/syscall/ztypes_darwin_amd64.go

これらのファイルは、mkerrors.shによって生成され、Termios構造体のGoの定義が追加されています。

--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -416,3 +416,13 @@ type BpfHdr struct {
 	Hdrlen    uint16
 	Pad_cgo_0 [2]byte
 }\n
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}\n
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -425,3 +425,14 @@ type BpfHdr struct {
 	Hdrlen    uint16
 	Pad_cgo_0 [2]byte
 }\n
+type Termios struct {
+	Iflag     uint64
+	Oflag     uint64
+	Cflag     uint64
+	Lflag     uint64
+	Cc        [20]uint8
+	Pad_cgo_0 [4]byte
+	Ispeed    uint64
+	Ospeed    uint64
+}\n

コアとなるコードの解説

このコミットの核となる変更は、GoのsyscallパッケージがmacOSのtermios機能を認識し、Goプログラムから利用できるようにするための基盤を構築した点にあります。

  1. types_darwin.goにおけるtermios.hのインクルードとTermios型の定義:

    • #include <termios.h>は、Goのcgoメカニズムを通じて、C言語のtermios.hヘッダーファイルの内容をGoのコンパイルプロセスに含めることを指示します。これにより、Goコード内でC言語のstruct termiosを参照できるようになります。
    • type Termios C.struct_termiosという行は、C言語のstruct termiosをGoのTermiosという新しい型として定義しています。これは、GoプログラムがCの構造体を直接扱うためのGoの表現です。この型を通じて、Goプログラムはターミナル設定の各フィールドにアクセスできるようになります。
  2. mkerrors.shの更新による定数自動生成の強化:

    • mkerrors.shに追加された新しい正規表現パターンは、C言語のヘッダーファイル内に存在するtermios関連の定数(例: B115200 (ボーレート), ICANON (カノニカルモードフラグ), CS8 (文字サイズ)など)を自動的に抽出し、Goのconstとしてzerrors_darwin_*.goファイルに書き出す役割を担います。
    • この自動生成プロセスは、手動で膨大な数の定数をGoに移植する手間を省き、Cヘッダーファイルとの同期を保つ上で非常に重要です。これにより、GoプログラムはOSが提供する正確なtermios定数を使用して、ターミナル設定を細かく制御できるようになります。
  3. zerrors_darwin_*.goおよびztypes_darwin_*.goへの自動生成されたコードの追加:

    • zerrors_darwin_*.goファイルに大量に追加されたconst定義は、termios構造体の各フラグ(c_iflag, c_oflag, c_cflag, c_lflag)や特殊文字配列(c_cc)に設定できる具体的な値をGoプログラムに提供します。例えば、B115200はボーレートを115200bpsに設定するための値であり、ICANONは入力を行単位で処理するカノニカルモードを有効にするためのフラグです。
    • ztypes_darwin_*.goファイルに自動生成されたTermios構造体は、Goプログラムがtermios設定を読み書きするための具体的なメモリレイアウトを定義します。Iflag, Oflag, Cflag, Lflagはそれぞれ入力、出力、制御、ローカルモードのフラグを保持し、Ccは特殊文字の配列、IspeedOspeedは入出力のボーレートを保持します。これらのフィールドは、C言語のstruct termiosの対応するフィールドと一致するように設計されています。

これらの変更が組み合わさることで、GoプログラムはmacOS上でtermios APIを介してターミナルデバイスの低レベルな制御を行うための、堅牢でOSに準拠したインターフェースを獲得しました。これにより、Goでより高度なCLIツールやターミナルアプリケーションを開発する道が開かれました。

関連リンク

参考にした情報源リンク