github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/fs/locker.go (about) 1 // Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . 2 3 package fsutils 4 5 import ( 6 "os" 7 "syscall" 8 "time" 9 ) 10 11 type Locker struct { 12 path string 13 fp *os.File 14 } 15 16 func NewLocker(path string) *Locker { 17 return &Locker{ 18 path: path + ".lock", 19 } 20 } 21 22 func (this *Locker) TryLock() (ok bool, err error) { 23 if this.fp == nil { 24 fp, err := os.OpenFile(this.path, os.O_CREATE|os.O_WRONLY, 0666) 25 if err != nil { 26 return false, err 27 } 28 this.fp = fp 29 } 30 return this.tryLock() 31 } 32 33 func (this *Locker) Lock() error { 34 if this.fp == nil { 35 fp, err := os.OpenFile(this.path, os.O_CREATE|os.O_WRONLY, 0666) 36 if err != nil { 37 return err 38 } 39 this.fp = fp 40 } 41 42 for { 43 b, err := this.tryLock() 44 if err != nil { 45 _ = this.fp.Close() 46 return err 47 } 48 if b { 49 return nil 50 } 51 time.Sleep(100 * time.Millisecond) 52 } 53 } 54 55 func (this *Locker) Release() error { 56 err := this.fp.Close() 57 if err != nil { 58 return err 59 } 60 this.fp = nil 61 return nil 62 } 63 64 func (this *Locker) tryLock() (ok bool, err error) { 65 err = syscall.Flock(int(this.fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) 66 if err == nil { 67 return true, nil 68 } 69 70 errno, isErrNo := err.(syscall.Errno) 71 if !isErrNo { 72 return 73 } 74 75 if !errno.Temporary() { 76 return 77 } 78 79 err = nil // 不提示错误 80 81 return 82 }