github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/go/internal/lockedfile/mutex.go (about) 1 // Copyright 2018 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 lockedfile 6 7 import ( 8 "fmt" 9 "os" 10 ) 11 12 // A Mutex provides mutual exclusion within and across processes by locking a 13 // well-known file. Such a file generally guards some other part of the 14 // filesystem: for example, a Mutex file in a directory might guard access to 15 // the entire tree rooted in that directory. 16 // 17 // Mutex does not implement sync.Locker: unlike a sync.Mutex, a lockedfile.Mutex 18 // can fail to lock (e.g. if there is a permission error in the filesystem). 19 // 20 // Like a sync.Mutex, a Mutex may be included as a field of a larger struct but 21 // must not be copied after first use. The Path field must be set before first 22 // use and must not be change thereafter. 23 type Mutex struct { 24 Path string // The path to the well-known lock file. Must be non-empty. 25 } 26 27 // MutexAt returns a new Mutex with Path set to the given non-empty path. 28 func MutexAt(path string) *Mutex { 29 if path == "" { 30 panic("lockedfile.MutexAt: path must be non-empty") 31 } 32 return &Mutex{Path: path} 33 } 34 35 func (mu *Mutex) String() string { 36 return fmt.Sprintf("lockedfile.Mutex(%s)", mu.Path) 37 } 38 39 // Lock attempts to lock the Mutex. 40 // 41 // If successful, Lock returns a non-nil unlock function: it is provided as a 42 // return-value instead of a separate method to remind the caller to check the 43 // accompanying error. (See https://golang.org/issue/20803.) 44 func (mu *Mutex) Lock() (unlock func(), err error) { 45 if mu.Path == "" { 46 panic("lockedfile.Mutex: missing Path during Lock") 47 } 48 49 // We could use either O_RDWR or O_WRONLY here. If we choose O_RDWR and the 50 // file at mu.Path is write-only, the call to OpenFile will fail with a 51 // permission error. That's actually what we want: if we add an RLock method 52 // in the future, it should call OpenFile with O_RDONLY and will require the 53 // files must be readable, so we should not let the caller make any 54 // assumptions about Mutex working with write-only files. 55 f, err := OpenFile(mu.Path, os.O_RDWR|os.O_CREATE, 0666) 56 if err != nil { 57 return nil, err 58 } 59 return func() { f.Close() }, nil 60 }