[インデックス 18292] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにNetBSD向けのTermios
構造体を追加するものです。これにより、GoプログラムからNetBSDシステム上でターミナル設定を操作するための低レベルなインターフェースが提供されます。
コミット
commit 081e2d01535f648d28813e81fe6e1ce74eb6b579
Author: Michael Gehring <mg@ebfe.org>
Date: Sun Jan 19 09:57:02 2014 -0800
syscall: add syscall.Termios on netbsd
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/54290043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/081e2d01535f648d28813e81fe6e1ce74eb6b579
元コミット内容
syscall: add syscall.Termios on netbsd
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/54290043
変更の背景
Go言語のsyscall
パッケージは、オペレーティングシステムが提供する低レベルなシステムコールへのインターフェースを提供します。これにより、GoプログラムはOSの機能に直接アクセスできます。このコミットが行われた2014年当時、Goは様々なOSへの対応を進めており、特にUnix系OSにおけるターミナル制御は重要な機能の一つでした。
termios
構造体は、POSIXシステム(Unix系OS)において、シリアルポートやターミナルデバイスの属性(ボーレート、文字サイズ、パリティ、フロー制御、特殊文字など)を制御するために使用されます。Go言語でNetBSDシステム上でターミナル関連の操作(例: stty
コマンドのような機能の実装、インタラクティブなCLIアプリケーションの作成)を行うためには、このtermios
構造体とそれに関連するシステムコール(tcgetattr
, tcsetattr
など)へのアクセスが必要不可欠でした。
このコミットは、NetBSD環境におけるGoプログラムのターミナル制御機能を強化し、より幅広いシステムプログラミングのユースケースに対応できるようにすることを目的としています。
前提知識の解説
1. システムコール (System Call)
システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で動作するOSの機能(ファイルI/O、プロセス管理、メモリ管理、ネットワーク通信など)を利用するためのインターフェースです。Go言語のsyscall
パッケージは、これらのシステムコールをGoの関数としてラップし、GoプログラムからOSの低レベル機能にアクセスできるようにします。
2. termios
(Terminal I/O)
termios
は、Unix系オペレーティングシステムにおけるターミナルI/O(入出力)の制御メカニズムです。これは、termios.h
ヘッダーファイルで定義される構造体と、それに関連する関数群(tcgetattr
, tcsetattr
, cfsetispeed
, cfsetospeed
など)から構成されます。
termios
構造体には、以下のようなターミナル設定が含まれます。
c_iflag
(Input flags): 入力モードフラグ。入力処理(例: エコー、改行変換、特殊文字の処理)を制御します。c_oflag
(Output flags): 出力モードフラグ。出力処理(例: 改行変換、タブ展開)を制御します。c_cflag
(Control flags): 制御モードフラグ。ハードウェア制御(例: ボーレート、文字サイズ、パリティ、フロー制御)を制御します。c_lflag
(Local flags): ローカルモードフラグ。ローカル処理(例: カノニカルモード、エコー、シグナル生成)を制御します。c_cc
(Control characters): 制御文字配列。EOF、EOL、INTRなどの特殊文字の定義が含まれます。c_ispeed
(Input speed): 入力ボーレート。c_ospeed
(Output speed): 出力ボーレート。
これらのフラグや設定を操作することで、ターミナルの挙動を細かく制御できます。例えば、パスワード入力時に入力文字をエコーしないようにしたり、行バッファリングを無効にして文字単位の入力を受け付けたりすることが可能です。
3. NetBSD
NetBSDは、BSD系Unixライクなオープンソースのオペレーティングシステムです。移植性が非常に高く、様々なハードウェアアーキテクチャで動作することで知られています。Go言語は、このような多様なOS環境をサポートすることを目指しており、各OS固有のシステムコールやデータ構造への対応が不可欠です。
4. Cgo
Go言語は、C言語のコードをGoプログラムから呼び出すためのcgo
というメカニズムを提供します。syscall
パッケージの多くの部分は、C言語で定義されたOSのデータ構造や関数をGoの型や関数にマッピングするためにcgo
を利用しています。このコミットでも、C言語のstruct termios
をGoのsyscall.Termios
型にマッピングするためにcgo
の機能が間接的に利用されています。具体的には、#include <termios.h>
というCヘッダーのインクルードがその証拠です。
技術的詳細
このコミットの主要な目的は、NetBSDシステムにおけるtermios
構造体をGoのsyscall
パッケージで利用可能にすることです。これは以下のステップで実現されています。
-
termios.h
のインクルード:src/pkg/syscall/types_netbsd.go
ファイルに#include <termios.h>
が追加されています。これは、cgo
がC言語のヘッダーファイルを読み込み、その中で定義されている型や定数をGoのコードから利用できるようにするための指示です。これにより、C言語のstruct termios
の定義がGoのビルドプロセスに認識されます。 -
Termios
型の定義:src/pkg/syscall/types_netbsd.go
において、type Termios C.struct_termios
というエイリアスが追加されています。これは、C言語のstruct termios
をGoのsyscall.Termios
型として扱うことを宣言しています。これにより、Goプログラム内でsyscall.Termios
という型名を使ってターミナル設定を表現できるようになります。 -
アーキテクチャ固有の
Termios
構造体の定義: NetBSDは複数のCPUアーキテクチャ(386, amd64, armなど)をサポートしています。各アーキテクチャにおいて、C言語のstruct termios
のメモリレイアウトやフィールドのサイズが異なる場合があります。このため、src/pkg/syscall/ztypes_netbsd_386.go
,src/pkg/syscall/ztypes_netbsd_amd64.go
,src/pkg/syscall/ztypes_netbsd_arm.go
の各ファイルに、それぞれのアーキテクチャに対応するTermios
構造体が明示的に定義されています。これらの構造体は、C言語の
struct termios
のGoにおけるミラーリングであり、Goの型システムに適合するようにGoのプリミティブ型(uint32
,int32
,uint8
など)でフィールドが定義されています。例えば、Cc
フィールドは制御文字を格納するための配列であり、NetBSDでは20バイトのuint8
配列として定義されています。type Termios struct { Iflag uint32 Oflag uint32 Cflag uint32 Lflag uint32 Cc [20]uint8 // Control characters Ispeed int32 Ospeed int32 }
この定義により、Goプログラムは
syscall.Termios
型のインスタンスを作成し、そのフィールドを読み書きすることで、NetBSDのターミナル設定を操作できるようになります。
この変更は、Goのsyscall
パッケージが各OSの低レベルなAPIをGoの型システムに適合させるための典型的なアプローチを示しています。cgo
とアーキテクチャ固有の型定義を組み合わせることで、Goは多様なプラットフォームで一貫したシステムプログラミングインターフェースを提供しています。
コアとなるコードの変更箇所
このコミットによる変更は、以下の4つのファイルにわたっています。
-
src/pkg/syscall/types_netbsd.go
:#include <termios.h>
の追加。type Termios C.struct_termios
の追加。
-
src/pkg/syscall/ztypes_netbsd_386.go
:type Termios struct { ... }
の定義(386アーキテクチャ向け)。
-
src/pkg/syscall/ztypes_netbsd_amd64.go
:type Termios struct { ... }
の定義(amd64アーキテクチャ向け)。
-
src/pkg/syscall/ztypes_netbsd_arm.go
:type Termios struct { ... }
の定義(ARMアーキテクチャ向け)。
コアとなるコードの解説
src/pkg/syscall/types_netbsd.go
--- a/src/pkg/syscall/types_netbsd.go
+++ b/src/pkg/syscall/types_netbsd.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/param.h>
@@ -222,6 +223,10 @@ type BpfHdr C.struct_bpf_hdr
type BpfTimeval C.struct_bpf_timeval
+// Terminal handling
+//
+type Termios C.struct_termios // <-- 追加
+
// Sysctl
type Sysctlnode C.struct_sysctlnode
このファイルは、NetBSD固有のシステムコール関連の型定義やCヘッダーのインクルードを管理しています。
#include <termios.h>
の追加は、C言語のtermios
関連の定義をGoのビルドシステムに認識させるための重要なステップです。これにより、C.struct_termios
という形でCの構造体を参照できるようになります。
type Termios C.struct_termios
は、Goのsyscall
パッケージ内でTermios
という型名を使ってC言語のstruct termios
を参照するためのエイリアスを定義しています。これにより、GoのコードからよりGoらしいシンタックスでターミナル設定を扱えるようになります。
src/pkg/syscall/ztypes_netbsd_386.go
, src/pkg/syscall/ztypes_netbsd_amd64.go
, src/pkg/syscall/ztypes_netbsd_arm.go
これらのファイルは、Goのビルドプロセスによって自動生成されることが多い(z
プレフィックスがその慣習を示す)アーキテクチャ固有の型定義を含んでいます。各ファイルには、それぞれのCPUアーキテクチャにおけるstruct termios
のGo言語での表現が定義されています。
例として、src/pkg/syscall/ztypes_netbsd_amd64.go
の変更を見てみましょう。他のアーキテクチャのファイルも同様の構造です。
--- a/src/pkg/syscall/ztypes_netbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_netbsd_amd64.go
@@ -377,6 +377,16 @@ type BpfTimeval struct {
Usec int64
}
+type Termios struct { // <-- 追加
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
type Sysctlnode struct {
Flags uint32
Num int32
ここで定義されているTermios
構造体は、C言語のstruct termios
のフィールドをGoの対応する型にマッピングしたものです。
Iflag
,Oflag
,Cflag
,Lflag
: これらはそれぞれ入力、出力、制御、ローカルモードのフラグを表し、通常はビットマスクとして使用されるためuint32
型で定義されています。Cc
: 制御文字の配列です。NetBSDでは20個の制御文字が定義されており、それぞれが1バイトのuint8
で表現されるため、[20]uint8
という固定サイズの配列として定義されています。Ispeed
,Ospeed
: 入力および出力のボーレートを表し、int32
型で定義されています。
これらのアーキテクチャ固有の定義により、Goのコンパイラは各ターゲットプラットフォームでsyscall.Termios
型がC言語のstruct termios
と正しくメモリ上で対応するように、適切なサイズとアライメントで構造体を扱えるようになります。これにより、Goプログラムがtcgetattr
やtcsetattr
のようなシステムコールを呼び出す際に、Termios
構造体のポインタを渡すことで、OSカーネルと正しくデータをやり取りできるようになります。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - NetBSDの
termios(4)
マニュアルページ (オンライン): https://man.netbsd.org/termios.4 - POSIX
termios.h
の定義 (The Open Group Base Specifications Issue 7): https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html
参考にした情報源リンク
- Go言語のソースコード (特に
src/pkg/syscall
ディレクトリ) - NetBSDのシステムプログラミングに関するドキュメント
- POSIX標準の
termios
に関する仕様 - Go言語の
cgo
に関するドキュメント