...
1
2
3 package jobobject
4
5 import (
6 "context"
7 "fmt"
8 "sync"
9 "unsafe"
10
11 "github.com/Microsoft/hcsshim/internal/log"
12 "github.com/Microsoft/hcsshim/internal/queue"
13 "github.com/Microsoft/hcsshim/internal/winapi"
14 "github.com/sirupsen/logrus"
15 "golang.org/x/sys/windows"
16 )
17
18 var (
19 ioInitOnce sync.Once
20 initIOErr error
21
22 ioCompletionPort windows.Handle
23
24 jobMap sync.Map
25 )
26
27
28 type MsgAllProcessesExited struct{}
29
30
31
32 type MsgUnimplemented struct{}
33
34
35 func pollIOCP(ctx context.Context, iocpHandle windows.Handle) {
36 var (
37 overlapped uintptr
38 code uint32
39 key uintptr
40 )
41
42 for {
43 err := windows.GetQueuedCompletionStatus(iocpHandle, &code, &key, (**windows.Overlapped)(unsafe.Pointer(&overlapped)), windows.INFINITE)
44 if err != nil {
45 log.G(ctx).WithError(err).Error("failed to poll for job object message")
46 continue
47 }
48 if val, ok := jobMap.Load(key); ok {
49 msq, ok := val.(*queue.MessageQueue)
50 if !ok {
51 log.G(ctx).WithField("value", msq).Warn("encountered non queue type in job map")
52 continue
53 }
54 notification, err := parseMessage(code, overlapped)
55 if err != nil {
56 log.G(ctx).WithFields(logrus.Fields{
57 "code": code,
58 "overlapped": overlapped,
59 }).Warn("failed to parse job object message")
60 continue
61 }
62 if err := msq.Enqueue(notification); err == queue.ErrQueueClosed {
63
64
65
66
67
68 log.G(ctx).WithFields(logrus.Fields{
69 "code": code,
70 "overlapped": overlapped,
71 }).Warn("tried to write to a closed queue")
72 continue
73 }
74 } else {
75 log.G(ctx).Warn("received a message for a job not present in the mapping")
76 }
77 }
78 }
79
80 func parseMessage(code uint32, overlapped uintptr) (interface{}, error) {
81
82
83
84 switch code {
85 case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
86 return MsgAllProcessesExited{}, nil
87
88
89 case winapi.JOB_OBJECT_MSG_END_OF_JOB_TIME:
90 case winapi.JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
91 case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
92 case winapi.JOB_OBJECT_MSG_NEW_PROCESS:
93 case winapi.JOB_OBJECT_MSG_EXIT_PROCESS:
94 case winapi.JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
95 case winapi.JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
96 case winapi.JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
97 case winapi.JOB_OBJECT_MSG_NOTIFICATION_LIMIT:
98 default:
99 return nil, fmt.Errorf("unknown job notification type: %d", code)
100 }
101 return MsgUnimplemented{}, nil
102 }
103
104
105
106 func attachIOCP(job windows.Handle, iocp windows.Handle) error {
107 info := winapi.JOBOBJECT_ASSOCIATE_COMPLETION_PORT{
108 CompletionKey: job,
109 CompletionPort: iocp,
110 }
111 _, err := windows.SetInformationJobObject(job, windows.JobObjectAssociateCompletionPortInformation, uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
112 return err
113 }
114
View as plain text