github.com/GuanceCloud/cliutils@v1.1.21/diskcache/lock.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package diskcache 7 8 import ( 9 "fmt" 10 "os" 11 "path/filepath" 12 "runtime" 13 "strconv" 14 "sync" 15 "syscall" 16 ) 17 18 type flock struct { 19 file string 20 mtx *sync.Mutex 21 } 22 23 func newFlock(path string) *flock { 24 return &flock{ 25 file: filepath.Clean(filepath.Join(path, ".lock")), 26 mtx: &sync.Mutex{}, 27 } 28 } 29 30 func (l *flock) lock() error { 31 l.mtx.Lock() 32 defer l.mtx.Unlock() 33 34 curPid := os.Getpid() 35 36 if _, err := os.Stat(l.file); err != nil { 37 goto write // file not exist 38 } else { 39 x, err := os.ReadFile(l.file) 40 if err != nil { 41 return err 42 } 43 44 if len(x) == 0 { 45 goto write 46 } 47 48 pidInFile, err := strconv.Atoi(string(x)) 49 if err != nil { 50 return err 51 } else { 52 switch pidInFile { 53 case -1: // unlocked 54 goto write 55 case curPid: 56 return fmt.Errorf("lock failed(locked by pid %d)", curPid) 57 default: // other pid, may terminated 58 if pidAlive(pidInFile) { 59 return fmt.Errorf("lock failed(locked by alive %d)", pidInFile) 60 } 61 } 62 } 63 } 64 65 write: 66 return os.WriteFile(l.file, []byte(fmt.Sprintf("%d", curPid)), 0o600) 67 } 68 69 func (l *flock) unlock() error { 70 l.mtx.Lock() 71 defer l.mtx.Unlock() 72 73 return os.WriteFile(l.file, []byte(fmt.Sprintf("%d", -1)), 0o600) 74 } 75 76 func pidAlive(pid int) bool { 77 p, err := os.FindProcess(pid) 78 if err != nil { 79 return false 80 } 81 82 // Signal not available on windows. 83 if runtime.GOOS == "windows" { 84 return true 85 } 86 87 if err := p.Signal(syscall.Signal(0)); err != nil { 88 switch err.Error() { 89 case "operation not permitted": 90 return true 91 default: 92 return false 93 } 94 } else { 95 return true 96 } 97 }