Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/proc/reaper_unsupported.go → pkg/proc/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ package proc

// StartReaper has no effect on non-linux platforms.
// Support for other unices will be added.
func StartReaper() {
func StartReaper(period time.Duration) {
}
82 changes: 82 additions & 0 deletions pkg/proc/proc_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package proc

import (
"bufio"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"

"k8s.io/klog"
)

// parseProcForZombies parses the current procfs mounted at /proc
// to find processes in the zombie state.
func parseProcForZombies() ([]int, error) {
files, err := ioutil.ReadDir("/proc")
if err != nil {
return nil, err
}

var zombies []int
for _, file := range files {
processID, err := strconv.Atoi(file.Name())
if err != nil {
break
}
stateFilePath := filepath.Join("/proc", file.Name(), "status")
fd, err := os.Open(stateFilePath)
if err != nil {
klog.Errorf("Failed to open %v for getting process status: %v", stateFilePath, err)
continue
}
defer fd.Close()
fs := bufio.NewScanner(fd)
for fs.Scan() {
line := fs.Text()
if strings.HasPrefix(line, "State:") {
if strings.Contains(line, "zombie") {
zombies = append(zombies, processID)
}
break
}
}
}

return zombies, nil
}

// StartReaper starts a goroutine to reap processes periodically if called
// from a pid 1 process.
// If period is 0, then it is defaulted to 5 seconds.
// A caller can adjust the period depending on how many and how frequently zombie
// processes are created and need to be reaped.
func StartReaper(period time.Duration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If period is less than or equal to zero set it to five seconds and add a comment above. Also describe why you might change the default period (if you create tens of thousands of defunct processes every five seconds).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

if os.Getpid() == 1 {
const defaultReaperPeriodSeconds = 5
if period == 0 {
period = defaultReaperPeriodSeconds * time.Second
}
go func() {
var zs []int
var err error
for {
zs, err = parseProcForZombies()
if err != nil {
klog.Errorf("Failed to parse proc filesystem to find processes to reap: %v", err)
continue
}
time.Sleep(period)
for _, z := range zs {
cpid, err := syscall.Wait4(z, nil, syscall.WNOHANG, nil)
if err != nil {
klog.Errorf("Unable to reap process pid %v: %v", cpid, err)
}
}
}
}()
}
}
37 changes: 0 additions & 37 deletions pkg/proc/reaper.go

This file was deleted.