Commit a25c5a91 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Refactor ShutdownSocketSet atomic state machine

Summary:
[Folly] Refactor `ShutdownSocketSet` atomic state machine.

* Format.
* Use `while` over `goto`.
* Avoid `memory_order_acq_rel` as the single-argument memory order; some platforms fail to build that.
* Use `memory_order_relaxed` for all atomic operations because stronger memory orders are not actually required: the atomic state never serves as a barrier for synchronizing loads and stores of associated data because there is no associated data.

Reviewed By: davidtgoldblatt

Differential Revision: D6058292

fbshipit-source-id: d45d7fcfa472e6e393a5f980e75ad9ea3358bab3
parent 9917cdab
...@@ -51,10 +51,9 @@ void ShutdownSocketSet::add(int fd) { ...@@ -51,10 +51,9 @@ void ShutdownSocketSet::add(int fd) {
auto& sref = data_[size_t(fd)]; auto& sref = data_[size_t(fd)];
uint8_t prevState = FREE; uint8_t prevState = FREE;
CHECK(sref.compare_exchange_strong(prevState, CHECK(sref.compare_exchange_strong(
IN_USE, prevState, IN_USE, std::memory_order_relaxed))
std::memory_order_acq_rel)) << "Invalid prev state for fd " << fd << ": " << int(prevState);
<< "Invalid prev state for fd " << fd << ": " << int(prevState);
} }
void ShutdownSocketSet::remove(int fd) { void ShutdownSocketSet::remove(int fd) {
...@@ -66,23 +65,19 @@ void ShutdownSocketSet::remove(int fd) { ...@@ -66,23 +65,19 @@ void ShutdownSocketSet::remove(int fd) {
auto& sref = data_[size_t(fd)]; auto& sref = data_[size_t(fd)];
uint8_t prevState = 0; uint8_t prevState = 0;
retry_load:
prevState = sref.load(std::memory_order_relaxed); prevState = sref.load(std::memory_order_relaxed);
do {
retry: switch (prevState) {
switch (prevState) { case IN_SHUTDOWN:
case IN_SHUTDOWN: std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); prevState = sref.load(std::memory_order_relaxed);
goto retry_load; continue;
case FREE: case FREE:
LOG(FATAL) << "Invalid prev state for fd " << fd << ": " << int(prevState); LOG(FATAL) << "Invalid prev state for fd " << fd << ": "
} << int(prevState);
}
if (!sref.compare_exchange_weak(prevState, } while (
FREE, !sref.compare_exchange_weak(prevState, FREE, std::memory_order_relaxed));
std::memory_order_acq_rel)) {
goto retry;
}
} }
int ShutdownSocketSet::close(int fd) { int ShutdownSocketSet::close(int fd) {
...@@ -95,24 +90,21 @@ int ShutdownSocketSet::close(int fd) { ...@@ -95,24 +90,21 @@ int ShutdownSocketSet::close(int fd) {
uint8_t prevState = sref.load(std::memory_order_relaxed); uint8_t prevState = sref.load(std::memory_order_relaxed);
uint8_t newState = 0; uint8_t newState = 0;
retry: do {
switch (prevState) { switch (prevState) {
case IN_USE: case IN_USE:
case SHUT_DOWN: case SHUT_DOWN:
newState = FREE; newState = FREE;
break; break;
case IN_SHUTDOWN: case IN_SHUTDOWN:
newState = MUST_CLOSE; newState = MUST_CLOSE;
break; break;
default: default:
LOG(FATAL) << "Invalid prev state for fd " << fd << ": " << int(prevState); LOG(FATAL) << "Invalid prev state for fd " << fd << ": "
} << int(prevState);
}
if (!sref.compare_exchange_weak(prevState, } while (!sref.compare_exchange_weak(
newState, prevState, newState, std::memory_order_relaxed));
std::memory_order_acq_rel)) {
goto retry;
}
return newState == FREE ? folly::closeNoInt(fd) : 0; return newState == FREE ? folly::closeNoInt(fd) : 0;
} }
...@@ -126,18 +118,16 @@ void ShutdownSocketSet::shutdown(int fd, bool abortive) { ...@@ -126,18 +118,16 @@ void ShutdownSocketSet::shutdown(int fd, bool abortive) {
auto& sref = data_[size_t(fd)]; auto& sref = data_[size_t(fd)];
uint8_t prevState = IN_USE; uint8_t prevState = IN_USE;
if (!sref.compare_exchange_strong(prevState, if (!sref.compare_exchange_strong(
IN_SHUTDOWN, prevState, IN_SHUTDOWN, std::memory_order_relaxed)) {
std::memory_order_acq_rel)) {
return; return;
} }
doShutdown(fd, abortive); doShutdown(fd, abortive);
prevState = IN_SHUTDOWN; prevState = IN_SHUTDOWN;
if (sref.compare_exchange_strong(prevState, if (sref.compare_exchange_strong(
SHUT_DOWN, prevState, SHUT_DOWN, std::memory_order_relaxed)) {
std::memory_order_acq_rel)) {
return; return;
} }
...@@ -146,16 +136,15 @@ void ShutdownSocketSet::shutdown(int fd, bool abortive) { ...@@ -146,16 +136,15 @@ void ShutdownSocketSet::shutdown(int fd, bool abortive) {
folly::closeNoInt(fd); // ignore errors, nothing to do folly::closeNoInt(fd); // ignore errors, nothing to do
CHECK(sref.compare_exchange_strong(prevState, CHECK(
FREE, sref.compare_exchange_strong(prevState, FREE, std::memory_order_relaxed))
std::memory_order_acq_rel)) << "Invalid prev state for fd " << fd << ": " << int(prevState);
<< "Invalid prev state for fd " << fd << ": " << int(prevState);
} }
void ShutdownSocketSet::shutdownAll(bool abortive) { void ShutdownSocketSet::shutdownAll(bool abortive) {
for (int i = 0; i < maxFd_; ++i) { for (int i = 0; i < maxFd_; ++i) {
auto& sref = data_[size_t(i)]; auto& sref = data_[size_t(i)];
if (sref.load(std::memory_order_acquire) == IN_USE) { if (sref.load(std::memory_order_relaxed) == IN_USE) {
shutdown(i, abortive); shutdown(i, abortive);
} }
} }
......
...@@ -117,12 +117,20 @@ class ShutdownSocketSet : private boost::noncopyable { ...@@ -117,12 +117,20 @@ class ShutdownSocketSet : private boost::noncopyable {
// (::shutdown()) // (::shutdown())
// IN_SHUTDOWN -> SHUT_DOWN // IN_SHUTDOWN -> SHUT_DOWN
// MUST_CLOSE -> (::close()) -> FREE // MUST_CLOSE -> (::close()) -> FREE
//
// State atomic operation memory orders:
// All atomic operations on per-socket states use std::memory_order_relaxed
// because there is no associated per-socket data guarded by the state and
// the states for different sockets are unrelated. If there were associated
// per-socket data, acquire and release orders would be desired; and if the
// states for different sockets were related, it could be that sequential
// consistent orders would be desired.
enum State : uint8_t { enum State : uint8_t {
FREE = 0, FREE = 0,
IN_USE, IN_USE,
IN_SHUTDOWN, IN_SHUTDOWN,
SHUT_DOWN, SHUT_DOWN,
MUST_CLOSE MUST_CLOSE,
}; };
struct Free { struct Free {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment