zombie_others.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //go:build !windows
  15. // +build !windows
  16. package procutils
  17. import (
  18. "context"
  19. "io/ioutil"
  20. "os"
  21. "path/filepath"
  22. "strconv"
  23. "strings"
  24. "syscall"
  25. "time"
  26. "yunion.io/x/log"
  27. )
  28. func WaitZombieLoop(ctx context.Context) {
  29. myPid := os.Getpid()
  30. if myPid != 1 {
  31. log.Infof("My pid is not 1 and no need to wait zombies")
  32. return
  33. }
  34. const myPidStr = "1"
  35. tick := time.NewTicker(31 * time.Second)
  36. for {
  37. dirs, err := ioutil.ReadDir("/proc")
  38. if err != nil {
  39. log.Errorf("read /proc dir: %v", err)
  40. }
  41. for _, dir := range dirs {
  42. // /proc/<pid>/
  43. if !dir.IsDir() {
  44. continue
  45. }
  46. name := dir.Name()
  47. allDigits := true
  48. for _, c := range name {
  49. if c < '0' || c > '9' {
  50. allDigits = false
  51. break
  52. }
  53. }
  54. if !allDigits {
  55. continue
  56. }
  57. // read /proc/<pid>/stat
  58. statPath := filepath.Join("/proc", name, "stat")
  59. data, err := ioutil.ReadFile(statPath)
  60. if err != nil {
  61. log.Errorf("read %s: %v", statPath, err)
  62. continue
  63. }
  64. dataStr := string(data)
  65. items := strings.Split(dataStr, " ")
  66. const (
  67. idxPid = iota
  68. idxName
  69. idxState
  70. idxPpid
  71. idxMinLen
  72. )
  73. if len(items) < idxMinLen {
  74. log.Errorf("%s contains less than %d items: %s", statPath, idxMinLen, dataStr)
  75. }
  76. // my zombie subprocesses
  77. state := items[idxState]
  78. if state != "Z" {
  79. continue
  80. }
  81. ppidStr := items[idxPpid]
  82. if ppidStr != myPidStr {
  83. continue
  84. }
  85. // wait it
  86. pname := items[idxName]
  87. pidStr := items[idxPid]
  88. pid, err := strconv.Atoi(pidStr)
  89. if err != nil {
  90. log.Errorf("%s: %s has invalid pid number %q: %v", pname, statPath, pidStr, err)
  91. continue
  92. }
  93. pid1, err := syscall.Wait4(pid, nil, 0, nil)
  94. if err != nil {
  95. log.Errorf("%s: %s: wait error: %v", pname, statPath, err)
  96. continue
  97. }
  98. if pid1 == pid {
  99. log.Infof("%s: pid %d: wait done", pname, pid)
  100. }
  101. }
  102. select {
  103. case <-ctx.Done():
  104. case <-tick.C:
  105. }
  106. }
  107. }