Skip to content

Commit

Permalink
Merge pull request #14 from theckman/appveyor
Browse files Browse the repository at this point in the history
Add Windows CI with AppVeyor; fix bugs discovered through Windows CI

Signed-off-by: Tim Heckman <[email protected]>
  • Loading branch information
theckman committed Jan 12, 2018
2 parents d0cbbf0 + f8d3134 commit 22bdc08
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 62 deletions.
25 changes: 25 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '{build}'

build: false
deploy: false

clone_folder: 'c:\gopath\src\github.com\theckman\go-flock'

environment:
GOPATH: 'c:\gopath'
GOVERSION: '1.9.2'

init:
- git config --global core.autocrlf input

install:
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- set Path=c:\go\bin;c:\gopath\bin;%Path%
- go version
- go env

test_script:
- go get -t ./...
- go test -v ./...
11 changes: 4 additions & 7 deletions flock_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ package flock_test
import (
"context"
"fmt"
"os"
"time"

"github.com/theckman/go-flock"
)

func ExampleFlock_Locked() {
f := flock.NewFlock("/tmp/go-lock.lock")
f := flock.NewFlock(os.TempDir() + "/go-lock.lock")
f.TryLock() // unchecked errors here

fmt.Printf("locked: %v\n", f.Locked())
Expand All @@ -27,7 +28,7 @@ func ExampleFlock_Locked() {

func ExampleFlock_TryLock() {
// should probably put these in /var/lock
fileLock := flock.NewFlock("/tmp/go-lock.lock")
fileLock := flock.NewFlock(os.TempDir() + "/go-lock.lock")

locked, err := fileLock.TryLock()

Expand All @@ -44,13 +45,11 @@ func ExampleFlock_TryLock() {
}

fmt.Printf("path: %s; locked: %v\n", fileLock.Path(), fileLock.Locked())
// Output: path: /tmp/go-lock.lock; locked: true
// path: /tmp/go-lock.lock; locked: false
}

func ExampleFlock_TryLockContext() {
// should probably put these in /var/lock
fileLock := flock.NewFlock("/tmp/go-lock.lock")
fileLock := flock.NewFlock(os.TempDir() + "/go-lock.lock")

lockCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
Expand All @@ -69,6 +68,4 @@ func ExampleFlock_TryLockContext() {
}

fmt.Printf("path: %s; locked: %v\n", fileLock.Path(), fileLock.Locked())
// Output: path: /tmp/go-lock.lock; locked: true
// path: /tmp/go-lock.lock; locked: false
}
65 changes: 20 additions & 45 deletions flock_winapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,12 @@ var (
)

const (
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
winLockfileFailImmediately = 0x00000001
winLockfileExclusiveLock = 0x00000002
)

// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)

var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
)

// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}

func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (success bool, err error) {
r1, _, e1 := syscall.Syscall6(
func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
r1, _, errNo := syscall.Syscall6(
uintptr(procLockFileEx),
6,
uintptr(handle),
Expand All @@ -58,19 +33,19 @@ func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBy
uintptr(numberOfBytesToLockHigh),
uintptr(unsafe.Pointer(offset)))

success = r1 == 1
if !success {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
if r1 != 1 {
if errNo == 0 {
return false, syscall.EINVAL
}

return false, errNo
}
return

return true, 0
}

func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (success bool, err error) {
r1, _, e1 := syscall.Syscall6(
func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
r1, _, errNo := syscall.Syscall6(
uintptr(procUnlockFileEx),
5,
uintptr(handle),
Expand All @@ -80,13 +55,13 @@ func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow
uintptr(unsafe.Pointer(offset)),
0)

success = r1 == 1
if !success {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
if r1 != 1 {
if errNo == 0 {
return false, syscall.EINVAL
}

return false, errNo
}
return

return true, 0
}
28 changes: 18 additions & 10 deletions flock_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"syscall"
)

// ErrorLockViolation is the error code returned from the Windows syscall when a
// lock would block and you ask to fail immediately.
const ErrorLockViolation syscall.Errno = 0x21 // 33

// Lock is a blocking call to try and take the file lock. It will wait until it
// is able to obtain the exclusive file lock. It's recommended that TryLock() be
// used over this function. This function may block the ability to query the
Expand All @@ -29,8 +33,8 @@ func (f *Flock) Lock() error {
}
}

if _, err := lockFileEx(syscall.Handle(f.fh.Fd()), LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &syscall.Overlapped{}); err != nil {
return err
if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), winLockfileExclusiveLock, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
return errNo
}

f.l = true
Expand All @@ -54,8 +58,8 @@ func (f *Flock) Unlock() error {
}

// mark the file as unlocked
if _, err := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); err != nil {
return err
if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
return errNo
}

f.fh.Close()
Expand Down Expand Up @@ -88,13 +92,17 @@ func (f *Flock) TryLock() (bool, error) {
}
}

_, err := lockFileEx(syscall.Handle(f.fh.Fd()), LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &syscall.Overlapped{})
_, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), winLockfileExclusiveLock|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{})

switch err {
case nil:
f.l = true
return true, nil
if errNo > 0 {
if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING {
return false, nil
}

return false, errNo
}

return false, err
f.l = true

return true, nil
}

0 comments on commit 22bdc08

Please sign in to comment.