Codebase list golang-github-alexflint-go-filemutex / fe62465
Update upstream source from tag 'upstream/1.2.0' Update to upstream version '1.2.0' with Debian dir cb5a13b3b66ca0a6d7032b58044a164d478cef97 Shengjing Zhu 1 year, 8 months ago
6 changed file(s) with 119 addition(s) and 92 deletion(s). Raw diff Collapse all Expand all
0 name: Go
1
2 on:
3 push:
4 branches: [ master ]
5 pull_request:
6 branches: [ master ]
7
8 jobs:
9
10 # Unfortunately there is much duplication below. I have not found a
11 # way to set "runs-on" to an array, so instead I duplicated the
12 # whole thing three times.
13
14 linux_build_and_test:
15 name: Build and test (Linux)
16 runs-on: windows-latest
17 strategy:
18 fail-fast: false
19 matrix:
20 go: ['1.13', '1.14', '1.15', '1.16']
21 steps:
22 - id: go
23 name: Set up Go
24 uses: actions/setup-go@v1
25 with:
26 go-version: ${{ matrix.go }}
27 - name: Checkout
28 uses: actions/checkout@v2
29 - name: Build
30 run: go build -v .
31 - name: Test
32 run: go test -v .
33
34 windows_build_and_test:
35 name: Build and test (Windows)
36 runs-on: windows-latest
37 strategy:
38 fail-fast: false
39 matrix:
40 go: ['1.13', '1.14', '1.15', '1.16']
41 steps:
42 - id: go
43 name: Set up Go
44 uses: actions/setup-go@v1
45 with:
46 go-version: ${{ matrix.go }}
47 - name: Checkout
48 uses: actions/checkout@v2
49 - name: Build
50 run: go build -v .
51 - name: Test
52 run: go test -v .
53
54 macos_build_and_test:
55 name: Build and test (macOS)
56 runs-on: macos-latest
57 strategy:
58 fail-fast: false
59 matrix:
60 go: ['1.13', '1.14', '1.15', '1.16']
61 steps:
62 - id: go
63 name: Set up Go
64 uses: actions/setup-go@v1
65 with:
66 go-version: ${{ matrix.go }}
67 - name: Checkout
68 uses: actions/checkout@v2
69 - name: Build
70 run: go build -v .
71 - name: Test
72 run: go test -v .
11 // Use of this source code is governed by a BSD-style
22 // license that can be found in the LICENSE file.
33
4 // +build darwin dragonfly freebsd linux netbsd openbsd
4 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
55
66 package filemutex
77
8 import (
9 "syscall"
10 )
8 import "golang.org/x/sys/unix"
119
1210 const (
1311 mkdirPerm = 0750
2018 }
2119
2220 func New(filename string) (*FileMutex, error) {
23 fd, err := syscall.Open(filename, syscall.O_CREAT|syscall.O_RDONLY, mkdirPerm)
21 fd, err := unix.Open(filename, unix.O_CREAT|unix.O_RDONLY, mkdirPerm)
2422 if err != nil {
2523 return nil, err
2624 }
2826 }
2927
3028 func (m *FileMutex) Lock() error {
31 if err := syscall.Flock(m.fd, syscall.LOCK_EX); err != nil {
32 return err
33 }
34 return nil
29 return unix.Flock(m.fd, unix.LOCK_EX)
3530 }
3631
3732 func (m *FileMutex) TryLock() error {
38 if err := syscall.Flock(m.fd, syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
39 if errno, ok := err.(syscall.Errno); ok {
40 if errno == syscall.EWOULDBLOCK {
33 if err := unix.Flock(m.fd, unix.LOCK_EX|unix.LOCK_NB); err != nil {
34 if errno, ok := err.(unix.Errno); ok {
35 if errno == unix.EWOULDBLOCK {
4136 return AlreadyLocked
4237 }
4338 }
4742 }
4843
4944 func (m *FileMutex) Unlock() error {
50 if err := syscall.Flock(m.fd, syscall.LOCK_UN); err != nil {
51 return err
52 }
53 return nil
45 return unix.Flock(m.fd, unix.LOCK_UN)
5446 }
5547
5648 func (m *FileMutex) RLock() error {
57 if err := syscall.Flock(m.fd, syscall.LOCK_SH); err != nil {
58 return err
59 }
60 return nil
49 return unix.Flock(m.fd, unix.LOCK_SH)
6150 }
6251
6352 func (m *FileMutex) RUnlock() error {
64 if err := syscall.Flock(m.fd, syscall.LOCK_UN); err != nil {
65 return err
66 }
67 return nil
53 return unix.Flock(m.fd, unix.LOCK_UN)
6854 }
6955
7056 // Close unlocks the lock and closes the underlying file descriptor.
7157 func (m *FileMutex) Close() error {
72 if err := syscall.Flock(m.fd, syscall.LOCK_UN); err != nil {
58 if err := unix.Flock(m.fd, unix.LOCK_UN); err != nil {
7359 return err
7460 }
75 return syscall.Close(m.fd)
61 return unix.Close(m.fd)
7662 }
7272 m.Close()
7373 }
7474
75 func TestOnlyClose(t *testing.T) {
76 dir, err := ioutil.TempDir("", "")
77 require.NoError(t, err)
78 defer os.RemoveAll(dir)
79
80 path := filepath.Join(dir, "x")
81 m, err := New(path)
82 require.NoError(t, err)
83
84 require.NoError(t, m.Close())
85 }
86
7587 func TestLockErrorsAreRecoverable(t *testing.T) {
7688 dir, err := ioutil.TempDir("", "")
7789 require.NoError(t, err)
55
66 import (
77 "syscall"
8 "unsafe"
8
9 "golang.org/x/sys/windows"
910 )
1011
11 var (
12 modkernel32 = syscall.NewLazyDLL("kernel32.dll")
13 procLockFileEx = modkernel32.NewProc("LockFileEx")
14 procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
15 )
16
17 const (
18 lockfileFailImmediately = 1
19 lockfileExclusiveLock = 2
20 )
21
22 func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
23 r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
24 if r1 == 0 {
25 if e1 != 0 {
26 err = error(e1)
27 } else {
28 err = syscall.EINVAL
29 }
30 }
31 return
32 }
33
34 func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
35 r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
36 if r1 == 0 {
37 if e1 != 0 {
38 err = error(e1)
39 } else {
40 err = syscall.EINVAL
41 }
42 }
43 return
44 }
12 // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
13 var errLockUnlocked syscall.Errno = 0x9E
4514
4615 // FileMutex is similar to sync.RWMutex, but also synchronizes across processes.
4716 // This implementation is based on flock syscall.
4817 type FileMutex struct {
49 fd syscall.Handle
18 fd windows.Handle
5019 }
5120
5221 func New(filename string) (*FileMutex, error) {
53 fd, err := syscall.CreateFile(&(syscall.StringToUTF16(filename)[0]), syscall.GENERIC_READ|syscall.GENERIC_WRITE,
54 syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, nil, syscall.OPEN_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
22 fd, err := windows.CreateFile(&(windows.StringToUTF16(filename)[0]), windows.GENERIC_READ|windows.GENERIC_WRITE,
23 windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_ALWAYS, windows.FILE_ATTRIBUTE_NORMAL, 0)
5524 if err != nil {
5625 return nil, err
5726 }
5928 }
6029
6130 func (m *FileMutex) TryLock() error {
62 var ol syscall.Overlapped
63 if err := lockFileEx(m.fd, lockfileFailImmediately|lockfileExclusiveLock, 0, 1, 0, &ol); err != nil {
64 if errno, ok := err.(syscall.Errno); ok {
65 if errno == syscall.Errno(0x21) {
31 if err := windows.LockFileEx(m.fd, windows.LOCKFILE_FAIL_IMMEDIATELY|windows.LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &windows.Overlapped{}); err != nil {
32 if errno, ok := err.(windows.Errno); ok {
33 if errno == windows.ERROR_LOCK_VIOLATION {
6634 return AlreadyLocked
6735 }
6836 }
7240 }
7341
7442 func (m *FileMutex) Lock() error {
75 var ol syscall.Overlapped
76 if err := lockFileEx(m.fd, lockfileExclusiveLock, 0, 1, 0, &ol); err != nil {
77 return err
78 }
79 return nil
43 return windows.LockFileEx(m.fd, windows.LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &windows.Overlapped{})
8044 }
8145
8246 func (m *FileMutex) Unlock() error {
83 var ol syscall.Overlapped
84 if err := unlockFileEx(m.fd, 0, 1, 0, &ol); err != nil {
85 return err
86 }
87 return nil
47 return windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{})
8848 }
8949
9050 func (m *FileMutex) RLock() error {
91 var ol syscall.Overlapped
92 if err := lockFileEx(m.fd, 0, 0, 1, 0, &ol); err != nil {
93 return err
94 }
95 return nil
51 return windows.LockFileEx(m.fd, 0, 0, 1, 0, &windows.Overlapped{})
9652 }
9753
9854 func (m *FileMutex) RUnlock() error {
99 var ol syscall.Overlapped
100 if err := unlockFileEx(m.fd, 0, 1, 0, &ol); err != nil {
101 return err
102 }
103 return nil
55 return windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{})
10456 }
10557
10658 // Close unlocks the lock and closes the underlying file descriptor.
10759 func (m *FileMutex) Close() error {
108 var ol syscall.Overlapped
109 if err := unlockFileEx(m.fd, 0, 1, 0, &ol); err != nil {
60 if err := windows.UnlockFileEx(m.fd, 0, 1, 0, &windows.Overlapped{}); err != nil && err != errLockUnlocked {
11061 return err
11162 }
112 return syscall.Close(m.fd)
63 return windows.Close(m.fd)
11364 }
11
22 go 1.13
33
4 require github.com/stretchr/testify v1.4.0
4 require (
5 github.com/stretchr/testify v1.4.0
6 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
7 )
44 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
55 github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
66 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
7 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
8 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
79 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
810 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
911 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=