// flock acquires an advisory lock on a file descriptor. func flock(f *os.File, exclusive bool, timeout time.Duration) error { var t time.Time for { // If we're beyond our timeout then return an error. // This can only occur after we've attempted a flock once. if t.IsZero() { t = time.Now() } else if timeout > 0 && time.Since(t) > timeout { return ErrTimeout } var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 lock.Pid = 0 lock.Whence = 0 lock.Pid = 0 if exclusive { lock.Type = syscall.F_WRLCK } else { lock.Type = syscall.F_RDLCK } err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &lock) if err == nil { return nil } else if err != syscall.EAGAIN { return err } // Wait for a bit and try again. time.Sleep(50 * time.Millisecond) } }
// funlock releases an advisory lock on a file descriptor. func funlock(f *os.File) error { var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 lock.Type = syscall.F_UNLCK lock.Whence = 0 return syscall.FcntlFlock(uintptr(f.Fd()), syscall.F_SETLK, &lock) }
// Lock acquires exclusivity on the lock without blocking func (l *lock) Lock() error { var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 lock.Type = syscall.F_WRLCK lock.Whence = 0 lock.Pid = 0 return syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) }
// Unlock unlocks the lock func (l *lock) Unlock() error { var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 lock.Type = syscall.F_UNLCK lock.Whence = 0 err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) if err != nil && err == syscall.EAGAIN { return ErrLocked } return err }
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 lock.Pid = 0 lock.Type = syscall.F_WRLCK lock.Whence = 0 f, err := os.OpenFile(path, flag, perm) if err != nil { return nil, err } if err = syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, &lock); err != nil { f.Close() return nil, err } return &LockedFile{f}, nil }