@@ -53,7 +53,7 @@ type Container struct {
53
53
Args []string
54
54
55
55
Config * runconfig.Config
56
- State State
56
+ State * State
57
57
Image string
58
58
59
59
NetworkSettings * NetworkSettings
@@ -74,8 +74,7 @@ type Container struct {
74
74
daemon * Daemon
75
75
MountLabel , ProcessLabel string
76
76
77
- waitLock chan struct {}
78
- Volumes map [string ]string
77
+ Volumes map [string ]string
79
78
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
80
79
// Easier than migrating older container configs :)
81
80
VolumesRW map [string ]bool
@@ -284,7 +283,6 @@ func (container *Container) Start() (err error) {
284
283
if err := container .startLoggingToDisk (); err != nil {
285
284
return err
286
285
}
287
- container .waitLock = make (chan struct {})
288
286
289
287
return container .waitForStart ()
290
288
}
@@ -293,7 +291,7 @@ func (container *Container) Run() error {
293
291
if err := container .Start (); err != nil {
294
292
return err
295
293
}
296
- container .Wait ( )
294
+ container .State . WaitStop ( - 1 * time . Second )
297
295
return nil
298
296
}
299
297
@@ -307,7 +305,7 @@ func (container *Container) Output() (output []byte, err error) {
307
305
return nil , err
308
306
}
309
307
output , err = ioutil .ReadAll (pipe )
310
- container .Wait ( )
308
+ container .State . WaitStop ( - 1 * time . Second )
311
309
return output , err
312
310
}
313
311
@@ -467,6 +465,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
467
465
if err != nil {
468
466
utils .Errorf ("Error running container: %s" , err )
469
467
}
468
+ container .State .SetStopped (exitCode )
470
469
471
470
// Cleanup
472
471
container .cleanup ()
@@ -475,28 +474,17 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
475
474
if container .Config .OpenStdin {
476
475
container .stdin , container .stdinPipe = io .Pipe ()
477
476
}
478
-
479
477
if container .daemon != nil && container .daemon .srv != nil {
480
478
container .daemon .srv .LogEvent ("die" , container .ID , container .daemon .repositories .ImageName (container .Image ))
481
479
}
482
-
483
- close (container .waitLock )
484
-
485
480
if container .daemon != nil && container .daemon .srv != nil && container .daemon .srv .IsRunning () {
486
- container .State .SetStopped (exitCode )
487
-
488
- // FIXME: there is a race condition here which causes this to fail during the unit tests.
489
- // If another goroutine was waiting for Wait() to return before removing the container's root
490
- // from the filesystem... At this point it may already have done so.
491
- // This is because State.setStopped() has already been called, and has caused Wait()
492
- // to return.
493
- // FIXME: why are we serializing running state to disk in the first place?
494
- //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
481
+ // FIXME: here is race condition between two RUN instructions in Dockerfile
482
+ // because they share same runconfig and change image. Must be fixed
483
+ // in server/buildfile.go
495
484
if err := container .ToDisk (); err != nil {
496
- utils .Errorf ("Error dumping container state to disk: %s\n " , err )
485
+ utils .Errorf ("Error dumping container %s state to disk: %s\n " , container . ID , err )
497
486
}
498
487
}
499
-
500
488
return err
501
489
}
502
490
@@ -532,6 +520,7 @@ func (container *Container) cleanup() {
532
520
}
533
521
534
522
func (container * Container ) KillSig (sig int ) error {
523
+ utils .Debugf ("Sending %d to %s" , sig , container .ID )
535
524
container .Lock ()
536
525
defer container .Unlock ()
537
526
@@ -577,17 +566,17 @@ func (container *Container) Kill() error {
577
566
}
578
567
579
568
// 2. Wait for the process to die, in last resort, try to kill the process directly
580
- if err := container .WaitTimeout (10 * time .Second ); err != nil {
569
+ if _ , err := container .State . WaitStop (10 * time .Second ); err != nil {
581
570
// Ensure that we don't kill ourselves
582
- if pid := container .State .Pid ; pid != 0 {
571
+ if pid := container .State .GetPid () ; pid != 0 {
583
572
log .Printf ("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL" , utils .TruncateID (container .ID ))
584
573
if err := syscall .Kill (pid , 9 ); err != nil {
585
574
return err
586
575
}
587
576
}
588
577
}
589
578
590
- container .Wait ( )
579
+ container .State . WaitStop ( - 1 * time . Second )
591
580
return nil
592
581
}
593
582
@@ -605,11 +594,11 @@ func (container *Container) Stop(seconds int) error {
605
594
}
606
595
607
596
// 2. Wait for the process to exit on its own
608
- if err := container .WaitTimeout (time .Duration (seconds ) * time .Second ); err != nil {
597
+ if _ , err := container .State . WaitStop (time .Duration (seconds ) * time .Second ); err != nil {
609
598
log .Printf ("Container %v failed to exit within %d seconds of SIGTERM - using the force" , container .ID , seconds )
610
599
// 3. If it doesn't, then send SIGKILL
611
600
if err := container .Kill (); err != nil {
612
- container .Wait ( )
601
+ container .State . WaitStop ( - 1 * time . Second )
613
602
return err
614
603
}
615
604
}
@@ -630,12 +619,6 @@ func (container *Container) Restart(seconds int) error {
630
619
return container .Start ()
631
620
}
632
621
633
- // Wait blocks until the container stops running, then returns its exit code.
634
- func (container * Container ) Wait () int {
635
- <- container .waitLock
636
- return container .State .GetExitCode ()
637
- }
638
-
639
622
func (container * Container ) Resize (h , w int ) error {
640
623
return container .command .Terminal .Resize (h , w )
641
624
}
@@ -678,21 +661,6 @@ func (container *Container) Export() (archive.Archive, error) {
678
661
nil
679
662
}
680
663
681
- func (container * Container ) WaitTimeout (timeout time.Duration ) error {
682
- done := make (chan bool , 1 )
683
- go func () {
684
- container .Wait ()
685
- done <- true
686
- }()
687
-
688
- select {
689
- case <- time .After (timeout ):
690
- return fmt .Errorf ("Timed Out" )
691
- case <- done :
692
- return nil
693
- }
694
- }
695
-
696
664
func (container * Container ) Mount () error {
697
665
return container .daemon .Mount (container )
698
666
}
@@ -1103,9 +1071,7 @@ func (container *Container) startLoggingToDisk() error {
1103
1071
}
1104
1072
1105
1073
func (container * Container ) waitForStart () error {
1106
- callbackLock := make (chan struct {})
1107
1074
callback := func (command * execdriver.Command ) {
1108
- container .State .SetRunning (command .Pid ())
1109
1075
if command .Tty {
1110
1076
// The callback is called after the process Start()
1111
1077
// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
@@ -1117,16 +1083,23 @@ func (container *Container) waitForStart() error {
1117
1083
if err := container .ToDisk (); err != nil {
1118
1084
utils .Debugf ("%s" , err )
1119
1085
}
1120
- close ( callbackLock )
1086
+ container . State . SetRunning ( command . Pid () )
1121
1087
}
1122
1088
1123
1089
// We use a callback here instead of a goroutine and an chan for
1124
1090
// syncronization purposes
1125
1091
cErr := utils .Go (func () error { return container .monitor (callback ) })
1126
1092
1093
+ waitStart := make (chan struct {})
1094
+
1095
+ go func () {
1096
+ container .State .WaitRunning (- 1 * time .Second )
1097
+ close (waitStart )
1098
+ }()
1099
+
1127
1100
// Start should not return until the process is actually running
1128
1101
select {
1129
- case <- callbackLock :
1102
+ case <- waitStart :
1130
1103
case err := <- cErr :
1131
1104
return err
1132
1105
}
0 commit comments