From 1cb254a085678170895634b33c486b3cef223286 Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Mon, 12 Dec 2011 16:12:22 -0500 Subject: [PATCH] time: fix Plan 9 build for new API I had to move readFile into sys_$GOOS.go since syscall.Open takes only two arguments on Plan 9. R=lucio.dere, rsc, alex.brainman CC=golang-dev https://golang.org/cl/5447061 --- src/pkg/runtime/plan9/thread.c | 12 +++ src/pkg/time/Makefile | 1 - src/pkg/time/sleep.go | 3 + src/pkg/time/sys.go | 36 ------- src/pkg/time/sys_plan9.go | 30 ++++++ src/pkg/time/sys_unix.go | 26 +++++ src/pkg/time/zoneinfo_plan9.go | 185 ++++++++++++++++++++++++--------- 7 files changed, 209 insertions(+), 84 deletions(-) delete mode 100644 src/pkg/time/sys.go diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c index 87ea8a2363..07edb717e4 100644 --- a/src/pkg/runtime/plan9/thread.c +++ b/src/pkg/runtime/plan9/thread.c @@ -97,6 +97,18 @@ runtime·nanotime(void) return (int64)hi<<32 | (int64)lo; } +void +time·now(int64 sec, int32 nsec) +{ + int64 ns; + + ns = runtime·nanotime(); + sec = ns / 1000000000LL; + nsec = ns - sec * 1000000000LL; + FLUSH(&sec); + FLUSH(&nsec); +} + extern Tos *_tos; void runtime·exit(int32) diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile index 28c6afc537..9f61329d38 100644 --- a/src/pkg/time/Makefile +++ b/src/pkg/time/Makefile @@ -8,7 +8,6 @@ TARG=time GOFILES=\ format.go\ sleep.go\ - sys.go\ tick.go\ time.go\ zoneinfo.go\ diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go index 844d964d5a..b4680db238 100644 --- a/src/pkg/time/sleep.go +++ b/src/pkg/time/sleep.go @@ -4,6 +4,9 @@ package time +// Sleep pauses the current goroutine for the duration d. +func Sleep(d Duration) + func nano() int64 { sec, nsec := now() return sec*1e9 + int64(nsec) diff --git a/src/pkg/time/sys.go b/src/pkg/time/sys.go deleted file mode 100644 index fe6bc27d30..0000000000 --- a/src/pkg/time/sys.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -import "syscall" - -// Sleep pauses the current goroutine for the duration d. -func Sleep(d Duration) - -// readFile reads and returns the content of the named file. -// It is a trivial implementation of ioutil.ReadFile, reimplemented -// here to avoid depending on io/ioutil or os. -func readFile(name string) ([]byte, error) { - f, err := syscall.Open(name, syscall.O_RDONLY, 0) - if err != nil { - return nil, err - } - defer syscall.Close(f) - var ( - buf [4096]byte - ret []byte - n int - ) - for { - n, err = syscall.Read(f, buf[:]) - if n > 0 { - ret = append(ret, buf[:n]...) - } - if n == 0 || err != nil { - break - } - } - return ret, err -} diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go index e58fb519ea..c7cfa792a2 100644 --- a/src/pkg/time/sys_plan9.go +++ b/src/pkg/time/sys_plan9.go @@ -2,9 +2,39 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build plan9 + package time +import "syscall" + // for testing: whatever interrupts a sleep func interrupt() { // cannot predict pid, don't want to kill group } + +// readFile reads and returns the content of the named file. +// It is a trivial implementation of ioutil.ReadFile, reimplemented +// here to avoid depending on io/ioutil or os. +func readFile(name string) ([]byte, error) { + f, err := syscall.Open(name, syscall.O_RDONLY) + if err != nil { + return nil, err + } + defer syscall.Close(f) + var ( + buf [4096]byte + ret []byte + n int + ) + for { + n, err = syscall.Read(f, buf[:]) + if n > 0 { + ret = append(ret, buf[:n]...) + } + if n == 0 || err != nil { + break + } + } + return ret, err +} diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go index 715d186be1..55ae5f7da2 100644 --- a/src/pkg/time/sys_unix.go +++ b/src/pkg/time/sys_unix.go @@ -12,3 +12,29 @@ import "syscall" func interrupt() { syscall.Kill(syscall.Getpid(), syscall.SIGCHLD) } + +// readFile reads and returns the content of the named file. +// It is a trivial implementation of ioutil.ReadFile, reimplemented +// here to avoid depending on io/ioutil or os. +func readFile(name string) ([]byte, error) { + f, err := syscall.Open(name, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + defer syscall.Close(f) + var ( + buf [4096]byte + ret []byte + n int + ) + for { + n, err = syscall.Read(f, buf[:]) + if n > 0 { + ret = append(ret, buf[:n]...) + } + if n == 0 || err != nil { + break + } + } + return ret, err +} diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go index 38aefc7a97..9c052d42cd 100644 --- a/src/pkg/time/zoneinfo_plan9.go +++ b/src/pkg/time/zoneinfo_plan9.go @@ -6,61 +6,152 @@ package time -//import ( -// "strconv" -// "strings" -//) +import ( + "errors" + "syscall" +) -func parseZones(s string) (zt []zonetime) { - f := strings.Fields(s) - if len(f) < 4 { - return - } +var badData = errors.New("malformed time zone information") - // standard timezone offset - o, err := strconv.Atoi(f[1]) - if err != nil { - return - } - std := &zone{name: f[0], utcoff: o, isdst: false} - - // alternate timezone offset - o, err = strconv.Atoi(f[3]) - if err != nil { - return - } - dst := &zone{name: f[2], utcoff: o, isdst: true} - - // transition time pairs - f = f[4:] - for i := 0; i < len(f); i++ { - z := std - if i%2 == 0 { - z = dst - } - t, err := strconv.Atoi(f[i]) - if err != nil { - return nil - } - t -= std.utcoff - zt = append(zt, zonetime{time: int32(t), zone: z}) - } - return +func isSpace(r rune) bool { + return r == ' ' || r == '\t' || r == '\n' } -func initLocal() { - t, err := os.Getenverror("timezone") - if err != nil { - // do nothing: use UTC - return +// Copied from strings to avoid a dependency. +func fields(s string) []string { + // First count the fields. + n := 0 + inField := false + for _, rune := range s { + wasInField := inField + inField = !isSpace(rune) + if inField && !wasInField { + n++ + } } - zones = parseZones(t) + + // Now create them. + a := make([]string, n) + na := 0 + fieldStart := -1 // Set to -1 when looking for start of field. + for i, rune := range s { + if isSpace(rune) { + if fieldStart >= 0 { + a[na] = s[fieldStart:i] + na++ + fieldStart = -1 + } + } else if fieldStart == -1 { + fieldStart = i + } + } + if fieldStart >= 0 { // Last field might end at EOF. + a[na] = s[fieldStart:] + } + return a +} + +func loadZoneData(s string) (l *Location, err error) { + f := fields(s) + if len(f) < 4 { + if len(f) == 2 && f[0] == "GMT" { + return UTC, nil + } + return nil, badData + } + + var zones [2]zone + + // standard timezone offset + o, err := atoi(f[1]) + if err != nil { + return nil, badData + } + zones[0] = zone{name: f[0], offset: o, isDST: false} + + // alternate timezone offset + o, err = atoi(f[3]) + if err != nil { + return nil, badData + } + zones[1] = zone{name: f[2], offset: o, isDST: true} + + // transition time pairs + var tx []zoneTrans + f = f[4:] + for i := 0; i < len(f); i++ { + zi := 0 + if i%2 == 0 { + zi = 1 + } + t, err := atoi(f[i]) + if err != nil { + return nil, badData + } + t -= zones[0].offset + tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)}) + } + + // Committed to succeed. + l = &Location{zone: zones[:], tx: tx} + + // Fill in the cache with information about right now, + // since that will be the most common lookup. + sec, _ := now() + for i := range tx { + if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { + l.cacheStart = tx[i].when + l.cacheEnd = 1<<63 - 1 + if i+1 < len(tx) { + l.cacheEnd = tx[i+1].when + } + l.cacheZone = &l.zone[tx[i].index] + } + } + + return l, nil +} + +func loadZoneFile(name string) (*Location, error) { + b, err := readFile(name) + if err != nil { + return nil, err + } + return loadZoneData(string(b)) } func initTestingZone() { - buf, err := readFile("/adm/timezone/US_Pacific") - if err != nil { + if z, err := loadZoneFile("/adm/timezone/US_Pacific"); err == nil { + localLoc = *z return } - zones = parseZones(string(buf)) + + // Fall back to UTC. + localLoc.name = "UTC" +} + +func initLocal() { + t, ok := syscall.Getenv("timezone") + if ok { + if z, err := loadZoneData(t); err == nil { + localLoc = *z + return + } + } else { + if z, err := loadZoneFile("/adm/timezone/local"); err == nil { + localLoc = *z + localLoc.name = "Local" + return + } + } + + // Fall back to UTC. + localLoc.name = "UTC" +} + +func loadLocation(name string) (*Location, error) { + if z, err := loadZoneFile("/adm/timezone/" + name); err == nil { + return z, nil + } + return nil, errors.New("unknown time zone " + name) }