job_windows.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. Copyright 2020 Docker, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package mobycli
  14. import (
  15. "fmt"
  16. "os"
  17. "syscall"
  18. "unsafe"
  19. )
  20. func init() {
  21. if err := killSubProcessesOnClose(); err != nil {
  22. fmt.Println("failed to create job:", err)
  23. }
  24. }
  25. var (
  26. kernel32 = syscall.NewLazyDLL("kernel32.dll")
  27. )
  28. type jobObjectExtendedLimitInformation struct {
  29. BasicLimitInformation struct {
  30. PerProcessUserTimeLimit uint64
  31. PerJobUserTimeLimit uint64
  32. LimitFlags uint32
  33. MinimumWorkingSetSize uintptr
  34. MaximumWorkingSetSize uintptr
  35. ActiveProcessLimit uint32
  36. Affinity uintptr
  37. PriorityClass uint32
  38. SchedulingClass uint32
  39. }
  40. IoInfo struct {
  41. ReadOperationCount uint64
  42. WriteOperationCount uint64
  43. OtherOperationCount uint64
  44. ReadTransferCount uint64
  45. WriteTransferCount uint64
  46. OtherTransferCount uint64
  47. }
  48. ProcessMemoryLimit uintptr
  49. JobMemoryLimit uintptr
  50. PeakProcessMemoryUsed uintptr
  51. PeakJobMemoryUsed uintptr
  52. }
  53. // killSubProcessesOnClose will ensure on windows that all child processes of the current process are killed if parent is killed.
  54. func killSubProcessesOnClose() error {
  55. job, err := createJobObject()
  56. if err != nil {
  57. return err
  58. }
  59. info := jobObjectExtendedLimitInformation{}
  60. info.BasicLimitInformation.LimitFlags = 0x2000
  61. if err := setInformationJobObject(job, info); err != nil {
  62. _ = syscall.CloseHandle(job)
  63. return err
  64. }
  65. proc, err := syscall.GetCurrentProcess()
  66. if err != nil {
  67. _ = syscall.CloseHandle(job)
  68. return err
  69. }
  70. if err := assignProcessToJobObject(job, proc); err != nil {
  71. _ = syscall.CloseHandle(job)
  72. return err
  73. }
  74. return nil
  75. }
  76. func createJobObject() (syscall.Handle, error) {
  77. res, _, err := kernel32.NewProc("CreateJobObjectW").Call(uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
  78. if res == 0 {
  79. return syscall.InvalidHandle, os.NewSyscallError("CreateJobObject", err)
  80. }
  81. return syscall.Handle(res), nil
  82. }
  83. func setInformationJobObject(job syscall.Handle, info jobObjectExtendedLimitInformation) error {
  84. infoClass := uint32(9)
  85. res, _, err := kernel32.NewProc("SetInformationJobObject").Call(uintptr(job), uintptr(infoClass), uintptr(unsafe.Pointer(&info)), uintptr(uint32(unsafe.Sizeof(info))))
  86. if res == 0 {
  87. return os.NewSyscallError("SetInformationJobObject", err)
  88. }
  89. return nil
  90. }
  91. func assignProcessToJobObject(job syscall.Handle, process syscall.Handle) error {
  92. res, _, err := kernel32.NewProc("AssignProcessToJobObject").Call(uintptr(job), uintptr(process))
  93. if res == 0 {
  94. return os.NewSyscallError("AssignProcessToJobObject", err)
  95. }
  96. return nil
  97. }