選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

flock_windows.go 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2015 Tim Heckman. All rights reserved.
  2. // Use of this source code is governed by the BSD 3-Clause
  3. // license that can be found in the LICENSE file.
  4. package flock
  5. import (
  6. "syscall"
  7. )
  8. // ErrorLockViolation is the error code returned from the Windows syscall when a
  9. // lock would block and you ask to fail immediately.
  10. const ErrorLockViolation syscall.Errno = 0x21 // 33
  11. // Lock is a blocking call to try and take an exclusive file lock. It will wait
  12. // until it is able to obtain the exclusive file lock. It's recommended that
  13. // TryLock() be used over this function. This function may block the ability to
  14. // query the current Locked() or RLocked() status due to a RW-mutex lock.
  15. //
  16. // If we are already locked, this function short-circuits and returns
  17. // immediately assuming it can take the mutex lock.
  18. func (f *Flock) Lock() error {
  19. return f.lock(&f.l, winLockfileExclusiveLock)
  20. }
  21. // RLock is a blocking call to try and take a shared file lock. It will wait
  22. // until it is able to obtain the shared file lock. It's recommended that
  23. // TryRLock() be used over this function. This function may block the ability to
  24. // query the current Locked() or RLocked() status due to a RW-mutex lock.
  25. //
  26. // If we are already locked, this function short-circuits and returns
  27. // immediately assuming it can take the mutex lock.
  28. func (f *Flock) RLock() error {
  29. return f.lock(&f.r, winLockfileSharedLock)
  30. }
  31. func (f *Flock) lock(locked *bool, flag uint32) error {
  32. f.m.Lock()
  33. defer f.m.Unlock()
  34. if *locked {
  35. return nil
  36. }
  37. if f.fh == nil {
  38. if err := f.setFh(); err != nil {
  39. return err
  40. }
  41. defer f.ensureFhState()
  42. }
  43. if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
  44. return errNo
  45. }
  46. *locked = true
  47. return nil
  48. }
  49. // Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
  50. // while it is running the Locked() and RLocked() functions will be blocked.
  51. //
  52. // This function short-circuits if we are unlocked already. If not, it calls
  53. // UnlockFileEx() on the file and closes the file descriptor. It does not remove
  54. // the file from disk. It's up to your application to do.
  55. func (f *Flock) Unlock() error {
  56. f.m.Lock()
  57. defer f.m.Unlock()
  58. // if we aren't locked or if the lockfile instance is nil
  59. // just return a nil error because we are unlocked
  60. if (!f.l && !f.r) || f.fh == nil {
  61. return nil
  62. }
  63. // mark the file as unlocked
  64. if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 {
  65. return errNo
  66. }
  67. f.fh.Close()
  68. f.l = false
  69. f.r = false
  70. f.fh = nil
  71. return nil
  72. }
  73. // TryLock is the preferred function for taking an exclusive file lock. This
  74. // function does take a RW-mutex lock before it tries to lock the file, so there
  75. // is the possibility that this function may block for a short time if another
  76. // goroutine is trying to take any action.
  77. //
  78. // The actual file lock is non-blocking. If we are unable to get the exclusive
  79. // file lock, the function will return false instead of waiting for the lock. If
  80. // we get the lock, we also set the *Flock instance as being exclusive-locked.
  81. func (f *Flock) TryLock() (bool, error) {
  82. return f.try(&f.l, winLockfileExclusiveLock)
  83. }
  84. // TryRLock is the preferred function for taking a shared file lock. This
  85. // function does take a RW-mutex lock before it tries to lock the file, so there
  86. // is the possibility that this function may block for a short time if another
  87. // goroutine is trying to take any action.
  88. //
  89. // The actual file lock is non-blocking. If we are unable to get the shared file
  90. // lock, the function will return false instead of waiting for the lock. If we
  91. // get the lock, we also set the *Flock instance as being shared-locked.
  92. func (f *Flock) TryRLock() (bool, error) {
  93. return f.try(&f.r, winLockfileSharedLock)
  94. }
  95. func (f *Flock) try(locked *bool, flag uint32) (bool, error) {
  96. f.m.Lock()
  97. defer f.m.Unlock()
  98. if *locked {
  99. return true, nil
  100. }
  101. if f.fh == nil {
  102. if err := f.setFh(); err != nil {
  103. return false, err
  104. }
  105. defer f.ensureFhState()
  106. }
  107. _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{})
  108. if errNo > 0 {
  109. if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING {
  110. return false, nil
  111. }
  112. return false, errNo
  113. }
  114. *locked = true
  115. return true, nil
  116. }