@@ -148,8 +148,12 @@ type Machine struct {
148
148
cmd * exec.Cmd
149
149
logger * log.Entry
150
150
machineConfig models.MachineConfiguration // The actual machine config as reported by Firecracker
151
- errCh chan error
152
- startOnce sync.Once
151
+ // startOnce ensures that the machine can only be started once
152
+ startOnce sync.Once
153
+ // exitCh is a channel which gets closed when the VMM exits
154
+ exitCh chan struct {}
155
+ // err records any error executing the VMM
156
+ err error
153
157
}
154
158
155
159
// Logger returns a logrus logger appropriate for logging hypervisor messages
@@ -201,7 +205,9 @@ func NewMachine(ctx context.Context, cfg Config, opts ...Opt) (*Machine, error)
201
205
return nil , err
202
206
}
203
207
204
- m := & Machine {}
208
+ m := & Machine {
209
+ exitCh : make (chan struct {}),
210
+ }
205
211
logger := log .New ()
206
212
207
213
if cfg .Debug {
@@ -251,13 +257,15 @@ func (m *Machine) Start(ctx context.Context) error {
251
257
return m .startInstance (ctx )
252
258
}
253
259
254
- // Wait will wait until the firecracker process has finished
260
+ // Wait will wait until the firecracker process has finished. Wait is safe to
261
+ // call concurrently, and will deliver the same error to all callers, subject to
262
+ // each caller's context cancellation.
255
263
func (m * Machine ) Wait (ctx context.Context ) error {
256
264
select {
257
265
case <- ctx .Done ():
258
266
return ctx .Err ()
259
- case err := <- m .errCh :
260
- return err
267
+ case <- m .exitCh :
268
+ return m . err
261
269
}
262
270
}
263
271
@@ -297,11 +305,12 @@ func (m *Machine) attachDrives(ctx context.Context, drives ...models.Drive) erro
297
305
func (m * Machine ) startVMM (ctx context.Context ) error {
298
306
m .logger .Printf ("Called startVMM(), setting up a VMM on %s" , m .cfg .SocketPath )
299
307
300
- m . errCh = make (chan error )
308
+ errCh : = make (chan error )
301
309
302
310
err := m .cmd .Start ()
303
311
if err != nil {
304
312
m .logger .Errorf ("Failed to start VMM: %s" , err )
313
+ close (m .exitCh )
305
314
return err
306
315
}
307
316
m .logger .Debugf ("VMM started socket path is %s" , m .cfg .SocketPath )
@@ -316,7 +325,7 @@ func (m *Machine) startVMM(ctx context.Context) error {
316
325
os .Remove (m .cfg .SocketPath )
317
326
os .Remove (m .cfg .LogFifo )
318
327
os .Remove (m .cfg .MetricsFifo )
319
- m . errCh <- err
328
+ errCh <- err
320
329
}()
321
330
322
331
// Set up a signal handler and pass INT, QUIT, and TERM through to firecracker
@@ -334,12 +343,18 @@ func (m *Machine) startVMM(ctx context.Context) error {
334
343
}()
335
344
336
345
// Wait for firecracker to initialize:
337
- err = m .waitForSocket (3 * time .Second , m . errCh )
346
+ err = m .waitForSocket (3 * time .Second , errCh )
338
347
if err != nil {
339
348
msg := fmt .Sprintf ("Firecracker did not create API socket %s: %s" , m .cfg .SocketPath , err )
340
349
err = errors .New (msg )
350
+ close (m .exitCh )
341
351
return err
342
352
}
353
+ go func () {
354
+ err := <- errCh
355
+ m .err = err
356
+ close (m .exitCh )
357
+ }()
343
358
344
359
m .logger .Debugf ("returning from startVMM()" )
345
360
return nil
0 commit comments