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

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

このコミットは、Go言語のsyscallパッケージにおいて、TimespecおよびTimeval構造体にUnix()メソッドを追加するものです。これにより、これらの時間表現構造体からUnixエポック秒とナノ秒(またはマイクロ秒)を直接取得できるようになります。

コミット

commit 7d418aeed2f93014d2717da36dd08376e3fe2bf9
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Wed Jan 18 19:05:44 2012 -0800

    syscall: add Unix method to TimeSpec, TimeVal
    
    Fixes #2534
    
    R=golang-dev, dave, alex.brainman
    CC=golang-dev
    https://golang.org/cl/5554057

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

https://github.com/golang/go/commit/7d418aeed2f93014d2717da36dd08376e3fe2bf9

元コミット内容

syscallパッケージのTimespecおよびTimeval構造体にUnix()メソッドを追加しました。これにより、これらの構造体からUnixエポック秒とナノ秒(またはマイクロ秒)を取得できるようになります。

変更の背景

この変更は、Go言語のIssue #2534を修正するために行われました。Issue #2534は、syscall.Timespecsyscall.Timevaltime.Time型に変換できないという問題提起でした。具体的には、time.Unix()関数がint64型の秒とナノ秒を引数として取るため、TimespecTimevalのフィールドを直接渡すことができませんでした。このコミットは、これらの構造体にUnix()メソッドを追加することで、time.Unix()関数への変換を容易にし、よりGoらしい(idiomaticな)方法で時間情報を扱うことを可能にしました。

前提知識の解説

Unix時間 (Unix Epoch Time)

Unix時間(またはPOSIX時間)は、協定世界時 (UTC) の1970年1月1日00時00分00秒(Unixエポック)からの経過秒数で時間を表現する方法です。うるう秒は考慮されません。多くのシステムで内部的に時間を扱う際の標準的な形式として利用されています。

syscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)の低レベルなシステムコールへのインターフェースを提供します。ファイル操作、プロセス管理、ネットワーク通信など、OSが提供する基本的な機能に直接アクセスするために使用されます。このパッケージはOSに依存する部分が多く、OSごとに異なる実装を持つことがあります。

Timespec構造体

Timespec構造体は、Unix系OSで高精度な時間情報を表現するために使用されます。通常、秒 (tv_sec) とナノ秒 (tv_nsec) の2つのフィールドを持ちます。

  • Sec: 秒を表すint64型。
  • Nsec: ナノ秒を表すint64型。

Timeval構造体

Timeval構造体もTimespecと同様に時間情報を表現しますが、こちらは秒 (tv_sec) とマイクロ秒 (tv_usec) の2つのフィールドを持ちます。

  • Sec: 秒を表すint64型。
  • Usec: マイクロ秒を表すint64型。

これらの構造体は、ファイルシステムのタイムスタンプ(作成時刻、最終アクセス時刻、最終更新時刻など)や、select()poll()などのシステムコールにおけるタイムアウト値の指定など、様々な場面で利用されます。

Go言語のメソッド

Go言語では、構造体に対してメソッドを定義することができます。これは、特定の構造体のデータに対して操作を行う関数を、その構造体に関連付けるための仕組みです。func (t Type) MethodName(...) の形式で定義され、tはレシーバと呼ばれます。

技術的詳細

このコミットの主要な目的は、syscallパッケージ内のTimespecTimeval構造体から、標準的なUnix時間形式(秒とナノ秒)を簡単に取得できるようにすることです。

Unix()メソッドの追加

TimespecTimevalUnix()メソッドが追加されました。このメソッドは、Go標準ライブラリのtime.Time型が持つUnix()およびUnixNano()メソッドと同様のセマンティクスを提供します。

  • TimespecUnix()メソッド: func (ts *Timespec) Unix() (sec int64, nsec int64) このメソッドは、Timespec構造体のSecフィールドをそのまま秒として、Nsecフィールドをそのままナノ秒として返します。これはTimespecが元々秒とナノ秒で構成されているため、単純なフィールドのキャストで済みます。

  • TimevalUnix()メソッド: func (tv *Timeval) Unix() (sec int64, nsec int64) このメソッドは、Timeval構造体のSecフィールドを秒として返します。ナノ秒については、Usecフィールド(マイクロ秒)を1000倍してナノ秒に変換します(1マイクロ秒 = 1000ナノ秒)。

