diff --git a/cmd/syncthing/usage_report.go b/cmd/syncthing/usage_report.go index f1550331..62334571 100644 --- a/cmd/syncthing/usage_report.go +++ b/cmd/syncthing/usage_report.go @@ -17,6 +17,7 @@ import ( "runtime" "sort" "strings" + "sync" "time" "github.com/syncthing/syncthing/lib/config" @@ -326,6 +327,8 @@ type usageReportingService struct { connectionsService *connections.Service forceRun chan struct{} stop chan struct{} + stopped chan struct{} + stopMut sync.RWMutex } func newUsageReportingService(cfg *config.Wrapper, model *model.Model, connectionsService *connections.Service) *usageReportingService { @@ -335,7 +338,9 @@ func newUsageReportingService(cfg *config.Wrapper, model *model.Model, connectio connectionsService: connectionsService, forceRun: make(chan struct{}), stop: make(chan struct{}), + stopped: make(chan struct{}), } + close(svc.stopped) // Not yet running, dont block on Stop() cfg.Subscribe(svc) return svc } @@ -359,8 +364,16 @@ func (s *usageReportingService) sendUsageReport() error { } func (s *usageReportingService) Serve() { + s.stopMut.Lock() s.stop = make(chan struct{}) + s.stopped = make(chan struct{}) + s.stopMut.Unlock() t := time.NewTimer(time.Duration(s.cfg.Options().URInitialDelayS) * time.Second) + s.stopMut.RLock() + defer func() { + close(s.stopped) + s.stopMut.RUnlock() + }() for { select { case <-s.stop: @@ -387,14 +400,21 @@ func (s *usageReportingService) VerifyConfiguration(from, to config.Configuratio func (s *usageReportingService) CommitConfiguration(from, to config.Configuration) bool { if from.Options.URAccepted != to.Options.URAccepted || from.Options.URUniqueID != to.Options.URUniqueID || from.Options.URURL != to.Options.URURL { - s.forceRun <- struct{}{} + s.stopMut.RLock() + select { + case s.forceRun <- struct{}{}: + case <-s.stop: + } + s.stopMut.RUnlock() } return true } func (s *usageReportingService) Stop() { + s.stopMut.RLock() close(s.stop) - close(s.forceRun) + <-s.stopped + s.stopMut.RUnlock() } func (usageReportingService) String() string { diff --git a/lib/relay/client/static.go b/lib/relay/client/static.go index 07ca2655..67e5ef18 100644 --- a/lib/relay/client/static.go +++ b/lib/relay/client/static.go @@ -28,6 +28,7 @@ type staticClient struct { stop chan struct{} stopped chan struct{} + stopMut sync.RWMutex conn *tls.Conn @@ -44,6 +45,8 @@ func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan pro invitations = make(chan protocol.SessionInvitation) } + stopped := make(chan struct{}) + close(stopped) // not yet started, don't block on Stop() return &staticClient{ uri: uri, invitations: invitations, @@ -56,7 +59,8 @@ func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan pro connectTimeout: timeout, stop: make(chan struct{}), - stopped: make(chan struct{}), + stopped: stopped, + stopMut: sync.NewRWMutex(), mut: sync.NewRWMutex(), } @@ -64,8 +68,10 @@ func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan pro func (c *staticClient) Serve() { defer c.cleanup() + c.stopMut.Lock() c.stop = make(chan struct{}) c.stopped = make(chan struct{}) + c.stopMut.Unlock() defer close(c.stopped) if err := c.connect(); err != nil { @@ -104,6 +110,8 @@ func (c *staticClient) Serve() { timeout := time.NewTimer(c.messageTimeout) + c.stopMut.RLock() + defer c.stopMut.RUnlock() for { select { case message := <-messages: @@ -169,12 +177,10 @@ func (c *staticClient) Serve() { } func (c *staticClient) Stop() { - if c.stop == nil { - return - } - + c.stopMut.RLock() close(c.stop) <-c.stopped + c.stopMut.RUnlock() } func (c *staticClient) StatusOK() bool {