From 28890b0482feb66e057d2e2763d851f020f8dd65 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 23 Jul 2020 13:12:59 +0200 Subject: [PATCH] Use common implementation for BootTime/Uptime on all BSDs All BSDs use the same implementation to get BootTime{,WithContext} and Uptime{,WithContext} based on the kern.boottime sysctl. Move this implementation to a separate host/host_bsd.go file shared by darwin, freebsd and openbsd. Also use SysctlTimeval to get the boot time directly as a type Timeval instead of manually extracting it using package unsafe. It will also allow for easier reuse to support package host on e.g. Dragonfly BSD or NetBSD. This requires updating the golang.org/x/sys/unix dependency to the latest revision. Signed-off-by: Tobias Klauser --- Gopkg.lock | 4 ++-- host/host_bsd.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ host/host_darwin.go | 44 -------------------------------------------- host/host_freebsd.go | 42 ------------------------------------------ host/host_openbsd.go | 44 -------------------------------------------- 5 files changed, 51 insertions(+), 132 deletions(-) create mode 100644 host/host_bsd.go diff --git a/Gopkg.lock b/Gopkg.lock index 2f91cba..04ca6c2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -49,7 +49,7 @@ [[projects]] branch = "master" - digest = "1:c33af8636b2c5128b62b5bacd6fbdf6bf65a76e95b5b0111bfa134cb8ad5676d" + digest = "1:e7b553682850788c6b266faaf25218ce901558e541102d12b2998cad99f6b4fb" name = "golang.org/x/sys" packages = [ "internal/unsafeheader", @@ -59,7 +59,7 @@ "windows/svc/mgr", ] pruneopts = "UT" - revision = "ed371f2e16b4b305ee99df548828de367527b76b" + revision = "76b94024e4b621e672466e8db3d7f084e7ddcad2" [[projects]] branch = "v3" diff --git a/host/host_bsd.go b/host/host_bsd.go new file mode 100644 index 0000000..7c49e6a --- /dev/null +++ b/host/host_bsd.go @@ -0,0 +1,49 @@ +// +build darwin freebsd openbsd + +package host + +import ( + "context" + "sync/atomic" + "time" + + "golang.org/x/sys/unix" +) + +// cachedBootTime must be accessed via atomic.Load/StoreUint64 +var cachedBootTime uint64 + +func BootTime() (uint64, error) { + return BootTimeWithContext(context.Background()) +} + +func BootTimeWithContext(ctx context.Context) (uint64, error) { + t := atomic.LoadUint64(&cachedBootTime) + if t != 0 { + return t, nil + } + tv, err := unix.SysctlTimeval("kern.boottime") + if err != nil { + return 0, err + } + + atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec)) + + return uint64(tv.Sec), nil +} + +func uptime(boot uint64) uint64 { + return uint64(time.Now().Unix()) - boot +} + +func Uptime() (uint64, error) { + return UptimeWithContext(context.Background()) +} + +func UptimeWithContext(ctx context.Context) (uint64, error) { + boot, err := BootTimeWithContext(ctx) + if err != nil { + return 0, err + } + return uptime(boot), nil +} diff --git a/host/host_darwin.go b/host/host_darwin.go index f019e3e..e2d576e 100644 --- a/host/host_darwin.go +++ b/host/host_darwin.go @@ -11,8 +11,6 @@ import ( "os/exec" "runtime" "strings" - "sync/atomic" - "time" "unsafe" "github.com/shirou/gopsutil/internal/common" @@ -80,48 +78,6 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { return ret, nil } -// cachedBootTime must be accessed via atomic.Load/StoreUint64 -var cachedBootTime uint64 - -func BootTime() (uint64, error) { - return BootTimeWithContext(context.Background()) -} - -func BootTimeWithContext(ctx context.Context) (uint64, error) { - // https://github.com/AaronO/dashd/blob/222e32ef9f7a1f9bea4a8da2c3627c4cb992f860/probe/probe_darwin.go - t := atomic.LoadUint64(&cachedBootTime) - if t != 0 { - return t, nil - } - value, err := unix.Sysctl("kern.boottime") - if err != nil { - return 0, err - } - bytes := []byte(value[:]) - var boottime uint64 - boottime = uint64(bytes[0]) + uint64(bytes[1])*256 + uint64(bytes[2])*256*256 + uint64(bytes[3])*256*256*256 - - atomic.StoreUint64(&cachedBootTime, boottime) - - return boottime, nil -} - -func uptime(boot uint64) uint64 { - return uint64(time.Now().Unix()) - boot -} - -func Uptime() (uint64, error) { - return UptimeWithContext(context.Background()) -} - -func UptimeWithContext(ctx context.Context) (uint64, error) { - boot, err := BootTimeWithContext(ctx) - if err != nil { - return 0, err - } - return uptime(boot), nil -} - func Users() ([]UserStat, error) { return UsersWithContext(context.Background()) } diff --git a/host/host_freebsd.go b/host/host_freebsd.go index 6dc4bc1..c5457c5 100644 --- a/host/host_freebsd.go +++ b/host/host_freebsd.go @@ -11,9 +11,6 @@ import ( "os" "runtime" "strings" - "sync/atomic" - "syscall" - "time" "unsafe" "github.com/shirou/gopsutil/internal/common" @@ -80,45 +77,6 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { return ret, nil } -// cachedBootTime must be accessed via atomic.Load/StoreUint64 -var cachedBootTime uint64 - -func BootTime() (uint64, error) { - return BootTimeWithContext(context.Background()) -} - -func BootTimeWithContext(ctx context.Context) (uint64, error) { - t := atomic.LoadUint64(&cachedBootTime) - if t != 0 { - return t, nil - } - buf, err := unix.SysctlRaw("kern.boottime") - if err != nil { - return 0, err - } - - tv := *(*syscall.Timeval)(unsafe.Pointer((&buf[0]))) - atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec)) - - return t, nil -} - -func uptime(boot uint64) uint64 { - return uint64(time.Now().Unix()) - boot -} - -func Uptime() (uint64, error) { - return UptimeWithContext(context.Background()) -} - -func UptimeWithContext(ctx context.Context) (uint64, error) { - boot, err := BootTime() - if err != nil { - return 0, err - } - return uptime(boot), nil -} - func Users() ([]UserStat, error) { return UsersWithContext(context.Background()) } diff --git a/host/host_openbsd.go b/host/host_openbsd.go index d1501e9..03e00cf 100644 --- a/host/host_openbsd.go +++ b/host/host_openbsd.go @@ -10,8 +10,6 @@ import ( "os" "runtime" "strings" - "sync/atomic" - "time" "unsafe" "github.com/shirou/gopsutil/internal/common" @@ -71,48 +69,6 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) { return ret, nil } -// cachedBootTime must be accessed via atomic.Load/StoreUint64 -var cachedBootTime uint64 - -func BootTime() (uint64, error) { - return BootTimeWithContext(context.Background()) -} - -func BootTimeWithContext(ctx context.Context) (uint64, error) { - // https://github.com/AaronO/dashd/blob/222e32ef9f7a1f9bea4a8da2c3627c4cb992f860/probe/probe_darwin.go - t := atomic.LoadUint64(&cachedBootTime) - if t != 0 { - return t, nil - } - value, err := unix.Sysctl("kern.boottime") - if err != nil { - return 0, err - } - bytes := []byte(value[:]) - var boottime uint64 - boottime = uint64(bytes[0]) + uint64(bytes[1])*256 + uint64(bytes[2])*256*256 + uint64(bytes[3])*256*256*256 - - atomic.StoreUint64(&cachedBootTime, boottime) - - return boottime, nil -} - -func uptime(boot uint64) uint64 { - return uint64(time.Now().Unix()) - boot -} - -func Uptime() (uint64, error) { - return UptimeWithContext(context.Background()) -} - -func UptimeWithContext(ctx context.Context) (uint64, error) { - boot, err := BootTime() - if err != nil { - return 0, err - } - return uptime(boot), nil -} - func PlatformInformation() (string, string, string, error) { return PlatformInformationWithContext(context.Background()) }