@@ -23,6 +23,9 @@ type Process struct {
2323 callbackNumber uintptr
2424
2525 logctx logrus.Fields
26+
27+ waitBlock chan struct {}
28+ waitError error
2629}
2730
2831func newProcess (process hcsProcess , processID int , computeSystem * System ) * Process {
@@ -34,6 +37,7 @@ func newProcess(process hcsProcess, processID int, computeSystem *System) *Proce
3437 logfields .ContainerID : computeSystem .ID (),
3538 logfields .ProcessID : processID ,
3639 },
40+ waitBlock : make (chan struct {}),
3741 }
3842}
3943
@@ -163,33 +167,47 @@ func (process *Process) Kill() (err error) {
163167 return nil
164168}
165169
166- // Wait waits for the process to exit.
170+ // waitBackground waits for the process exit notification. Once received sets
171+ // `process.waitError` (if any) and unblocks all `Wait` and `WaitTimeout` calls.
172+ //
173+ // This MUST be called exactly once per `process.handle` but `Wait` and
174+ // `WaitTimeout` are safe to call multiple times.
175+ func (process * Process ) waitBackground () {
176+ process .waitError = waitForNotification (process .callbackNumber , hcsNotificationProcessExited , nil )
177+ close (process .waitBlock )
178+ }
179+
180+ // Wait waits for the process to exit. If the process has already exited returns
181+ // the pervious error (if any).
167182func (process * Process ) Wait () (err error ) {
168183 operation := "hcsshim::Process::Wait"
169184 process .logOperationBegin (operation )
170185 defer func () { process .logOperationEnd (operation , err ) }()
171186
172- err = waitForNotification ( process .callbackNumber , hcsNotificationProcessExited , nil )
173- if err != nil {
187+ <- process .waitBlock
188+ if process . waitError != nil {
174189 return makeProcessError (process , operation , err , nil )
175190 }
176-
177191 return nil
178192}
179193
180- // WaitTimeout waits for the process to exit or the duration to elapse. It returns
181- // false if timeout occurs.
194+ // WaitTimeout waits for the process to exit or the duration to elapse. If the
195+ // process has already exited returns the pervious error (if any). If a timeout
196+ // occurs returns `ErrTimeout`.
182197func (process * Process ) WaitTimeout (timeout time.Duration ) (err error ) {
183198 operation := "hcssshim::Process::WaitTimeout"
184199 process .logOperationBegin (operation )
185200 defer func () { process .logOperationEnd (operation , err ) }()
186201
187- err = waitForNotification (process .callbackNumber , hcsNotificationProcessExited , & timeout )
188- if err != nil {
189- return makeProcessError (process , operation , err , nil )
202+ select {
203+ case <- process .waitBlock :
204+ if process .waitError != nil {
205+ return makeProcessError (process , operation , process .waitError , nil )
206+ }
207+ return nil
208+ case <- time .After (timeout ):
209+ return makeProcessError (process , operation , ErrTimeout , nil )
190210 }
191-
192- return nil
193211}
194212
195213// ResizeConsole resizes the console of the process.
0 commit comments