blob: 4433d27e1c7d821452ffb053feacc385b5bb46b9 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package server
import (
"sync"
)
// watchers provides syncronization and notifications for a shared resource.
type watchers struct {
mu sync.RWMutex
nextId int
clients map[int][]chan struct{}
}
func (p *watchers) lock() {
p.mu.Lock()
}
func (p *watchers) unlock(id int) {
for i, c := range p.clients {
if i != id {
for _, ch := range c {
// Non-blocking send. If the channel is full we don't need
// to send a duplicate flush.
select {
case ch <- struct{}{}:
default:
}
}
}
}
p.mu.Unlock()
}
func (p *watchers) rlock() {
p.mu.RLock()
}
func (p *watchers) runlock() {
p.mu.RUnlock()
}
func (p *watchers) newID() int {
p.mu.Lock()
id := p.nextId
p.nextId += 1
p.mu.Unlock()
return id
}
func (p *watchers) register(id int) chan struct{} {
ch := make(chan struct{}, 1)
p.mu.Lock()
p.clients[id] = append(p.clients[id], ch)
p.mu.Unlock()
return ch
}
func (p *watchers) unregister(id int, ch chan struct{}) {
p.mu.Lock()
defer p.mu.Unlock()
clients := p.clients[id]
max := len(clients) - 1
for i, v := range clients {
if v == ch {
clients[i], clients[max], p.clients[id] = clients[max], nil, clients[:max]
close(ch)
return
}
}
}
func newWatchers() *watchers {
return &watchers{clients: make(map[int][]chan struct{})}
}