proxygen
folly::ShutdownSocketSet Class Reference

#include <ShutdownSocketSet.h>

Inheritance diagram for folly::ShutdownSocketSet:

Classes

struct  Free
 

Public Member Functions

 ShutdownSocketSet (int maxFd=1<< 18)
 
void add (int fd)
 
void remove (int fd)
 
int close (int fd)
 
void shutdown (int fd, bool abortive=false)
 
void shutdownAll (bool abortive=false)
 

Private Types

enum  State : uint8_t {
  FREE = 0, IN_USE, IN_SHUTDOWN, SHUT_DOWN,
  MUST_CLOSE
}
 

Private Member Functions

void doShutdown (int fd, bool abortive)
 

Private Attributes

const int maxFd_
 
std::unique_ptr< std::atomic< uint8_t >[], Freedata_
 
folly::File nullFile_
 

Detailed Description

Set of sockets that allows immediate, take-no-prisoners abort.

Definition at line 32 of file ShutdownSocketSet.h.

Member Enumeration Documentation

Constructor & Destructor Documentation

folly::ShutdownSocketSet::ShutdownSocketSet ( int  maxFd = 1 << 18)
explicit

Create a socket set that can handle file descriptors < maxFd. The default value (256Ki) is high enough for just about all applications, even if you increased the number of file descriptors on your system.

Definition at line 29 of file ShutdownSocketSet.cpp.

30  : maxFd_(maxFd),
31  data_(static_cast<std::atomic<uint8_t>*>(
32  folly::checkedCalloc(size_t(maxFd), sizeof(std::atomic<uint8_t>)))),
33  nullFile_("/dev/null", O_RDWR) {}
void * checkedCalloc(size_t n, size_t size)
Definition: Malloc.h:235
std::unique_ptr< std::atomic< uint8_t >[], Free > data_

Member Function Documentation

void folly::ShutdownSocketSet::add ( int  fd)

Add an already open socket to the list of sockets managed by ShutdownSocketSet. You MUST close the socket by calling ShutdownSocketSet::close (which will, as a side effect, also handle EINTR properly) and not by calling close() on the file descriptor.

Definition at line 35 of file ShutdownSocketSet.cpp.

References data_, FREE, IN_USE, maxFd_, and uint8_t.

Referenced by folly::AsyncSocket::connect(), folly::test::Server::Server(), and folly::AsyncServerSocket::setupSocket().

35  {
36  // Silently ignore any fds >= maxFd_, very unlikely
37  DCHECK_GE(fd, 0);
38  if (fd >= maxFd_) {
39  return;
40  }
41 
42  auto& sref = data_[size_t(fd)];
43  uint8_t prevState = FREE;
44  CHECK(sref.compare_exchange_strong(
45  prevState, IN_USE, std::memory_order_relaxed))
46  << "Invalid prev state for fd " << fd << ": " << int(prevState);
47 }
std::unique_ptr< std::atomic< uint8_t >[], Free > data_
int folly::ShutdownSocketSet::close ( int  fd)

Close a socket managed by ShutdownSocketSet. Returns the same return code as close() (and sets errno accordingly).

Definition at line 73 of file ShutdownSocketSet.cpp.

References folly::closeNoInt(), data_, folly::FATAL, FREE, IN_SHUTDOWN, IN_USE, maxFd_, MUST_CLOSE, SHUT_DOWN, and uint8_t.

Referenced by folly::AsyncServerSocket::bind(), folly::test::Server::closeClients(), folly::AsyncSocket::doClose(), folly::test::Server::Server(), and folly::AsyncServerSocket::stopAccepting().

73  {
74  DCHECK_GE(fd, 0);
75  if (fd >= maxFd_) {
76  return folly::closeNoInt(fd);
77  }
78 
79  auto& sref = data_[size_t(fd)];
80  uint8_t prevState = sref.load(std::memory_order_relaxed);
81  uint8_t newState = 0;
82 
83  do {
84  switch (prevState) {
85  case IN_USE:
86  case SHUT_DOWN:
87  newState = FREE;
88  break;
89  case IN_SHUTDOWN:
90  newState = MUST_CLOSE;
91  break;
92  default:
93  LOG(FATAL) << "Invalid prev state for fd " << fd << ": "
94  << int(prevState);
95  }
96  } while (!sref.compare_exchange_weak(
97  prevState, newState, std::memory_order_relaxed));
98 
99  return newState == FREE ? folly::closeNoInt(fd) : 0;
100 }
int closeNoInt(int fd)
Definition: FileUtil.cpp:56
std::unique_ptr< std::atomic< uint8_t >[], Free > data_
void folly::ShutdownSocketSet::doShutdown ( int  fd,
bool  abortive 
)
private

Definition at line 143 of file ShutdownSocketSet.cpp.

References folly::dup2NoInt(), folly::File::fd(), nullFile_, folly::netops::setsockopt(), and folly::shutdownNoInt().

Referenced by shutdown().

143  {
144  // shutdown() the socket first, to awaken any threads blocked on the fd
145  // (subsequent IO will fail because it's been shutdown); close()ing the
146  // socket does not wake up blockers, see
147  // http://stackoverflow.com/a/3624545/1736339
148  folly::shutdownNoInt(fd, SHUT_RDWR);
149 
150  // If abortive shutdown is desired, we'll set the SO_LINGER option on
151  // the socket with a timeout of 0; this will cause RST to be sent on
152  // close.
153  if (abortive) {
154  struct linger l = {1, 0};
155  if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) != 0) {
156  // Probably not a socket, ignore.
157  return;
158  }
159  }
160 
161  // We can't close() the socket, as that would be dangerous; a new file
162  // could be opened and get the same file descriptor, and then code assuming
163  // the old fd would do IO in the wrong place. We'll (atomically) dup2
164  // /dev/null onto the fd instead.
166 }
int shutdownNoInt(NetworkSocket fd, int how)
Definition: FileUtil.cpp:98
int setsockopt(NetworkSocket s, int level, int optname, const void *optval, socklen_t optlen)
Definition: NetOps.cpp:384
int fd() const
Definition: File.h:85
int dup2NoInt(int oldfd, int newfd)
Definition: FileUtil.cpp:72
void folly::ShutdownSocketSet::remove ( int  fd)

