2
0

cgroup.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package worker
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "strconv"
  8. "syscall"
  9. "golang.org/x/sys/unix"
  10. "github.com/codeskyblue/go-sh"
  11. )
  12. var cgSubsystem string = "cpu"
  13. type cgroupHook struct {
  14. emptyHook
  15. provider mirrorProvider
  16. basePath string
  17. baseGroup string
  18. created bool
  19. }
  20. func initCgroup(basePath string) {
  21. if _, err := os.Stat(filepath.Join(basePath, "memory")); err == nil {
  22. cgSubsystem = "memory"
  23. return
  24. }
  25. logger.Warning("Memory subsystem of cgroup not enabled, fallback to cpu")
  26. }
  27. func newCgroupHook(p mirrorProvider, basePath, baseGroup string) *cgroupHook {
  28. if basePath == "" {
  29. basePath = "/sys/fs/cgroup"
  30. }
  31. if baseGroup == "" {
  32. baseGroup = "tunasync"
  33. }
  34. return &cgroupHook{
  35. provider: p,
  36. basePath: basePath,
  37. baseGroup: baseGroup,
  38. }
  39. }
  40. func (c *cgroupHook) preExec() error {
  41. c.created = true
  42. if err := sh.Command("cgcreate", "-g", c.Cgroup()).Run(); err != nil {
  43. return err
  44. }
  45. if cgSubsystem != "memory" {
  46. return nil
  47. }
  48. if c.provider.Type() == provRsync || c.provider.Type() == provTwoStageRsync {
  49. gname := fmt.Sprintf("%s/%s", c.baseGroup, c.provider.Name())
  50. return sh.Command(
  51. "cgset", "-r", "memory.limit_in_bytes=128M", gname,
  52. ).Run()
  53. }
  54. return nil
  55. }
  56. func (c *cgroupHook) postExec() error {
  57. err := c.killAll()
  58. if err != nil {
  59. logger.Errorf("Error killing tasks: %s", err.Error())
  60. }
  61. c.created = false
  62. return sh.Command("cgdelete", c.Cgroup()).Run()
  63. }
  64. func (c *cgroupHook) Cgroup() string {
  65. name := c.provider.Name()
  66. return fmt.Sprintf("%s:%s/%s", cgSubsystem, c.baseGroup, name)
  67. }
  68. func (c *cgroupHook) killAll() error {
  69. if !c.created {
  70. return nil
  71. }
  72. name := c.provider.Name()
  73. taskFile, err := os.Open(filepath.Join(c.basePath, cgSubsystem, c.baseGroup, name, "tasks"))
  74. if err != nil {
  75. return err
  76. }
  77. defer taskFile.Close()
  78. taskList := []int{}
  79. scanner := bufio.NewScanner(taskFile)
  80. for scanner.Scan() {
  81. pid, err := strconv.Atoi(scanner.Text())
  82. if err != nil {
  83. return err
  84. }
  85. taskList = append(taskList, pid)
  86. }
  87. for _, pid := range taskList {
  88. logger.Debugf("Killing process: %d", pid)
  89. unix.Kill(pid, syscall.SIGKILL)
  90. }
  91. return nil
  92. }