Skip to content

Commit 16c7857

Browse files
committed
Fix potential deadlock in event draining
1 parent 7045131 commit 16c7857

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

crates/amalthea/src/socket/shell.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,12 +471,25 @@ impl Shell {
471471

472472
let ready = sel.ready();
473473

474+
// Always drain pending comm events, regardless of which
475+
// channel was ready.
474476
while let Ok(event) = self.comm_event_rx.try_recv() {
475477
self.process_comm_event(event);
476478
}
477479

480+
// `Select::ready()` can return spuriously, so we must use
481+
// `try_recv()` instead of `recv()` to avoid blocking when
482+
// the channel isn't actually ready. Blocking here would
483+
// prevent us from draining comm events, causing a deadlock
484+
// when the R thread sends a barrier via `comm_open_backend`.
478485
if ready == rx_idx {
479-
return rx.recv().unwrap();
486+
match rx.try_recv() {
487+
Ok(value) => return value,
488+
Err(crossbeam::channel::TryRecvError::Empty) => continue,
489+
Err(crossbeam::channel::TryRecvError::Disconnected) => {
490+
panic!("Completion channel disconnected in drain_comm_events_until");
491+
},
492+
}
480493
}
481494
}
482495
}

0 commit comments

Comments
 (0)