Remove a socket from the list of sockets managed by ShutdownSocketSet. Note that remove() might block! (which we lamely implement by sleep()-ing) in the extremely rare case that the fd is currently being shutdown().

Definition at line 49 of file ShutdownSocketSet.cpp.

References data_, folly::FATAL, FREE, IN_SHUTDOWN, maxFd_, and uint8_t.

Referenced by folly::AsyncSocket::setShutdownSocketSet(), and folly::AsyncServerSocket::setShutdownSocketSet().

49  {
50  DCHECK_GE(fd, 0);
51  if (fd >= maxFd_) {
52  return;
53  }
54 
55  auto& sref = data_[size_t(fd)];
56  uint8_t prevState = 0;
57 
58  prevState = sref.load(std::memory_order_relaxed);
59  do {
60  switch (prevState) {
61  case IN_SHUTDOWN:
62  std::this_thread::sleep_for(std::chrono::milliseconds(1));
63  prevState = sref.load(std::memory_order_relaxed);
64  continue;
65  case FREE:
66  LOG(FATAL) << "Invalid prev state for fd " << fd << ": "
67  << int(prevState);
68  }
69  } while (
70  !sref.compare_exchange_weak(prevState, FREE, std::memory_order_relaxed));
71 }
std::unique_ptr< std::atomic< uint8_t >[], Free > data_
void folly::ShutdownSocketSet::shutdown ( int  fd,
bool  abortive = false 
)

Shut down a socket. If abortive is true, we perform an abortive shutdown (send RST rather than FIN). Note that we might still end up sending FIN due to the rather interesting implementation.

This is async-signal-safe and ignores errors. Obviously, subsequent read() and write() operations to the socket will fail. During normal operation, just call shutdown() on the socket.

Definition at line 102 of file ShutdownSocketSet.cpp.

References folly::closeNoInt(), data_, doShutdown(), FREE, IN_SHUTDOWN, IN_USE, maxFd_, MUST_CLOSE, SHUT_DOWN, and uint8_t.

Referenced by shutdownAll().

102  {
103  DCHECK_GE(fd, 0);
104  if (fd >= maxFd_) {
105  doShutdown(fd, abortive);
106  return;
107  }
108 
109  auto& sref = data_[size_t(fd)];
110  uint8_t prevState = IN_USE;
111  if (!sref.compare_exchange_strong(
112  prevState, IN_SHUTDOWN, std::memory_order_relaxed)) {
113  return;
114  }
115 
116  doShutdown(fd, abortive);
117 
118  prevState = IN_SHUTDOWN;
119  if (sref.compare_exchange_strong(
120  prevState, SHUT_DOWN, std::memory_order_relaxed)) {
121  return;
122  }
123 
124  CHECK_EQ(prevState, MUST_CLOSE)
125  << "Invalid prev state for fd " << fd << ": " << int(prevState);
126 
127  folly::closeNoInt(fd); // ignore errors, nothing to do
128 
129  CHECK(
130  sref.compare_exchange_strong(prevState, FREE, std::memory_order_relaxed))
131  << "Invalid prev state for fd " << fd << ": " << int(prevState);
132 }
int closeNoInt(int fd)
Definition: FileUtil.cpp:56
void doShutdown(int fd, bool abortive)
std::unique_ptr< std::atomic< uint8_t >[], Free > data_
void folly::ShutdownSocketSet::shutdownAll ( bool  abortive = false)

Immediate shutdown of all connections. This is a hard-hitting hammer; all reads and writes will return errors and no new connections will be accepted.

To be used only in dire situations. We're using it from the failure signal handler to close all connections quickly, even though the server might take multiple seconds to finish crashing.

The optional bool parameter indicates whether to set the active connections in to not linger. The effect of that includes RST packets being immediately sent to clients which will result in errors (and not normal EOF) on the client side. This also causes the local (ip, tcp port number) tuple to be reusable immediately, instead of having to wait the standard amount of time. For full details see the shutdown method of ShutdownSocketSet (incl. notes about the abortive parameter).

This is async-signal-safe and ignores errors.

Definition at line 134 of file ShutdownSocketSet.cpp.

References data_, i, IN_USE, maxFd_, and shutdown().

Referenced by folly::test::runKillTest().

134  {
135  for (int i = 0; i < maxFd_; ++i) {
136  auto& sref = data_[size_t(i)];
137  if (sref.load(std::memory_order_relaxed) == IN_USE) {
138  shutdown(i, abortive);
139  }
140  }
141 }
void shutdown(int fd, bool abortive=false)
std::unique_ptr< std::atomic< uint8_t >[], Free > data_

Member Data Documentation

std::unique_ptr<std::atomic<uint8_t>[], Free> folly::ShutdownSocketSet::data_
private

Definition at line 140 of file ShutdownSocketSet.h.

Referenced by add(), close(), remove(), shutdown(), and shutdownAll().

const int folly::ShutdownSocketSet::maxFd_
private

Definition at line 139 of file ShutdownSocketSet.h.

Referenced by add(), close(), remove(), shutdown(), and shutdownAll().

folly::File folly::ShutdownSocketSet::nullFile_
private

Definition at line 141 of file ShutdownSocketSet.h.

Referenced by doShutdown().


The documentation for this class was generated from the following files: