Skip to content

Commit 713e1cd

Browse files
authored
Merge pull request #2729 from nirs/fix-locktuil-windows
Fix locktuil on windows
2 parents 11eb750 + 3840a3b commit 713e1cd

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

pkg/lockutil/lockutil_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package lockutil
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
)
11+
12+
const parallel = 20
13+
14+
func TestWithDirLock(t *testing.T) {
15+
dir := t.TempDir()
16+
log := filepath.Join(dir, "log")
17+
18+
errc := make(chan error, 10)
19+
for i := 0; i < parallel; i++ {
20+
go func() {
21+
err := WithDirLock(dir, func() error {
22+
if _, err := os.Stat(log); err == nil {
23+
return nil
24+
} else if !errors.Is(err, os.ErrNotExist) {
25+
return err
26+
}
27+
logFile, err := os.OpenFile(log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o640)
28+
if err != nil {
29+
return err
30+
}
31+
defer logFile.Close()
32+
if _, err := fmt.Fprintf(logFile, "writer %d\n", i); err != nil {
33+
return err
34+
}
35+
return logFile.Close()
36+
})
37+
errc <- err
38+
}()
39+
}
40+
41+
for i := 0; i < parallel; i++ {
42+
err := <-errc
43+
if err != nil {
44+
t.Error(err)
45+
}
46+
}
47+
48+
data, err := os.ReadFile(log)
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
lines := strings.Split(strings.Trim(string(data), "\n"), "\n")
53+
if len(lines) != 1 {
54+
t.Errorf("Expected one writer, got %v", lines)
55+
}
56+
}

pkg/lockutil/lockutil_windows.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,37 @@ var (
3333
procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
3434
)
3535

36+
const (
37+
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
38+
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
39+
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
40+
)
41+
3642
func WithDirLock(dir string, fn func() error) error {
3743
dirFile, err := os.OpenFile(dir+".lock", os.O_CREATE, 0o644)
3844
if err != nil {
3945
return err
4046
}
4147
defer dirFile.Close()
42-
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
43-
// 1 lock immediately
44-
if err := lockFileEx(syscall.Handle(dirFile.Fd()), 1, 0, 1, 0, &syscall.Overlapped{}); err != nil {
48+
if err := lockFileEx(
49+
syscall.Handle(dirFile.Fd()), // hFile
50+
LOCKFILE_EXCLUSIVE_LOCK, // dwFlags
51+
0, // dwReserved
52+
1, // nNumberOfBytesToLockLow
53+
0, // nNumberOfBytesToLockHigh
54+
&syscall.Overlapped{}, // lpOverlapped
55+
); err != nil {
4556
return fmt.Errorf("failed to lock %q: %w", dir, err)
4657
}
4758

4859
defer func() {
49-
if err := unlockFileEx(syscall.Handle(dirFile.Fd()), 0, 1, 0, &syscall.Overlapped{}); err != nil {
60+
if err := unlockFileEx(
61+
syscall.Handle(dirFile.Fd()), // hFile
62+
0, // dwReserved
63+
1, // nNumberOfBytesToLockLow
64+
0, // nNumberOfBytesToLockHigh
65+
&syscall.Overlapped{}, // lpOverlapped
66+
); err != nil {
5067
logrus.WithError(err).Errorf("failed to unlock %q", dir)
5168
}
5269
}()

0 commit comments

Comments
 (0)