Skip to content

Commit 38363d0

Browse files
committed
fix panic
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 56ab28a commit 38363d0

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

pkg/watch/watcher_darwin.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"os"
2424
"path/filepath"
25+
"sync/atomic"
2526
"time"
2627

2728
"github.com/fsnotify/fsevents"
@@ -38,6 +39,7 @@ type fseventNotify struct {
3839
stop chan struct{}
3940

4041
pathsWereWatching map[string]any
42+
running atomic.Bool
4143
}
4244

4345
func (d *fseventNotify) loop() {
@@ -81,17 +83,26 @@ func (d *fseventNotify) Start() error {
8183
return nil
8284
}
8385

86+
if !d.running.CompareAndSwap(false, true) {
87+
return nil
88+
}
89+
8490
numberOfWatches.Add(int64(len(d.stream.Paths)))
8591

8692
err := d.stream.Start()
8793
if err != nil {
94+
d.running.Store(false)
8895
return err
8996
}
9097
go d.loop()
9198
return nil
9299
}
93100

94101
func (d *fseventNotify) Close() error {
102+
if !d.running.CompareAndSwap(true, false) {
103+
return nil
104+
}
105+
95106
numberOfWatches.Add(int64(-len(d.stream.Paths)))
96107

97108
d.stream.Stop()

pkg/watch/watcher_darwin_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//go:build fsnotify
2+
3+
/*
4+
Copyright 2020 Docker Compose CLI authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package watch
20+
21+
import (
22+
"testing"
23+
24+
"gotest.tools/v3/assert"
25+
)
26+
27+
func TestFseventNotifyCloseIdempotent(t *testing.T) {
28+
// Create a watcher with a temporary directory
29+
tmpDir := t.TempDir()
30+
watcher, err := newWatcher([]string{tmpDir})
31+
assert.NilError(t, err)
32+
33+
// Start the watcher
34+
err = watcher.Start()
35+
assert.NilError(t, err)
36+
37+
// Close should work the first time
38+
err = watcher.Close()
39+
assert.NilError(t, err)
40+
41+
// Close should be idempotent - calling it again should not panic
42+
err = watcher.Close()
43+
assert.NilError(t, err)
44+
45+
// Even a third time should be safe
46+
err = watcher.Close()
47+
assert.NilError(t, err)
48+
}

0 commit comments

Comments
 (0)