Repository: prometheus/procfs
Pull request #280 (2020-04-06 14:58:07)

Add wchan.
For https://github.com/ncabatoff/process-exporter/issues/140, I'm going to submit a PR on process-exporter to use upstream procfs (this repository) instead of github.com/ncabatoff/procfs fork.

But Wchan method is required by process-exporter and not yet implemented on prometheus/procfs, the PR add the feature.

This is mostly a cherry-pick of e1a38cb from github.com/ncabatoff/procfs
authored by @ncabatoff.

Edit: I've just seen that I referenced the wrong issue on process-exporter, fixed it the number.



Patch:
diff --git a/fixtures.ttar b/fixtures.ttar
index 45a7321..0fc2533 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -235,6 +235,11 @@ voluntary_ctxt_switches:	4742839
 nonvoluntary_ctxt_switches:	1727500
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/wchan
+Lines: 1
+poll_schedule_timeoutEOF
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/26232
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -310,6 +315,11 @@ Lines: 1
 33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26232/wchan
+Lines: 1
+0EOF
+Mode: 664
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/26233
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/proc.go b/proc.go
index 330e472..9f97b6e 100644
--- a/proc.go
+++ b/proc.go
@@ -134,6 +134,27 @@ func (p Proc) CmdLine() ([]string, error) {
 	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil
 }
 
+// Wchan returns the wchan (wait channel) of a process.
+func (p Proc) Wchan() (string, error) {
+	f, err := os.Open(p.path("wchan"))
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		return "", err
+	}
+
+	wchan := string(data)
+	if wchan == "" || wchan == "0" {
+		return "", nil
+	}
+
+	return wchan, nil
+}
+
 // Comm returns the command name of a process.
 func (p Proc) Comm() (string, error) {
 	data, err := util.ReadFileNoStat(p.path("comm"))


Test patch:
diff --git a/proc_test.go b/proc_test.go
index 60279fd..239e35b 100644
--- a/proc_test.go
+++ b/proc_test.go
@@ -72,6 +72,28 @@ func TestCmdLine(t *testing.T) {
 	}
 }
 
+func TestWchan(t *testing.T) {
+	for _, tt := range []struct {
+		process int
+		want    string
+	}{
+		{process: 26231, want: "poll_schedule_timeout"},
+		{process: 26232, want: ""},
+	} {
+		p1, err := getProcFixtures(t).Proc(tt.process)
+		if err != nil {
+			t.Fatal(err)
+		}
+		c1, err := p1.Wchan()
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !reflect.DeepEqual(tt.want, c1) {
+			t.Errorf("want wchan %v, have %v", tt.want, c1)
+		}
+	}
+}
+
 func TestComm(t *testing.T) {
 	for _, tt := range []struct {
 		process int