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  }