github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/builder/filemutex_windows.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"sync"
     9  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  var (
    14  	modkernel32      = syscall.NewLazyDLL("kernel32.dll")
    15  	procLockFileEx   = modkernel32.NewProc("LockFileEx")
    16  	procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
    17  )
    18  
    19  const (
    20  	INVALID_FILE_HANDLE     = ^syscall.Handle(0)
    21  	LOCKFILE_EXCLUSIVE_LOCK = 2
    22  )
    23  
    24  func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
    25  	r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
    26  	if r1 == 0 {
    27  		if e1 != 0 {
    28  			err = error(e1)
    29  		} else {
    30  			err = syscall.EINVAL
    31  		}
    32  	}
    33  	return
    34  }
    35  
    36  func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
    37  	r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
    38  	if r1 == 0 {
    39  		if e1 != 0 {
    40  			err = error(e1)
    41  		} else {
    42  			err = syscall.EINVAL
    43  		}
    44  	}
    45  	return
    46  }
    47  
    48  // FileMutex is similar to sync.RWMutex, but also synchronizes across processes.
    49  // This implementation is based on flock syscall.
    50  type FileMutex struct {
    51  	mu sync.RWMutex
    52  	fd syscall.Handle
    53  }
    54  
    55  func MakeFileMutex(filename string) *FileMutex {
    56  	if filename == "" {
    57  		return &FileMutex{fd: INVALID_FILE_HANDLE}
    58  	}
    59  	fd, err := syscall.CreateFile(&(syscall.StringToUTF16(filename)[0]), syscall.GENERIC_READ|syscall.GENERIC_WRITE,
    60  		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, nil, syscall.OPEN_ALWAYS, syscall.FILE_ATTRIBUTE_NORMAL, 0)
    61  	if err != nil {
    62  		panic(err)
    63  	}
    64  	return &FileMutex{fd: fd}
    65  }
    66  
    67  func (m *FileMutex) Lock() {
    68  	m.mu.Lock()
    69  	if m.fd != INVALID_FILE_HANDLE {
    70  		var ol syscall.Overlapped
    71  		if err := lockFileEx(m.fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol); err != nil {
    72  			panic(err)
    73  		}
    74  	}
    75  }
    76  
    77  func (m *FileMutex) Unlock() {
    78  	if m.fd != INVALID_FILE_HANDLE {
    79  		var ol syscall.Overlapped
    80  		if err := unlockFileEx(m.fd, 0, 1, 0, &ol); err != nil {
    81  			panic(err)
    82  		}
    83  	}
    84  	m.mu.Unlock()
    85  }
    86  
    87  func (m *FileMutex) RLock() {
    88  	m.mu.RLock()
    89  	if m.fd != INVALID_FILE_HANDLE {
    90  		var ol syscall.Overlapped
    91  		if err := lockFileEx(m.fd, 0, 0, 1, 0, &ol); err != nil {
    92  			panic(err)
    93  		}
    94  	}
    95  }
    96  
    97  func (m *FileMutex) RUnlock() {
    98  	if m.fd != INVALID_FILE_HANDLE {
    99  		var ol syscall.Overlapped
   100  		if err := unlockFileEx(m.fd, 0, 1, 0, &ol); err != nil {
   101  			panic(err)
   102  		}
   103  	}
   104  	m.mu.RUnlock()
   105  }