mirror of
https://github.com/containers/podman.git
synced 2025-06-22 01:48:54 +08:00
Merge pull request #3162 from giuseppe/fix-hang-waitforfile
util: fix race condition in WaitForFile
This commit is contained in:
@ -289,8 +289,8 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir
|
|||||||
chWait := make(chan error)
|
chWait := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
chWait <- execCmd.Wait()
|
chWait <- execCmd.Wait()
|
||||||
|
close(chWait)
|
||||||
}()
|
}()
|
||||||
defer close(chWait)
|
|
||||||
|
|
||||||
pidFile := c.execPidPath(sessionID)
|
pidFile := c.execPidPath(sessionID)
|
||||||
// 60 second seems a reasonable time to wait
|
// 60 second seems a reasonable time to wait
|
||||||
|
@ -90,11 +90,7 @@ func MountExists(specMounts []spec.Mount, dest string) bool {
|
|||||||
|
|
||||||
// WaitForFile waits until a file has been created or the given timeout has occurred
|
// WaitForFile waits until a file has been created or the given timeout has occurred
|
||||||
func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, error) {
|
func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, error) {
|
||||||
done := make(chan struct{})
|
|
||||||
chControl := make(chan struct{})
|
|
||||||
|
|
||||||
var inotifyEvents chan fsnotify.Event
|
var inotifyEvents chan fsnotify.Event
|
||||||
var timer chan struct{}
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
watcher, err := fsnotify.NewWatcher()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := watcher.Add(filepath.Dir(path)); err == nil {
|
if err := watcher.Add(filepath.Dir(path)); err == nil {
|
||||||
@ -102,51 +98,36 @@ func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, e
|
|||||||
}
|
}
|
||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
}
|
}
|
||||||
if inotifyEvents == nil {
|
|
||||||
// If for any reason we fail to create the inotify
|
|
||||||
// watcher, fallback to polling the file
|
|
||||||
timer = make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case <-chControl:
|
|
||||||
close(timer)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
time.Sleep(25 * time.Millisecond)
|
|
||||||
timer <- struct{}{}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
timeoutChan := time.After(timeout)
|
||||||
for {
|
|
||||||
select {
|
for {
|
||||||
case <-chControl:
|
select {
|
||||||
return
|
case e := <-chWait:
|
||||||
case <-timer:
|
return true, e
|
||||||
_, err := os.Stat(path)
|
case <-inotifyEvents:
|
||||||
if err == nil {
|
_, err := os.Stat(path)
|
||||||
close(done)
|
if err == nil {
|
||||||
return
|
return false, nil
|
||||||
}
|
|
||||||
case <-inotifyEvents:
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err == nil {
|
|
||||||
close(done)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return false, errors.Wrapf(err, "checking file %s", path)
|
||||||
|
}
|
||||||
|
case <-time.After(25 * time.Millisecond):
|
||||||
|
// Check periodically for the file existence. It is needed
|
||||||
|
// if the inotify watcher could not have been created. It is
|
||||||
|
// also useful when using inotify as if for any reasons we missed
|
||||||
|
// a notification, we won't hang the process.
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return false, errors.Wrapf(err, "checking file %s", path)
|
||||||
|
}
|
||||||
|
case <-timeoutChan:
|
||||||
|
return false, errors.Wrapf(ErrInternal, "timed out waiting for file %s", path)
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case e := <-chWait:
|
|
||||||
return true, e
|
|
||||||
case <-done:
|
|
||||||
return false, nil
|
|
||||||
case <-time.After(timeout):
|
|
||||||
close(chControl)
|
|
||||||
return false, errors.Wrapf(ErrInternal, "timed out waiting for file %s", path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user