Skip to content

Commit 753bef8

Browse files
committedSep 21, 2021
Fix gRPC BoardListWatch crashing when installing/uninstalling a core/lib
1 parent 1a3250b commit 753bef8

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed
 

‎arduino/discovery/discovery.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,19 @@ func (disc *PluggableDiscovery) jsonDecodeLoop(in io.Reader, outChan chan<- *dis
168168
disc.incomingMessagesError = err
169169
disc.statusMutex.Unlock()
170170
close(outChan)
171-
logrus.Errorf("stopped discovery %s decode loop", disc.id)
172-
// TODO: Try restarting process some times before closing it completely
171+
logrus.Errorf("stopped discovery %s decode loop: %v", disc.id, err)
173172
}
174173

175174
for {
176175
var msg discoveryMessage
177-
if err := decoder.Decode(&msg); err != nil {
176+
if err := decoder.Decode(&msg); err == io.EOF {
177+
// This is fine, we exit gracefully
178+
disc.statusMutex.Lock()
179+
disc.state = Dead
180+
disc.statusMutex.Unlock()
181+
close(outChan)
182+
return
183+
} else if err != nil {
178184
closeAndReportError(err)
179185
return
180186
}
@@ -218,9 +224,6 @@ func (disc *PluggableDiscovery) waitMessage(timeout time.Duration) (*discoveryMe
218224
select {
219225
case msg := <-disc.incomingMessagesChan:
220226
if msg == nil {
221-
// channel has been closed
222-
disc.statusMutex.Lock()
223-
defer disc.statusMutex.Unlock()
224227
return nil, disc.incomingMessagesError
225228
}
226229
return msg, nil

‎arduino/discovery/discoverymanager/discoverymanager.go

+3
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ func (dm *DiscoveryManager) QuitAll() []error {
192192
// Close the global channel only if there were no errors
193193
// quitting all alive discoveries
194194
if len(errs) == 0 && dm.globalEventCh != nil {
195+
// Let events consumers that discoveries are quitting no more events
196+
// will be sent on this channel
197+
dm.globalEventCh <- &discovery.Event{Type: "quit"}
195198
close(dm.globalEventCh)
196199
dm.globalEventCh = nil
197200
}

‎commands/board/list.go

+22-3
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,25 @@ func Watch(instanceID int32, interrupt <-chan bool) (<-chan *rpc.BoardListWatchR
258258
for {
259259
select {
260260
case event := <-eventsChan:
261+
if event.Type == "quit" {
262+
// The discovery manager has closed its event channel because it's
263+
// quitting all the discovery processes that are running, this
264+
// means that the events channel we're listening from won't receive any
265+
// more events.
266+
// Handling this case is necessary when the board watcher is running and
267+
// the instance being used is reinitialized since that quits all the
268+
// discovery processes and reset the discovery manager. That would leave
269+
// this goroutine listening forever on a "dead" channel and might even
270+
// cause panics.
271+
// This message avoid all this issues.
272+
// It will be the client's task restarting the board watcher if necessary,
273+
// this host won't attempt restarting it.
274+
outChan <- &rpc.BoardListWatchResponse{
275+
EventType: event.Type,
276+
}
277+
return
278+
}
279+
261280
port := &rpc.DetectedPort{
262281
Port: event.Port.ToRPC(),
263282
}
@@ -276,11 +295,11 @@ func Watch(instanceID int32, interrupt <-chan bool) (<-chan *rpc.BoardListWatchR
276295
Error: boardsError,
277296
}
278297
case <-interrupt:
279-
err := pm.DiscoveryManager().StopAll()
280-
if err != nil {
298+
errs := dm.StopAll()
299+
if len(errs) > 0 {
281300
outChan <- &rpc.BoardListWatchResponse{
282301
EventType: "error",
283-
Error: tr("stopping discoveries: %s", err),
302+
Error: tr("stopping discoveries: %s", errs),
284303
}
285304
// Don't close the channel if quitting all discoveries
286305
// failed, otherwise some processes might be left running.

‎commands/daemon/daemon.go

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import (
3131
"github.com/arduino/arduino-cli/i18n"
3232
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
3333
"github.com/sirupsen/logrus"
34+
"google.golang.org/grpc/codes"
35+
"google.golang.org/grpc/status"
3436
)
3537

3638
// ArduinoCoreServerImpl FIXMEDOC
@@ -109,6 +111,9 @@ func (s *ArduinoCoreServerImpl) BoardListWatch(stream rpc.ArduinoCoreService_Boa
109111
logrus.Info("boards watcher stream closed")
110112
interrupt <- true
111113
return
114+
} else if st, ok := status.FromError(err); ok && st.Code() == codes.Canceled {
115+
logrus.Info("boards watcher interrupted by host")
116+
return
112117
} else if err != nil {
113118
logrus.Infof("interrupting boards watcher: %v", err)
114119
interrupt <- true

0 commit comments

Comments
 (0)
Please sign in to comment.