mirror of
https://github.com/jech/galene.git
synced 2024-11-10 02:35:58 +01:00
Avoid overflow in FromDuration and ToDuration.
Thanks to lamhai1401.
This commit is contained in:
parent
7d01f0339b
commit
b4edb7c0c7
2 changed files with 34 additions and 10 deletions
|
@ -2,6 +2,7 @@
|
||||||
package rtptime
|
package rtptime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/bits"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,25 +10,29 @@ import (
|
||||||
var epoch = time.Now()
|
var epoch = time.Now()
|
||||||
|
|
||||||
// FromDuration converts a time.Duration into units of 1/hz.
|
// FromDuration converts a time.Duration into units of 1/hz.
|
||||||
|
// Negative values are clamped to zero.
|
||||||
func FromDuration(d time.Duration, hz uint32) int64 {
|
func FromDuration(d time.Duration, hz uint32) int64 {
|
||||||
return int64(d) * int64(hz) / int64(time.Second)
|
if d < 0 {
|
||||||
|
return -FromDuration(-d, hz)
|
||||||
|
}
|
||||||
|
hi, lo := bits.Mul64(uint64(d), uint64(hz))
|
||||||
|
q, _ := bits.Div64(hi, lo, uint64(time.Second))
|
||||||
|
return int64(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDuration converts units of 1/hz into a time.Duration.
|
// ToDuration converts units of 1/hz into a time.Duration.
|
||||||
func ToDuration(tm int64, hz uint32) time.Duration {
|
func ToDuration(tm int64, hz uint32) time.Duration {
|
||||||
return time.Duration(tm * int64(time.Second) / int64(hz))
|
if tm < 0 {
|
||||||
|
return -ToDuration(-tm, hz)
|
||||||
}
|
}
|
||||||
|
hi, lo := bits.Mul64(uint64(tm), uint64(time.Second))
|
||||||
func sat(a int64) uint64 {
|
q, _ := bits.Div64(hi, lo, uint64(hz))
|
||||||
if a < 0 {
|
return time.Duration(q)
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return uint64(a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now returns the current time in units of 1/hz from an arbitrary origin.
|
// Now returns the current time in units of 1/hz from an arbitrary origin.
|
||||||
func Now(hz uint32) uint64 {
|
func Now(hz uint32) uint64 {
|
||||||
return sat(FromDuration(time.Since(epoch), hz))
|
return uint64(FromDuration(time.Since(epoch), hz))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Microseconds is like Now, but uses microseconds.
|
// Microseconds is like Now, but uses microseconds.
|
||||||
|
@ -46,7 +51,7 @@ func Jiffies() uint64 {
|
||||||
|
|
||||||
// TimeToJiffies converts a time.Time into jiffies.
|
// TimeToJiffies converts a time.Time into jiffies.
|
||||||
func TimeToJiffies(tm time.Time) uint64 {
|
func TimeToJiffies(tm time.Time) uint64 {
|
||||||
return sat(FromDuration(tm.Sub(epoch), JiffiesPerSec))
|
return uint64(FromDuration(tm.Sub(epoch), JiffiesPerSec))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The origin of NTP time.
|
// The origin of NTP time.
|
||||||
|
|
|
@ -27,6 +27,25 @@ func TestDuration(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDurationOverflow(t *testing.T) {
|
||||||
|
delta := 10 * time.Minute
|
||||||
|
dj := FromDuration(delta, JiffiesPerSec)
|
||||||
|
var prev int64
|
||||||
|
for d := time.Duration(0); d < time.Duration(1000*time.Hour); d += delta {
|
||||||
|
jiffies := FromDuration(d, JiffiesPerSec)
|
||||||
|
if d != 0 {
|
||||||
|
if jiffies != prev+dj {
|
||||||
|
t.Errorf("%v: %v, %v", d, jiffies, prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d2 := ToDuration(jiffies, JiffiesPerSec)
|
||||||
|
if d2 != d {
|
||||||
|
t.Errorf("%v != %v (%v)", d2, d, jiffies)
|
||||||
|
}
|
||||||
|
prev = jiffies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func differs(a, b, delta uint64) bool {
|
func differs(a, b, delta uint64) bool {
|
||||||
if a < b {
|
if a < b {
|
||||||
a, b = b, a
|
a, b = b, a
|
||||||
|
|
Loading…
Reference in a new issue