WindowsにおけるTimespecの定義

興味深い点として、src/pkg/syscall/syscall_windows.goにおいて、Windows環境ではTimespec構造体が「発明された構造体」として定義されています。これは、Windows APIが直接Timespecのような構造体を提供しないため、GoのsyscallパッケージがUnix系OSとの一貫性を保つために内部的に定義していることを示しています。この定義は、SecNsecのフィールドを持つことで、Unix系OSのTimespecと互換性のあるインターフェースを提供します。

// Timespec is an invented structure on Windows, but here for
// consistency with the syscall package for other operating systems.
type Timespec struct {
	Sec  int64
	Nsec int64
}

この定義により、Windows上でもTimespec型を扱うことができ、今回追加されたUnix()メソッドも同様に利用可能になります。

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

src/pkg/syscall/syscall.go

--- a/src/pkg/syscall/syscall.go
+++ b/src/pkg/syscall/syscall.go
@@ -29,3 +29,11 @@ func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }\n // Single-word zero for use when we need a valid pointer to 0 bytes.\n // See mksyscall.pl.\n var _zero uintptr\n+\n+func (ts *Timespec) Unix() (sec int64, nsec int64) {\n+\treturn int64(ts.Sec), int64(ts.Nsec)\n+}\n+\n+func (tv *Timeval) Unix() (sec int64, nsec int64) {\n+\treturn int64(tv.Sec), int64(tv.Usec) * 1000\n+}\ndiff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go

src/pkg/syscall/syscall_windows.go

--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -624,6 +624,13 @@ func (w WaitStatus) Signaled() bool { return false }\n \n func (w WaitStatus) TrapCause() int { return -1 }\n \n+// Timespec is an invented structure on Windows, but here for\n+// consistency with the syscall package for other operating systems.\n+type Timespec struct {\n+\tSec  int64\n+\tNsec int64\n+}\n+\n // TODO(brainman): fix all needed for net\n \n func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, EWINDOWS }\n```

## コアとなるコードの解説

### `src/pkg/syscall/syscall.go` の変更

このファイルでは、`Timespec`と`Timeval`のポインタレシーバを持つ`Unix()`メソッドが追加されています。

```go
func (ts *Timespec) Unix() (sec int64, nsec int64) {
	return int64(ts.Sec), int64(ts.Nsec)
}
  • ts *Timespec: Timespec構造体へのポインタをレシーバとして受け取ります。これにより、メソッド内でTimespecのフィールドにアクセスできます。
  • return int64(ts.Sec), int64(ts.Nsec): TimespecSecNsecフィールドは既に適切な型(int64)であるため、そのまま返されます。
func (tv *Timeval) Unix() (sec int64, nsec int64) {
	return int64(tv.Sec), int64(tv.Usec) * 1000
}
  • tv *Timeval: Timeval構造体へのポインタをレシーバとして受け取ります。
  • return int64(tv.Sec), int64(tv.Usec) * 1000: TimevalSecフィールドはそのまま秒として返されます。Usecフィールドはマイクロ秒単位であるため、ナノ秒に変換するために1000を乗算しています。

これらのメソッドの追加により、例えばsyscall.Stat_t構造体に含まれるAtim(アクセス時刻)、Mtim(変更時刻)、Ctim(作成時刻)などのTimespec型のフィールドから、直接Unix時間形式の秒とナノ秒を取得できるようになります。

src/pkg/syscall/syscall_windows.go の変更

このファイルでは、Windows環境におけるTimespec構造体の定義が追加されています。

// Timespec is an invented structure on Windows, but here for
// consistency with the syscall package for other operating systems.
type Timespec struct {
	Sec  int64
	Nsec int64
}
  • コメントにあるように、WindowsにはネイティブなTimespec構造体は存在しません。しかし、Goのsyscallパッケージがクロスプラットフォームで一貫したインターフェースを提供するために、この構造体がWindows向けに「発明」されました。
  • SecNsecフィールドを持つことで、Unix系OSのTimespecと互換性のあるデータ構造を提供し、syscall.goで定義されたUnix()メソッドがWindows上でも機能するようにしています。

この変更は、Go言語が異なるOSのシステムコールを抽象化し、開発者に一貫したAPIを提供するという設計思想を反映しています。

関連リンク

参考にした情報源リンク