1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-27 20:12:58 +01:00

Fix memory ordering of WorkerAvailability (#340)

This commit is contained in:
fakeshadow 2021-04-16 03:20:08 -07:00 committed by GitHub
parent bd48908792
commit 19468feef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 12 deletions

View File

@ -128,7 +128,7 @@ impl Availability {
/// This would result in a re-check on all workers' availability. /// This would result in a re-check on all workers' availability.
fn set_available_all(&mut self, handles: &[WorkerHandleAccept]) { fn set_available_all(&mut self, handles: &[WorkerHandleAccept]) {
handles.iter().for_each(|handle| { handles.iter().for_each(|handle| {
self.set_available(handle.idx, true); self.set_available(handle.idx(), true);
}) })
} }
} }
@ -248,7 +248,7 @@ impl Accept {
drop(guard); drop(guard);
// maybe we want to recover from a backpressure. // maybe we want to recover from a backpressure.
self.maybe_backpressure(&mut sockets, false); self.maybe_backpressure(&mut sockets, false);
self.avail.set_available(handle.idx, true); self.avail.set_available(handle.idx(), true);
self.handles.push(handle); self.handles.push(handle);
} }
// got timer interest and it's time to try register socket(s) again // got timer interest and it's time to try register socket(s) again
@ -400,7 +400,7 @@ impl Accept {
} else { } else {
while self.avail.available() { while self.avail.available() {
let next = self.next(); let next = self.next();
let idx = next.idx; let idx = next.idx();
if next.available() { if next.available() {
self.avail.set_available(idx, true); self.avail.set_available(idx, true);
match self.send_connection(sockets, conn) { match self.send_connection(sockets, conn) {
@ -503,7 +503,7 @@ impl Accept {
/// Remove next worker handle that fail to accept connection. /// Remove next worker handle that fail to accept connection.
fn remove_next(&mut self) { fn remove_next(&mut self) {
let handle = self.handles.swap_remove(self.next); let handle = self.handles.swap_remove(self.next);
let idx = handle.idx; let idx = handle.idx();
// A message is sent to `ServerBuilder` future to notify it a new worker // A message is sent to `ServerBuilder` future to notify it a new worker
// should be made. // should be made.
self.srv.worker_faulted(idx); self.srv.worker_faulted(idx);

View File

@ -47,11 +47,7 @@ fn handle_pair(
tx2: UnboundedSender<Stop>, tx2: UnboundedSender<Stop>,
avail: WorkerAvailability, avail: WorkerAvailability,
) -> (WorkerHandleAccept, WorkerHandleServer) { ) -> (WorkerHandleAccept, WorkerHandleServer) {
let accept = WorkerHandleAccept { let accept = WorkerHandleAccept { tx: tx1, avail };
idx,
tx: tx1,
avail,
};
let server = WorkerHandleServer { idx, tx: tx2 }; let server = WorkerHandleServer { idx, tx: tx2 };
@ -63,16 +59,22 @@ fn handle_pair(
/// ///
/// Held by [Accept](crate::accept::Accept). /// Held by [Accept](crate::accept::Accept).
pub(crate) struct WorkerHandleAccept { pub(crate) struct WorkerHandleAccept {
pub idx: usize,
tx: UnboundedSender<Conn>, tx: UnboundedSender<Conn>,
avail: WorkerAvailability, avail: WorkerAvailability,
} }
impl WorkerHandleAccept { impl WorkerHandleAccept {
#[inline(always)]
pub(crate) fn idx(&self) -> usize {
self.avail.idx
}
#[inline(always)]
pub(crate) fn send(&self, msg: Conn) -> Result<(), Conn> { pub(crate) fn send(&self, msg: Conn) -> Result<(), Conn> {
self.tx.send(msg).map_err(|msg| msg.0) self.tx.send(msg).map_err(|msg| msg.0)
} }
#[inline(always)]
pub(crate) fn available(&self) -> bool { pub(crate) fn available(&self) -> bool {
self.avail.available() self.avail.available()
} }
@ -110,13 +112,18 @@ impl WorkerAvailability {
} }
} }
#[inline(always)]
pub fn available(&self) -> bool { pub fn available(&self) -> bool {
self.available.load(Ordering::Acquire) self.available.load(Ordering::Acquire)
} }
pub fn set(&self, val: bool) { pub fn set(&self, val: bool) {
let old = self.available.swap(val, Ordering::Release); // Ordering:
// notify the accept on switched to available. //
// There could be multiple set calls happen in one <ServerWorker as Future>::poll.
// Order is important between them.
let old = self.available.swap(val, Ordering::AcqRel);
// Notify the accept on switched to available.
if !old && val { if !old && val {
self.waker.wake(WakerInterest::WorkerAvailable(self.idx)); self.waker.wake(WakerInterest::WorkerAvailable(self.idx));
} }
@ -374,6 +381,10 @@ impl Default for WorkerState {
impl Drop for ServerWorker { impl Drop for ServerWorker {
fn drop(&mut self) { fn drop(&mut self) {
// Set availability to true so if accept try to send connection to this worker
// it would find worker is gone and remove it.
// This is helpful when worker is dropped unexpected.
self.availability.set(true);
// Stop the Arbiter ServerWorker runs on on drop. // Stop the Arbiter ServerWorker runs on on drop.
Arbiter::current().stop(); Arbiter::current().stop();
} }