2017-02-04 02:00:33 +08:00
|
|
|
package sftp
|
|
|
|
|
2017-02-05 01:32:44 +08:00
|
|
|
import "sync"
|
2017-02-04 02:00:33 +08:00
|
|
|
|
|
|
|
// stringLock locks for string IDs passed in
|
|
|
|
type stringLock struct {
|
|
|
|
mu sync.Mutex // mutex to protect below
|
|
|
|
locks map[string]chan struct{} // map of locks
|
|
|
|
}
|
|
|
|
|
|
|
|
// newStringLock creates a stringLock
|
|
|
|
func newStringLock() *stringLock {
|
|
|
|
return &stringLock{
|
|
|
|
locks: make(map[string]chan struct{}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock locks on the id passed in
|
|
|
|
func (l *stringLock) Lock(ID string) {
|
|
|
|
l.mu.Lock()
|
|
|
|
for {
|
|
|
|
ch, ok := l.locks[ID]
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// Wait for the channel to be closed
|
|
|
|
l.mu.Unlock()
|
2017-02-05 01:32:44 +08:00
|
|
|
// fs.Logf(nil, "Waiting for stringLock on %q", ID)
|
2017-02-04 02:00:33 +08:00
|
|
|
<-ch
|
|
|
|
l.mu.Lock()
|
|
|
|
}
|
|
|
|
l.locks[ID] = make(chan struct{})
|
|
|
|
l.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock unlocks on the id passed in. Will panic if Lock with the
|
|
|
|
// given id wasn't called first.
|
|
|
|
func (l *stringLock) Unlock(ID string) {
|
|
|
|
l.mu.Lock()
|
|
|
|
ch, ok := l.locks[ID]
|
|
|
|
if !ok {
|
|
|
|
panic("stringLock: Unlock before Lock")
|
|
|
|
}
|
|
|
|
close(ch)
|
|
|
|
delete(l.locks, ID)
|
|
|
|
l.mu.Unlock()
|
|
|
|
}
|