Merge pull request #689 from ZymoticB/td-remove-cycle

Remove cycle between process and host packages
tags/v2.19.05
shirou 6 years ago committed by GitHub
commit b2cbc26504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,7 +15,6 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/internal/common"
@ -105,71 +104,13 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
return ret, nil return ret, nil
} }
// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64
// BootTime returns the system boot time expressed in seconds since the epoch. // BootTime returns the system boot time expressed in seconds since the epoch.
func BootTime() (uint64, error) { func BootTime() (uint64, error) {
return BootTimeWithContext(context.Background()) return BootTimeWithContext(context.Background())
} }
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
t := atomic.LoadUint64(&cachedBootTime) return common.BootTimeWithContext(ctx)
if t != 0 {
return t, nil
}
system, role, err := Virtualization()
if err != nil {
return 0, err
}
statFile := "stat"
if system == "lxc" && role == "guest" {
// if lxc, /proc/uptime is used.
statFile = "uptime"
} else if system == "docker" && role == "guest" {
// also docker, guest
statFile = "uptime"
}
filename := common.HostProc(statFile)
lines, err := common.ReadLines(filename)
if err != nil {
return 0, err
}
if statFile == "stat" {
for _, line := range lines {
if strings.HasPrefix(line, "btime") {
f := strings.Fields(line)
if len(f) != 2 {
return 0, fmt.Errorf("wrong btime format")
}
b, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
return 0, err
}
t = uint64(b)
atomic.StoreUint64(&cachedBootTime, t)
return t, nil
}
}
} else if statFile == "uptime" {
if len(lines) != 1 {
return 0, fmt.Errorf("wrong uptime format")
}
f := strings.Fields(lines[0])
b, err := strconv.ParseFloat(f[0], 64)
if err != nil {
return 0, err
}
t = uint64(time.Now().Unix()) - uint64(b)
atomic.StoreUint64(&cachedBootTime, t)
return t, nil
}
return 0, fmt.Errorf("could not find btime")
} }
func uptime(boot uint64) uint64 { func uptime(boot uint64) uint64 {
@ -235,26 +176,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
} }
func getOSRelease() (platform string, version string, err error) {
contents, err := common.ReadLines(common.HostEtc("os-release"))
if err != nil {
return "", "", nil // return empty
}
for _, line := range contents {
field := strings.Split(line, "=")
if len(field) < 2 {
continue
}
switch field[0] {
case "ID": // use ID for lowercase
platform = strings.Trim(field[1], `"`)
case "VERSION":
version = strings.Trim(field[1], `"`)
}
}
return platform, version, nil
}
func getLSB() (*LSB, error) { func getLSB() (*LSB, error) {
ret := &LSB{} ret := &LSB{}
if common.PathExists(common.HostEtc("lsb-release")) { if common.PathExists(common.HostEtc("lsb-release")) {
@ -392,7 +313,7 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
version = contents[0] version = contents[0]
} }
} else if common.PathExists(common.HostEtc("os-release")) { } else if common.PathExists(common.HostEtc("os-release")) {
p, v, err := getOSRelease() p, v, err := common.GetOSRelease()
if err == nil { if err == nil {
platform = p platform = p
version = v version = v
@ -515,116 +436,7 @@ func Virtualization() (string, string, error) {
} }
func VirtualizationWithContext(ctx context.Context) (string, string, error) { func VirtualizationWithContext(ctx context.Context) (string, string, error) {
var system string return common.VirtualizationWithContext(ctx)
var role string
filename := common.HostProc("xen")
if common.PathExists(filename) {
system = "xen"
role = "guest" // assume guest
if common.PathExists(filepath.Join(filename, "capabilities")) {
contents, err := common.ReadLines(filepath.Join(filename, "capabilities"))
if err == nil {
if common.StringsContains(contents, "control_d") {
role = "host"
}
}
}
}
filename = common.HostProc("modules")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsContains(contents, "kvm") {
system = "kvm"
role = "host"
} else if common.StringsContains(contents, "vboxdrv") {
system = "vbox"
role = "host"
} else if common.StringsContains(contents, "vboxguest") {
system = "vbox"
role = "guest"
} else if common.StringsContains(contents, "vmware") {
system = "vmware"
role = "guest"
}
}
}
filename = common.HostProc("cpuinfo")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsContains(contents, "QEMU Virtual CPU") ||
common.StringsContains(contents, "Common KVM processor") ||
common.StringsContains(contents, "Common 32-bit KVM processor") {
system = "kvm"
role = "guest"
}
}
}
filename = common.HostProc("bus/pci/devices")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err == nil {
if common.StringsContains(contents, "virtio-pci") {
role = "guest"
}
}
}
filename = common.HostProc()
if common.PathExists(filepath.Join(filename, "bc", "0")) {
system = "openvz"
role = "host"
} else if common.PathExists(filepath.Join(filename, "vz")) {
system = "openvz"
role = "guest"
}
// not use dmidecode because it requires root
if common.PathExists(filepath.Join(filename, "self", "status")) {
contents, err := common.ReadLines(filepath.Join(filename, "self", "status"))
if err == nil {
if common.StringsContains(contents, "s_context:") ||
common.StringsContains(contents, "VxID:") {
system = "linux-vserver"
}
// TODO: guest or host
}
}
if common.PathExists(filepath.Join(filename, "self", "cgroup")) {
contents, err := common.ReadLines(filepath.Join(filename, "self", "cgroup"))
if err == nil {
if common.StringsContains(contents, "lxc") {
system = "lxc"
role = "guest"
} else if common.StringsContains(contents, "docker") {
system = "docker"
role = "guest"
} else if common.StringsContains(contents, "machine-rkt") {
system = "rkt"
role = "guest"
} else if common.PathExists("/usr/bin/lxc-version") {
system = "lxc"
role = "host"
}
}
}
if common.PathExists(common.HostEtc("os-release")) {
p, _, err := getOSRelease()
if err == nil && p == "coreos" {
system = "rkt" // Is it true?
role = "host"
}
}
return system, role, nil
} }
func SensorsTemperatures() ([]TemperatureStat, error) { func SensorsTemperatures() ([]TemperatureStat, error) {

@ -3,9 +3,15 @@
package common package common
import ( import (
"context"
"fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"strconv"
"strings" "strings"
"sync/atomic"
"time"
) )
func DoSysctrl(mib string) ([]string, error) { func DoSysctrl(mib string) ([]string, error) {
@ -39,3 +45,192 @@ func NumProcs() (uint64, error) {
} }
return uint64(len(list)), err return uint64(len(list)), err
} }
// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64
func BootTimeWithContext(ctx context.Context) (uint64, error) {
t := atomic.LoadUint64(&cachedBootTime)
if t != 0 {
return t, nil
}
system, role, err := Virtualization()
if err != nil {
return 0, err
}
statFile := "stat"
if system == "lxc" && role == "guest" {
// if lxc, /proc/uptime is used.
statFile = "uptime"
} else if system == "docker" && role == "guest" {
// also docker, guest
statFile = "uptime"
}
filename := HostProc(statFile)
lines, err := ReadLines(filename)
if err != nil {
return 0, err
}
if statFile == "stat" {
for _, line := range lines {
if strings.HasPrefix(line, "btime") {
f := strings.Fields(line)
if len(f) != 2 {
return 0, fmt.Errorf("wrong btime format")
}
b, err := strconv.ParseInt(f[1], 10, 64)
if err != nil {
return 0, err
}
t = uint64(b)
atomic.StoreUint64(&cachedBootTime, t)
return t, nil
}
}
} else if statFile == "uptime" {
if len(lines) != 1 {
return 0, fmt.Errorf("wrong uptime format")
}
f := strings.Fields(lines[0])
b, err := strconv.ParseFloat(f[0], 64)
if err != nil {
return 0, err
}
t = uint64(time.Now().Unix()) - uint64(b)
atomic.StoreUint64(&cachedBootTime, t)
return t, nil
}
return 0, fmt.Errorf("could not find btime")
}
func Virtualization() (string, string, error) {
return VirtualizationWithContext(context.Background())
}
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
var system string
var role string
filename := HostProc("xen")
if PathExists(filename) {
system = "xen"
role = "guest" // assume guest
if PathExists(filepath.Join(filename, "capabilities")) {
contents, err := ReadLines(filepath.Join(filename, "capabilities"))
if err == nil {
if StringsContains(contents, "control_d") {
role = "host"
}
}
}
}
filename = HostProc("modules")
if PathExists(filename) {
contents, err := ReadLines(filename)
if err == nil {
if StringsContains(contents, "kvm") {
system = "kvm"
role = "host"
} else if StringsContains(contents, "vboxdrv") {
system = "vbox"
role = "host"
} else if StringsContains(contents, "vboxguest") {
system = "vbox"
role = "guest"
} else if StringsContains(contents, "vmware") {
system = "vmware"
role = "guest"
}
}
}
filename = HostProc("cpuinfo")
if PathExists(filename) {
contents, err := ReadLines(filename)
if err == nil {
if StringsContains(contents, "QEMU Virtual CPU") ||
StringsContains(contents, "Common KVM processor") ||
StringsContains(contents, "Common 32-bit KVM processor") {
system = "kvm"
role = "guest"
}
}
}
filename = HostProc()
if PathExists(filepath.Join(filename, "bc", "0")) {
system = "openvz"
role = "host"
} else if PathExists(filepath.Join(filename, "vz")) {
system = "openvz"
role = "guest"
}
// not use dmidecode because it requires root
if PathExists(filepath.Join(filename, "self", "status")) {
contents, err := ReadLines(filepath.Join(filename, "self", "status"))
if err == nil {
if StringsContains(contents, "s_context:") ||
StringsContains(contents, "VxID:") {
system = "linux-vserver"
}
// TODO: guest or host
}
}
if PathExists(filepath.Join(filename, "self", "cgroup")) {
contents, err := ReadLines(filepath.Join(filename, "self", "cgroup"))
if err == nil {
if StringsContains(contents, "lxc") {
system = "lxc"
role = "guest"
} else if StringsContains(contents, "docker") {
system = "docker"
role = "guest"
} else if StringsContains(contents, "machine-rkt") {
system = "rkt"
role = "guest"
} else if PathExists("/usr/bin/lxc-version") {
system = "lxc"
role = "host"
}
}
}
if PathExists(HostEtc("os-release")) {
p, _, err := GetOSRelease()
if err == nil && p == "coreos" {
system = "rkt" // Is it true?
role = "host"
}
}
return system, role, nil
}
func GetOSRelease() (platform string, version string, err error) {
contents, err := ReadLines(HostEtc("os-release"))
if err != nil {
return "", "", nil // return empty
}
for _, line := range contents {
field := strings.Split(line, "=")
if len(field) < 2 {
continue
}
switch field[0] {
case "ID": // use ID for lowercase
platform = field[1]
case "VERSION":
version = field[1]
}
}
return platform, version, nil
}

@ -16,7 +16,6 @@ import (
"strings" "strings"
"github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/net" "github.com/shirou/gopsutil/net"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -1236,7 +1235,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui
System: float64(stime / ClockTicks), System: float64(stime / ClockTicks),
} }
bootTime, _ := host.BootTime() bootTime, _ := common.BootTimeWithContext(ctx)
t, err := strconv.ParseUint(fields[i+20], 10, 64) t, err := strconv.ParseUint(fields[i+20], 10, 64)
if err != nil { if err != nil {
return 0, 0, nil, 0, 0, 0, nil, err return 0, 0, nil, 0, 0, 0, nil, err

Loading…
Cancel
Save