2018-12-15 02:49:18 +00:00
package util
2017-12-29 04:16:20 +00:00
// These are misc. utility functions that didn't really fit anywhere else
import "runtime"
2019-02-03 04:18:55 +00:00
import "time"
2018-01-04 22:37:51 +00:00
2018-06-10 23:03:28 +00:00
// A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere.
2018-12-15 02:49:18 +00:00
func Yield ( ) {
2018-01-04 22:37:51 +00:00
runtime . Gosched ( )
2017-12-29 04:16:20 +00:00
}
2018-06-10 23:03:28 +00:00
// A wrapper around runtime.LockOSThread() so it doesn't need to be imported elsewhere.
2018-12-15 02:49:18 +00:00
func LockThread ( ) {
2018-01-04 22:37:51 +00:00
runtime . LockOSThread ( )
2017-12-29 04:16:20 +00:00
}
2018-06-10 23:03:28 +00:00
// A wrapper around runtime.UnlockOSThread() so it doesn't need to be imported elsewhere.
2018-12-15 02:49:18 +00:00
func UnlockThread ( ) {
2018-01-04 22:37:51 +00:00
runtime . UnlockOSThread ( )
2017-12-29 04:16:20 +00:00
}
2018-06-10 23:03:28 +00:00
// This is used to buffer recently used slices of bytes, to prevent allocations in the hot loops.
// It's used like a sync.Pool, but with a fixed size and typechecked without type casts to/from interface{} (which were making the profiles look ugly).
2017-12-29 04:16:20 +00:00
var byteStore chan [ ] byte
2018-12-15 02:49:18 +00:00
func init ( ) {
byteStore = make ( chan [ ] byte , 32 )
2017-12-29 04:16:20 +00:00
}
2018-06-10 23:03:28 +00:00
// Gets an empty slice from the byte store, if one is available, or else returns a new nil slice.
2018-12-15 02:49:18 +00:00
func GetBytes ( ) [ ] byte {
2018-01-04 22:37:51 +00:00
select {
case bs := <- byteStore :
return bs [ : 0 ]
default :
return nil
}
2017-12-29 04:16:20 +00:00
}
2018-06-10 23:03:28 +00:00
// Puts a slice in the store, if there's room, or else returns and lets the slice get collected.
2018-12-15 02:49:18 +00:00
func PutBytes ( bs [ ] byte ) {
2018-01-04 22:37:51 +00:00
select {
case byteStore <- bs :
default :
}
2017-12-29 04:16:20 +00:00
}
2019-02-03 04:18:55 +00:00
// This is a workaround to go's broken timer implementation
func TimerStop ( t * time . Timer ) bool {
if ! t . Stop ( ) {
select {
case <- t . C :
default :
}
}
return true
}
2019-02-27 03:07:56 +00:00
// Run a blocking function with a timeout.
// Returns true if the function returns.
// Returns false if the timer fires.
// The blocked function remains blocked--the caller is responsible for somehow killing it.
func FuncTimeout ( f func ( ) , timeout time . Duration ) bool {
success := make ( chan struct { } )
go func ( ) {
defer close ( success )
f ( )
} ( )
timer := time . NewTimer ( timeout )
defer TimerStop ( timer )
select {
case <- success :
return true
case <- timer . C :
return false
}
}
2019-03-04 18:41:32 +00:00
// This calculates the difference between two arrays and returns items
// that appear in A but not in B - useful somewhat when reconfiguring
// and working out what configuration items changed
func Difference ( a , b [ ] string ) [ ] string {
ab := [ ] string { }
mb := map [ string ] bool { }
for _ , x := range b {
mb [ x ] = true
}
for _ , x := range a {
if _ , ok := mb [ x ] ; ! ok {
ab = append ( ab , x )
}
}
return ab
}