implements some of process information on linux/amd64.

pull/4/head
WAKAYAMA Shirou 11 years ago committed by Shirou WAKAYAMA
parent 7b61bc5837
commit 1703a5b606

@ -1,5 +1,11 @@
package gopsutil
import (
"strings"
"os"
"syscall"
)
type Process struct {
Pid int32 `json:"pid"`
Ppid int32 `json:"ppid"`
@ -80,3 +86,42 @@ func Pid_exists(pid int32) (bool, error) {
return false, err
}
// POSIX
func getTerminalMap() (map[uint64]string, error){
ret := make(map[uint64]string)
termfiles := make([]string, 0)
d, err := os.Open("/dev")
if err != nil {
return nil, err
}
defer d.Close()
devnames, err := d.Readdirnames(-1)
for _, devname := range devnames{
if strings.HasPrefix(devname, "/dev/tty"){
termfiles = append(termfiles, "/dev/tty/" + devname)
}
}
ptsd, err := os.Open("/dev/pts")
if err != nil {
return nil, err
}
defer ptsd.Close()
ptsnames, err := ptsd.Readdirnames(-1)
for _, ptsname := range ptsnames{
termfiles = append(termfiles, "/dev/pts/" + ptsname)
}
for _, name := range termfiles{
stat := syscall.Stat_t{}
syscall.Stat(name, &stat)
rdev := stat.Rdev
ret[rdev] = strings.Replace(name, "/dev", "", -1)
}
return ret, nil
}

@ -8,13 +8,38 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
)
const (
PRIO_PROCESS = 0 // linux/resource.h
)
func NewProcess(pid int32) (*Process, error) {
p := &Process{
Pid: int32(pid),
}
go fillFromStat(pid, p)
var wg sync.WaitGroup
wg.Add(4)
go func() {
wg.Done()
fillFromStat(pid, p)
}()
go func() {
defer wg.Done()
fillFromStatus(pid, p)
}()
go func() {
defer wg.Done()
go fillFromfd(pid, p)
}()
go func() {
defer wg.Done()
go fillFromCmdline(pid, p)
}()
wg.Wait()
/*
// user := parseInt32(fields[13])
@ -33,22 +58,88 @@ func NewProcess(pid int32) (*Process, error) {
return p, nil
}
// Parse to int32 without error
func parseInt32(val string) int32 {
vv, _ := strconv.ParseInt(val, 10, 32)
return int32(vv)
}
// Parse to uint64 without error
func parseUint64(val string) uint64 {
vv, _ := strconv.ParseInt(val, 10, 64)
return uint64(vv)
}
// Get num_fds from /proc/(pid)/fd
func fillFromfd(pid int32, p *Process) error {
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "fd")
d, err := os.Open(statPath)
if err != nil {
return err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
p.Num_fds = int32(len(fnames))
/*
func fillFromStatm(pid int32, p *Process) error{
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "statm")
return nil
}
// Get cmdline from /proc/(pid)/cmdline
func fillFromCmdline(pid int32, p *Process) error {
cmdPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath)
if err != nil {
return err
}
// remove \u0000
p.Cmdline = strings.TrimFunc(string(cmdline), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
})
return nil
}
// get various status from /proc/(pid)/status
func fillFromStatus(pid int32, p *Process) error {
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "status")
contents, err := ioutil.ReadFile(statPath)
if err != nil {
return err
}
fields := strings.Fields(string(contents))
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
field := strings.Split(line, ":")
if len(field) < 2 {
continue
}
// fmt.Printf("%s ->__%s__\n", field[0], strings.Trim(field[1], " \t"))
switch field[0] {
case "Name":
p.Name = strings.Trim(field[1], " \t")
case "State":
// get between "(" and ")"
s := strings.Index(field[1], "(") + 1
e := strings.Index(field[1], "(") + 1
p.Status = field[1][s:e]
// case "PPid": // filled by fillFromStat
case "Uid":
for _, i := range strings.Split(field[1], "\t") {
p.Uids = append(p.Uids, parseInt32(i))
}
case "Gid":
for _, i := range strings.Split(field[1], "\t") {
p.Gids = append(p.Uids, parseInt32(i))
}
case "Threads":
p.Num_Threads = parseInt32(field[1])
}
}
return nil
}
*/
func fillFromStat(pid int32, p *Process) error {
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "stat")
@ -58,47 +149,26 @@ func fillFromStat(pid int32, p *Process) error {
}
fields := strings.Fields(string(contents))
p.Name = strings.Trim(fields[1], "()") // remove "(" and ")"
p.Status, _ = getState(fields[2][0])
termmap, err := getTerminalMap()
if err == nil{
p.Terminal = termmap[parseUint64(fields[6])]
}
p.Ppid = parseInt32(fields[3])
// p.Terminal, _ = strconv.Atoi(fields[6])
// p.Priority, _ = strconv.Atoi(fields[17])
p.Nice = parseInt32(fields[18])
// p.Processor, _ = strconv.Atoi(fields[38])
return nil
}
utime, _ := strconv.ParseFloat(fields[11], 64)
stime, _ := strconv.ParseFloat(fields[11], 64)
func getState(status uint8) (string, error) {
p.Cpu_times = CPU_TimesStat{
User: float32(utime / CLOCK_TICKS),
System: float32(stime / CLOCK_TICKS),
}
/*
>>> psutil.STATUS_RUNNING
'running'
>>> psutil.STATUS_SLEEPING
'sleeping'
>>> psutil.STATUS_DISK_SLEEP
'disk-sleep'
>>> psutil.STATUS_STOPPED
'stopped'
>>> psutil.STATUS_TRACING_STOP
'tracing-stop'
>>> psutil.STATUS_ZOMBIE
'zombie'
>>> psutil.STATUS_DEAD
'dead'
>>> psutil.STATUS_WAKE_KILL
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'ModuleWrapper' object has no attribute 'STATUS_WAKE_KILL'
>>> psutil.STATUS_WAKING
'waking'
>>> psutil.STATUS_IDLE
'idle'
>>> psutil.STATUS_LOCKED
'locked'
>>> psutil.STATUS_WAITING
'waiting'
*/
return "running", nil
// p.Nice = parseInt32(fields[18])
// use syscall instead of parse Stat file
nice, _ := syscall.Getpriority(PRIO_PROCESS, int(pid))
p.Nice = int32(nice) // FIXME: is this true?
return nil
}
func processes() ([]*Process, error) {

@ -0,0 +1,8 @@
// +build linux
// +build amd64
package gopsutil
const(
CLOCK_TICKS = 2 // FIXME: /usr/include/x86_64-linux-gnu/bits/time.h
)
Loading…
Cancel
Save