github.com/hy3/cuto@v0.9.8-0.20160830082821-aa6652f877b7/util/lock_unix.go (about) 1 // Copyright 2015 unirita Inc. 2 // Created 2015/06/03 shanxia 3 4 // +build darwin linux 5 6 package util 7 8 import ( 9 "errors" 10 "fmt" 11 "os" 12 "path/filepath" 13 "syscall" 14 "time" 15 ) 16 17 type LockHandle struct { 18 fd int //lockファイルディスクリプタ 19 isLock bool // ロックフラグ 20 } 21 22 var ( 23 ErrBusy = errors.New("Locked by other process.") 24 25 lockFilePath = os.TempDir() 26 ) 27 28 // ファイルを利用した同期処理機能の初期化関数。 29 // ファイル作成が可能なファイル名を指定します。 30 func InitLock(name string) (*LockHandle, error) { 31 if len(name) > 0 { 32 fullname := filepath.Join(lockFilePath, name) 33 // open処理移動 34 var fd int 35 var err error 36 if _, err = os.Stat(fullname); err != nil { 37 fd, err = syscall.Open(fullname, syscall.O_CREAT|syscall.O_RDONLY|syscall.O_CLOEXEC, 0644) 38 } else { 39 fd, err = syscall.Open(fullname, syscall.O_RDONLY|syscall.O_CLOEXEC, 0644) 40 } 41 if err != nil { 42 return nil, err 43 } 44 return &LockHandle{fd, false}, nil 45 } else { 46 return &LockHandle{0, false}, errors.New("Invalid lockfile name.") 47 } 48 } 49 50 // ファイルを利用して、ロックを行います。 51 // 引数で指定したミリ秒まで待機します。0以下を指定した場合は、リトライしません。 52 // 他プロセスのロックが指定時間内に解けなかった場合は、ErrBusy を返します。 53 func (l *LockHandle) Lock(timeout_millisec int) error { 54 if l.fd == 0 { 55 return errors.New("Not initialize.") 56 } 57 err := l.tryLock() 58 59 if err == nil { 60 return nil 61 62 } else { // Locked by other process. 63 if timeout_millisec > 0 { 64 st := time.Now() 65 for { 66 time.Sleep(1 * time.Millisecond) 67 err = l.tryLock() 68 if err == nil { 69 return nil // ロック成功 70 } 71 if time.Since(st).Nanoseconds() > (int64(timeout_millisec) * 1000000) { 72 fmt.Fprintf(os.Stderr, "Lock Timeout %v\n", err) 73 break 74 } 75 } 76 } 77 } 78 return ErrBusy 79 } 80 81 // ロック解除。 82 func (l *LockHandle) Unlock() error { 83 if !l.isLock { 84 return errors.New("It has not been locked yet.") 85 } 86 if err := syscall.Flock(l.fd, syscall.LOCK_UN); err != nil { 87 return err 88 } 89 l.isLock = false 90 return nil 91 } 92 93 // ロックファイルの終了処理。InitLock()成功後は、必ず呼び出して下さい。 94 func (l *LockHandle) TermLock() error { 95 if l.fd != 0 { 96 if l.isLock { 97 l.Unlock() 98 } 99 syscall.Close(l.fd) 100 l.fd = 0 101 } 102 return nil 103 } 104 105 // 実際にロック処理を行う。 106 func (l *LockHandle) tryLock() error { 107 if err := syscall.Flock(l.fd, syscall.LOCK_EX); err != nil { 108 return err 109 } 110 l.isLock = true 111 return nil 112 }