diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-12-12 23:40:51 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-12-12 23:40:51 +0000 |
commit | ab61e9c4da707f3bc7b177c0c8f92daccdb142dc (patch) | |
tree | 0c68629fac9d7c6f103b401c9063ef00ed259f06 /libgo/go/time | |
parent | 6e456f4cf4deee3e2ccd9849286f59b90644c48b (diff) | |
download | gcc-ab61e9c4da707f3bc7b177c0c8f92daccdb142dc.tar.gz |
libgo: Update to weekly.2011-11-18.
From-SVN: r182266
Diffstat (limited to 'libgo/go/time')
-rw-r--r-- | libgo/go/time/sleep.go | 194 | ||||
-rw-r--r-- | libgo/go/time/sleep_test.go | 19 | ||||
-rw-r--r-- | libgo/go/time/sys.go | 23 | ||||
-rw-r--r-- | libgo/go/time/sys_plan9.go | 13 | ||||
-rw-r--r-- | libgo/go/time/sys_unix.go | 8 | ||||
-rw-r--r-- | libgo/go/time/sys_windows.go | 13 | ||||
-rw-r--r-- | libgo/go/time/tick.go | 182 | ||||
-rw-r--r-- | libgo/go/time/time.go | 60 | ||||
-rw-r--r-- | libgo/go/time/time_test.go | 62 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_unix.go | 12 | ||||
-rw-r--r-- | libgo/go/time/zoneinfo_windows.go | 2 |
11 files changed, 233 insertions, 355 deletions
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go index 314622d0dc9..967fca09b99 100644 --- a/libgo/go/time/sleep.go +++ b/libgo/go/time/sleep.go @@ -4,54 +4,60 @@ package time -import ( - "container/heap" - "sync" -) +// Interface to timers implemented in package runtime. +// Must be in sync with ../runtime/runtime.h:/^struct.Timer$ +type runtimeTimer struct { + i int32 + when int64 + period int64 + f func(int64, interface{}) + arg interface{} +} + +func startTimer(*runtimeTimer) +func stopTimer(*runtimeTimer) bool // The Timer type represents a single event. -// When the Timer expires, the current time will be sent on C -// unless the Timer represents an AfterFunc event. +// When the Timer expires, the current time will be sent on C, +// unless the Timer was created by AfterFunc. type Timer struct { C <-chan int64 - t int64 // The absolute time that the event should fire. - f func(int64) // The function to call when the event fires. - i int // The event's index inside eventHeap. + r runtimeTimer } -type timerHeap []*Timer - -// forever is the absolute time (in ns) of an event that is forever away. -const forever = 1 << 62 - -// maxSleepTime is the maximum length of time that a sleeper -// sleeps for before checking if it is defunct. -const maxSleepTime = 1e9 - -var ( - // timerMutex guards the variables inside this var group. - timerMutex sync.Mutex - - // timers holds a binary heap of pending events, terminated with a sentinel. - timers timerHeap - - // currentSleeper is an ever-incrementing counter which represents - // the current sleeper. It allows older sleepers to detect that they are - // defunct and exit. - currentSleeper int64 -) - -func init() { - timers.Push(&Timer{t: forever}) // sentinel +// Stop prevents the Timer from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or stopped. +func (t *Timer) Stop() (ok bool) { + return stopTimer(&t.r) } // NewTimer creates a new Timer that will send // the current time on its channel after at least ns nanoseconds. func NewTimer(ns int64) *Timer { c := make(chan int64, 1) - e := after(ns, func(t int64) { c <- t }) - e.C = c - return e + t := &Timer{ + C: c, + r: runtimeTimer{ + when: Nanoseconds() + ns, + f: sendTime, + arg: c, + }, + } + startTimer(&t.r) + return t +} + +func sendTime(now int64, c interface{}) { + // Non-blocking send of time on c. + // Used in NewTimer, it cannot block anyway (buffer). + // Used in NewTicker, dropping sends on the floor is + // the desired behavior when the reader gets behind, + // because the sends are periodic. + select { + case c.(chan int64) <- now: + default: + } } // After waits at least ns nanoseconds before sending the current time @@ -65,113 +71,17 @@ func After(ns int64) <-chan int64 { // in its own goroutine. It returns a Timer that can // be used to cancel the call using its Stop method. func AfterFunc(ns int64, f func()) *Timer { - return after(ns, func(_ int64) { - go f() - }) -} - -// Stop prevents the Timer from firing. -// It returns true if the call stops the timer, false if the timer has already -// expired or stopped. -func (e *Timer) Stop() (ok bool) { - timerMutex.Lock() - // Avoid removing the first event in the queue so that - // we don't start a new sleeper unnecessarily. - if e.i > 0 { - heap.Remove(timers, e.i) - } - ok = e.f != nil - e.f = nil - timerMutex.Unlock() - return -} - -// after is the implementation of After and AfterFunc. -// When the current time is after ns, it calls f with the current time. -// It assumes that f will not block. -func after(ns int64, f func(int64)) (e *Timer) { - now := Nanoseconds() - t := now + ns - if ns > 0 && t < now { - panic("time: time overflow") - } - timerMutex.Lock() - t0 := timers[0].t - e = &Timer{nil, t, f, -1} - heap.Push(timers, e) - // Start a new sleeper if the new event is before - // the first event in the queue. If the length of time - // until the new event is at least maxSleepTime, - // then we're guaranteed that the sleeper will wake up - // in time to service it, so no new sleeper is needed. - if t0 > t && (t0 == forever || ns < maxSleepTime) { - currentSleeper++ - go sleeper(currentSleeper) - } - timerMutex.Unlock() - return -} - -// sleeper continually looks at the earliest event in the queue, waits until it happens, -// then removes any events in the queue that are due. It stops when the queue -// is empty or when another sleeper has been started. -func sleeper(sleeperId int64) { - timerMutex.Lock() - e := timers[0] - t := Nanoseconds() - for e.t != forever { - if dt := e.t - t; dt > 0 { - if dt > maxSleepTime { - dt = maxSleepTime - } - timerMutex.Unlock() - sysSleep(dt) - timerMutex.Lock() - if currentSleeper != sleeperId { - // Another sleeper has been started, making this one redundant. - break - } - } - e = timers[0] - t = Nanoseconds() - for t >= e.t { - if e.f != nil { - e.f(t) - e.f = nil - } - heap.Pop(timers) - e = timers[0] - } + t := &Timer{ + r: runtimeTimer{ + when: Nanoseconds() + ns, + f: goFunc, + arg: f, + }, } - timerMutex.Unlock() -} - -func (timerHeap) Len() int { - return len(timers) -} - -func (timerHeap) Less(i, j int) bool { - return timers[i].t < timers[j].t -} - -func (timerHeap) Swap(i, j int) { - timers[i], timers[j] = timers[j], timers[i] - timers[i].i = i - timers[j].i = j -} - -func (timerHeap) Push(x interface{}) { - e := x.(*Timer) - e.i = len(timers) - timers = append(timers, e) + startTimer(&t.r) + return t } -func (timerHeap) Pop() interface{} { - // TODO: possibly shrink array. - n := len(timers) - 1 - e := timers[n] - timers[n] = nil - timers = timers[0:n] - e.i = -1 - return e +func goFunc(now int64, arg interface{}) { + go arg.(func())() } diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go index 0662e3359cf..9171da3af1c 100644 --- a/libgo/go/time/sleep_test.go +++ b/libgo/go/time/sleep_test.go @@ -7,7 +7,9 @@ package time_test import ( "errors" "fmt" + "runtime" "sort" + "sync/atomic" "testing" . "time" ) @@ -47,6 +49,23 @@ func TestAfterFunc(t *testing.T) { <-c } +func TestAfterStress(t *testing.T) { + stop := uint32(0) + go func() { + for atomic.LoadUint32(&stop) == 0 { + runtime.GC() + // Need to yield, because otherwise + // the main goroutine will never set the stop flag. + runtime.Gosched() + } + }() + c := Tick(1) + for i := 0; i < 100; i++ { + <-c + } + atomic.StoreUint32(&stop, 1) +} + func BenchmarkAfterFunc(b *testing.B) { i := b.N c := make(chan bool) diff --git a/libgo/go/time/sys.go b/libgo/go/time/sys.go index ca1d334a5b7..a5e529b814a 100644 --- a/libgo/go/time/sys.go +++ b/libgo/go/time/sys.go @@ -17,25 +17,4 @@ func Seconds() int64 { func Nanoseconds() int64 // Sleep pauses the current goroutine for at least ns nanoseconds. -// Higher resolution sleeping may be provided by syscall.Nanosleep -// on some operating systems. -func Sleep(ns int64) error { - _, err := sleep(Nanoseconds(), ns) - return err -} - -// sleep takes the current time and a duration, -// pauses for at least ns nanoseconds, and -// returns the current time and an error. -func sleep(t, ns int64) (int64, error) { - // TODO(cw): use monotonic-time once it's available - end := t + ns - for t < end { - err := sysSleep(end - t) - if err != nil { - return 0, err - } - t = Nanoseconds() - } - return t, nil -} +func Sleep(ns int64) diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go index a630b3ee030..e58fb519ea3 100644 --- a/libgo/go/time/sys_plan9.go +++ b/libgo/go/time/sys_plan9.go @@ -4,19 +4,6 @@ package time -import ( - "os" - "syscall" -) - -func sysSleep(t int64) error { - err := syscall.Sleep(t) - if err != nil { - return os.NewSyscallError("sleep", err) - } - return nil -} - // for testing: whatever interrupts a sleep func interrupt() { // cannot predict pid, don't want to kill group diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go index 17a6a2d63e0..3d313228b01 100644 --- a/libgo/go/time/sys_unix.go +++ b/libgo/go/time/sys_unix.go @@ -11,14 +11,6 @@ import ( "syscall" ) -func sysSleep(t int64) error { - errno := syscall.Sleep(t) - if errno != 0 && errno != syscall.EINTR { - return os.NewSyscallError("sleep", errno) - } - return nil -} - // for testing: whatever interrupts a sleep func interrupt() { syscall.Kill(os.Getpid(), syscall.SIGCHLD) diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go index f9d6e89281c..8c7242f4275 100644 --- a/libgo/go/time/sys_windows.go +++ b/libgo/go/time/sys_windows.go @@ -4,19 +4,6 @@ package time -import ( - "os" - "syscall" -) - -func sysSleep(t int64) error { - errno := syscall.Sleep(t) - if errno != 0 && errno != syscall.EINTR { - return os.NewSyscallError("sleep", errno) - } - return nil -} - // for testing: whatever interrupts a sleep func interrupt() { } diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go index 92f9eb893e4..95941a1e819 100644 --- a/libgo/go/time/tick.go +++ b/libgo/go/time/tick.go @@ -4,156 +4,15 @@ package time -import ( - "errors" - "sync" -) +import "errors" // A Ticker holds a synchronous channel that delivers `ticks' of a clock // at intervals. type Ticker struct { - C <-chan int64 // The channel on which the ticks are delivered. - c chan<- int64 // The same channel, but the end we use. - ns int64 - shutdown chan bool // Buffered channel used to signal shutdown. - nextTick int64 - next *Ticker + C <-chan int64 // The channel on which the ticks are delivered. + r runtimeTimer } -// Stop turns off a ticker. After Stop, no more ticks will be sent. -func (t *Ticker) Stop() { - select { - case t.shutdown <- true: - // ok - default: - // Stop in progress already - } -} - -// Tick is a convenience wrapper for NewTicker providing access to the ticking -// channel only. Useful for clients that have no need to shut down the ticker. -func Tick(ns int64) <-chan int64 { - if ns <= 0 { - return nil - } - return NewTicker(ns).C -} - -type alarmer struct { - wakeUp chan bool // wakeup signals sent/received here - wakeMeAt chan int64 - wakeTime int64 -} - -// Set alarm to go off at time ns, if not already set earlier. -func (a *alarmer) set(ns int64) { - switch { - case a.wakeTime > ns: - // Next tick we expect is too late; shut down the late runner - // and (after fallthrough) start a new wakeLoop. - close(a.wakeMeAt) - fallthrough - case a.wakeMeAt == nil: - // There's no wakeLoop, start one. - a.wakeMeAt = make(chan int64) - a.wakeUp = make(chan bool, 1) - go wakeLoop(a.wakeMeAt, a.wakeUp) - fallthrough - case a.wakeTime == 0: - // Nobody else is waiting; it's just us. - a.wakeTime = ns - a.wakeMeAt <- ns - default: - // There's already someone scheduled. - } -} - -// Channel to notify tickerLoop of new Tickers being created. -var newTicker chan *Ticker - -func startTickerLoop() { - newTicker = make(chan *Ticker) - go tickerLoop() -} - -// wakeLoop delivers ticks at scheduled times, sleeping until the right moment. -// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new -// wakeLoop and signal that this one is done by closing the wakeMeAt channel. -func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) { - for wakeAt := range wakeMeAt { - Sleep(wakeAt - Nanoseconds()) - wakeUp <- true - } -} - -// A single tickerLoop serves all ticks to Tickers. It waits for two events: -// either the creation of a new Ticker or a tick from the alarm, -// signaling a time to wake up one or more Tickers. -func tickerLoop() { - // Represents the next alarm to be delivered. - var alarm alarmer - var now, wakeTime int64 - var tickers *Ticker - for { - select { - case t := <-newTicker: - // Add Ticker to list - t.next = tickers - tickers = t - // Arrange for a new alarm if this one precedes the existing one. - alarm.set(t.nextTick) - case <-alarm.wakeUp: - now = Nanoseconds() - wakeTime = now + 1e15 // very long in the future - var prev *Ticker = nil - // Scan list of tickers, delivering updates to those - // that need it and determining the next wake time. - // TODO(r): list should be sorted in time order. - for t := tickers; t != nil; t = t.next { - select { - case <-t.shutdown: - // Ticker is done; remove it from list. - if prev == nil { - tickers = t.next - } else { - prev.next = t.next - } - continue - default: - } - if t.nextTick <= now { - if len(t.c) == 0 { - // Only send if there's room. We must not block. - // The channel is allocated with a one-element - // buffer, which is sufficient: if he hasn't picked - // up the last tick, no point in sending more. - t.c <- now - } - t.nextTick += t.ns - if t.nextTick <= now { - // Still behind; advance in one big step. - t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns - } - } - if t.nextTick < wakeTime { - wakeTime = t.nextTick - } - prev = t - } - if tickers != nil { - // Please send wakeup at earliest required time. - // If there are no tickers, don't bother. - alarm.wakeTime = wakeTime - alarm.wakeMeAt <- wakeTime - } else { - alarm.wakeTime = 0 - } - } - } -} - -var onceStartTickerLoop sync.Once - // NewTicker returns a new Ticker containing a channel that will // send the time, in nanoseconds, every ns nanoseconds. It adjusts the // intervals to make up for pauses in delivery of the ticks. The value of @@ -162,16 +21,33 @@ func NewTicker(ns int64) *Ticker { if ns <= 0 { panic(errors.New("non-positive interval for NewTicker")) } - c := make(chan int64, 1) // See comment on send in tickerLoop + // Give the channel a 1-element time buffer. + // If the client falls behind while reading, we drop ticks + // on the floor until the client catches up. + c := make(chan int64, 1) t := &Ticker{ - C: c, - c: c, - ns: ns, - shutdown: make(chan bool, 1), - nextTick: Nanoseconds() + ns, + C: c, + r: runtimeTimer{ + when: Nanoseconds() + ns, + period: ns, + f: sendTime, + arg: c, + }, } - onceStartTickerLoop.Do(startTickerLoop) - // must be run in background so global Tickers can be created - go func() { newTicker <- t }() + startTimer(&t.r) return t } + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +func (t *Ticker) Stop() { + stopTimer(&t.r) +} + +// Tick is a convenience wrapper for NewTicker providing access to the ticking +// channel only. Useful for clients that have no need to shut down the ticker. +func Tick(ns int64) <-chan int64 { + if ns <= 0 { + return nil + } + return NewTicker(ns).C +} diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index 859b3167278..e11d17731b4 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -237,3 +237,63 @@ func (t *Time) Weekday() int { } return weekday } + +// julianDayNumber returns the time's Julian Day Number +// relative to the epoch 12:00 January 1, 4713 BC, Monday. +func julianDayNumber(year int64, month, day int) int64 { + a := int64(14-month) / 12 + y := year + 4800 - a + m := int64(month) + 12*a - 3 + return int64(day) + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045 +} + +// startOfFirstWeek returns the julian day number of the first day +// of the first week of the given year. +func startOfFirstWeek(year int64) (d int64) { + jan01 := julianDayNumber(year, 1, 1) + weekday := (jan01 % 7) + 1 + if weekday <= 4 { + d = jan01 - weekday + 1 + } else { + d = jan01 + 8 - weekday + } + return +} + +// dayOfWeek returns the weekday of the given date. +func dayOfWeek(year int64, month, day int) int { + t := Time{Year: year, Month: month, Day: day} + return t.Weekday() +} + +// ISOWeek returns the time's year and week number according to ISO 8601. +// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to +// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 +// of year n+1. +func (t *Time) ISOWeek() (year int64, week int) { + d := julianDayNumber(t.Year, t.Month, t.Day) + week1Start := startOfFirstWeek(t.Year) + + if d < week1Start { + // Previous year, week 52 or 53 + year = t.Year - 1 + if dayOfWeek(t.Year-1, 1, 1) == 4 || dayOfWeek(t.Year-1, 12, 31) == 4 { + week = 53 + } else { + week = 52 + } + return + } + + if d < startOfFirstWeek(t.Year+1) { + // Current year, week 01..52(,53) + year = t.Year + week = int((d-week1Start)/7 + 1) + return + } + + // Next year, week 1 + year = t.Year + 1 + week = 1 + return +} diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go index 8b373a13bc2..01b8bea4aad 100644 --- a/libgo/go/time/time_test.go +++ b/libgo/go/time/time_test.go @@ -478,6 +478,68 @@ func TestMinutesInTimeZone(t *testing.T) { } } +type ISOWeekTest struct { + year int64 // year + month, day int // month and day + yex int64 // expected year + wex int // expected week +} + +var isoWeekTests = []ISOWeekTest{ + {1981, 1, 1, 1981, 1}, {1982, 1, 1, 1981, 53}, {1983, 1, 1, 1982, 52}, + {1984, 1, 1, 1983, 52}, {1985, 1, 1, 1985, 1}, {1986, 1, 1, 1986, 1}, + {1987, 1, 1, 1987, 1}, {1988, 1, 1, 1987, 53}, {1989, 1, 1, 1988, 52}, + {1990, 1, 1, 1990, 1}, {1991, 1, 1, 1991, 1}, {1992, 1, 1, 1992, 1}, + {1993, 1, 1, 1992, 53}, {1994, 1, 1, 1993, 52}, {1995, 1, 2, 1995, 1}, + {1996, 1, 1, 1996, 1}, {1996, 1, 7, 1996, 1}, {1996, 1, 8, 1996, 2}, + {1997, 1, 1, 1997, 1}, {1998, 1, 1, 1998, 1}, {1999, 1, 1, 1998, 53}, + {2000, 1, 1, 1999, 52}, {2001, 1, 1, 2001, 1}, {2002, 1, 1, 2002, 1}, + {2003, 1, 1, 2003, 1}, {2004, 1, 1, 2004, 1}, {2005, 1, 1, 2004, 53}, + {2006, 1, 1, 2005, 52}, {2007, 1, 1, 2007, 1}, {2008, 1, 1, 2008, 1}, + {2009, 1, 1, 2009, 1}, {2010, 1, 1, 2009, 53}, {2010, 1, 1, 2009, 53}, + {2011, 1, 1, 2010, 52}, {2011, 1, 2, 2010, 52}, {2011, 1, 3, 2011, 1}, + {2011, 1, 4, 2011, 1}, {2011, 1, 5, 2011, 1}, {2011, 1, 6, 2011, 1}, + {2011, 1, 7, 2011, 1}, {2011, 1, 8, 2011, 1}, {2011, 1, 9, 2011, 1}, + {2011, 1, 10, 2011, 2}, {2011, 1, 11, 2011, 2}, {2011, 6, 12, 2011, 23}, + {2011, 6, 13, 2011, 24}, {2011, 12, 25, 2011, 51}, {2011, 12, 26, 2011, 52}, + {2011, 12, 27, 2011, 52}, {2011, 12, 28, 2011, 52}, {2011, 12, 29, 2011, 52}, + {2011, 12, 30, 2011, 52}, {2011, 12, 31, 2011, 52}, {1995, 1, 1, 1994, 52}, + {2012, 1, 1, 2011, 52}, {2012, 1, 2, 2012, 1}, {2012, 1, 8, 2012, 1}, + {2012, 1, 9, 2012, 2}, {2012, 12, 23, 2012, 51}, {2012, 12, 24, 2012, 52}, + {2012, 12, 30, 2012, 52}, {2012, 12, 31, 2013, 1}, {2013, 1, 1, 2013, 1}, + {2013, 1, 6, 2013, 1}, {2013, 1, 7, 2013, 2}, {2013, 12, 22, 2013, 51}, + {2013, 12, 23, 2013, 52}, {2013, 12, 29, 2013, 52}, {2013, 12, 30, 2014, 1}, + {2014, 1, 1, 2014, 1}, {2014, 1, 5, 2014, 1}, {2014, 1, 6, 2014, 2}, + {2015, 1, 1, 2015, 1}, {2016, 1, 1, 2015, 53}, {2017, 1, 1, 2016, 52}, + {2018, 1, 1, 2018, 1}, {2019, 1, 1, 2019, 1}, {2020, 1, 1, 2020, 1}, + {2021, 1, 1, 2020, 53}, {2022, 1, 1, 2021, 52}, {2023, 1, 1, 2022, 52}, + {2024, 1, 1, 2024, 1}, {2025, 1, 1, 2025, 1}, {2026, 1, 1, 2026, 1}, + {2027, 1, 1, 2026, 53}, {2028, 1, 1, 2027, 52}, {2029, 1, 1, 2029, 1}, + {2030, 1, 1, 2030, 1}, {2031, 1, 1, 2031, 1}, {2032, 1, 1, 2032, 1}, + {2033, 1, 1, 2032, 53}, {2034, 1, 1, 2033, 52}, {2035, 1, 1, 2035, 1}, + {2036, 1, 1, 2036, 1}, {2037, 1, 1, 2037, 1}, {2038, 1, 1, 2037, 53}, + {2039, 1, 1, 2038, 52}, {2040, 1, 1, 2039, 52}, +} + +func TestISOWeek(t *testing.T) { + // Selected dates and corner cases + for _, wt := range isoWeekTests { + dt := &Time{Year: wt.year, Month: wt.month, Day: wt.day} + y, w := dt.ISOWeek() + if w != wt.wex || y != wt.yex { + t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d", + y, w, wt.yex, wt.wex, wt.year, wt.month, wt.day) + } + } + + // The only real invariant: Jan 04 is in week 1 + for year := int64(1950); year < 2100; year++ { + if y, w := (&Time{Year: year, Month: 1, Day: 4}).ISOWeek(); y != year || w != 1 { + t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year) + } + } +} + func BenchmarkSeconds(b *testing.B) { for i := 0; i < b.N; i++ { Seconds() diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go index 0dc42353136..b552e589aa9 100644 --- a/libgo/go/time/zoneinfo_unix.go +++ b/libgo/go/time/zoneinfo_unix.go @@ -12,7 +12,7 @@ package time import ( - "io/ioutil" + "bytes" "os" ) @@ -180,11 +180,17 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) { } func readinfofile(name string) ([]zonetime, bool) { - buf, err := ioutil.ReadFile(name) + var b bytes.Buffer + + f, err := os.Open(name) if err != nil { return nil, false } - return parseinfo(buf) + defer f.Close() + if _, err := b.ReadFrom(f); err != nil { + return nil, false + } + return parseinfo(b.Bytes()) } func setupTestingZone() { diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go index ba152e0882a..995fd44dc06 100644 --- a/libgo/go/time/zoneinfo_windows.go +++ b/libgo/go/time/zoneinfo_windows.go @@ -161,7 +161,7 @@ var onceSetupZone sync.Once func setupZone() { var i syscall.Timezoneinformation - if _, e := syscall.GetTimeZoneInformation(&i); e != 0 { + if _, e := syscall.GetTimeZoneInformation(&i); e != nil { initError = os.NewSyscallError("GetTimeZoneInformation", e) return } |