From b91ff430dbcbea2b198acf2b4e152687d1290394 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Sun, 24 Jun 2018 17:55:28 +0200 Subject: [PATCH 1/2] lib/model: Release both locks when waiting for services to stop (fixes #5028) --- lib/model/model.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/model/model.go b/lib/model/model.go index 302f06c5b..fba9c2f8b 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -344,11 +344,13 @@ func (m *Model) tearDownFolderLocked(cfg config.FolderConfiguration) { // Stop the services running for this folder and wait for them to finish // stopping to prevent races on restart. tokens := m.folderRunnerTokens[cfg.ID] + m.pmut.Unlock() m.fmut.Unlock() for _, id := range tokens { m.RemoveAndWait(id, 0) } m.fmut.Lock() + m.pmut.Lock() // Close connections to affected devices for _, dev := range cfg.Devices { From 21035b0c1a230bb097fb615c7ad16c9d9489930c Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 29 Jun 2018 08:54:57 +0200 Subject: [PATCH 2/2] vendor: Update github.com/thejerf/suture --- vendor/github.com/thejerf/suture/messages.go | 5 +++-- vendor/github.com/thejerf/suture/service.go | 22 +++++++++++++++++++ .../github.com/thejerf/suture/supervisor.go | 20 +++++++++++++---- vendor/manifest | 2 +- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/vendor/github.com/thejerf/suture/messages.go b/vendor/github.com/thejerf/suture/messages.go index b4f8599b0..cb129d29e 100644 --- a/vendor/github.com/thejerf/suture/messages.go +++ b/vendor/github.com/thejerf/suture/messages.go @@ -41,12 +41,13 @@ type serviceFailed struct { func (sf serviceFailed) isSupervisorMessage() {} -func (s *Supervisor) serviceEnded(id serviceID) { - s.sendControl(serviceEnded{id}) +func (s *Supervisor) serviceEnded(id serviceID, complete bool) { + s.sendControl(serviceEnded{id, complete}) } type serviceEnded struct { id serviceID + complete bool } func (s serviceEnded) isSupervisorMessage() {} diff --git a/vendor/github.com/thejerf/suture/service.go b/vendor/github.com/thejerf/suture/service.go index 9d6fedc38..bfb8b3cf3 100644 --- a/vendor/github.com/thejerf/suture/service.go +++ b/vendor/github.com/thejerf/suture/service.go @@ -58,8 +58,30 @@ If you implement the fmt.Stringer interface, that will be used. If you do not implement the fmt.Stringer interface, a default fmt.Sprintf("%#v") will be used. +Optional Interface + +Services may optionally implement IsCompletable, which allows a service +to indicate to a supervisor that it does not need to be restarted if +it has terminated. + */ type Service interface { Serve() Stop() } + +/* + +IsCompletable is an optionally-implementable interface that allows a service +to report to a supervisor that it does not need to be restarted because it +has terminated normally. When a Service is going to be restarted, the +supervisor will check for this method, and if Complete returns true, the +service is removed from the supervisor instead of restarted. + +This is only executed when the service is not running because it has +terminated, and has not yet been restarted. + +*/ +type IsCompletable interface { + Complete() bool +} diff --git a/vendor/github.com/thejerf/suture/supervisor.go b/vendor/github.com/thejerf/suture/supervisor.go index 8c3efa39c..07aef042e 100644 --- a/vendor/github.com/thejerf/suture/supervisor.go +++ b/vendor/github.com/thejerf/suture/supervisor.go @@ -403,7 +403,14 @@ func (s *Supervisor) Serve() { case serviceEnded: service, monitored := s.services[msg.id] if monitored { - s.handleFailedService(msg.id, fmt.Sprintf("%s returned unexpectedly", service), []byte("[unknown stack trace]")) + if msg.complete { + delete(s.services, msg.id) + go func() { + service.Service.Stop() + }() + } else { + s.handleFailedService(msg.id, fmt.Sprintf("%s returned unexpectedly", service), []byte("[unknown stack trace]")) + } } case addService: id := s.serviceCounter @@ -524,7 +531,12 @@ func (s *Supervisor) runService(service Service, id serviceID) { service.Serve() - s.serviceEnded(id) + complete := false + if completable, ok := service.(IsCompletable); ok && completable.Complete() { + complete = true + } + + s.serviceEnded(id, complete) }() } @@ -534,10 +546,10 @@ func (s *Supervisor) removeService(id serviceID, notificationChan chan struct{}, delete(s.services, id) s.servicesShuttingDown[id] = namedService go func() { - successChan := make(chan bool) + successChan := make(chan struct{}) go func() { namedService.Service.Stop() - successChan <- true + close(successChan) if notificationChan != nil { notificationChan <- struct{}{} } diff --git a/vendor/manifest b/vendor/manifest index 7e44df8b9..195778333 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -476,7 +476,7 @@ "importpath": "github.com/thejerf/suture", "repository": "https://github.com/thejerf/suture", "vcs": "git", - "revision": "87e298c9891673c9ae76e10c2c9be589127e5f49", + "revision": "3f1fb62fe0a3cc6429122d7dc45588a8b59c5bb6", "branch": "master", "notests": true },