summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-01 21:37:31 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-01 21:37:31 +0000
commit157c61b07b3ce5e308db6230da9d93ff74a16ca3 (patch)
tree7a627dd3c11b684852e2a3ffe84bcfc079bf1316 /net
parent105414ec43286c5ba9953eaf66f147a9a1a6afd5 (diff)
downloadchromium_src-157c61b07b3ce5e308db6230da9d93ff74a16ca3.zip
chromium_src-157c61b07b3ce5e308db6230da9d93ff74a16ca3.tar.gz
chromium_src-157c61b07b3ce5e308db6230da9d93ff74a16ca3.tar.bz2
POSIX: Add a macro for handling EINTR.
On POSIX systems, system calls can be interrupted by signals. In this case, they'll return EINTR, indicating that the system call needs to be restarted. (The situation is a little more complicated than this with SA_RESTART, but you can read man 7 signal if you like.) The short of it is that you need to catch EINTR and restart the call for these system calls: * read, readv, write, writev, ioctl * open() when dealing with a fifo * wait* * Anything socket based (send*, recv*, connect, accept etc) * flock and lock control with fcntl * mq_ functions which can block * futex * sem_wait (and timed wait) * pause, sigsuspend, sigtimedwait, sigwaitinfo * poll, epoll_wait, select and 'p' versions of the same * msgrcv, msgsnd, semop, semtimedop * close (although, on Linux, EINTR won't happen here) * any sleep functions (careful, you need to handle this are restart with different arguments) We've been a little sloppy with this until now. This patch adds a macro for dealing with this and corrects every case of these system calls (that I found). The macro is HANDLE_EINTR in base/eintr_wrapper.h. It's safe to include on Windows and is a no-op there. On POSIX, it uses GCC magic to return the correct type based on the expression and restarts the system call if it throws EINTR. And you can use it like: HANDLE_EINTR(close(fd)); Or: ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, len)); *BEWARE* that it will evaluate the argument multiple times, so this is not safe: HANDLE_EINTR(close(FireMissiles())); http://groups.google.com/group/chromium-dev/browse_thread/thread/41a35b2a457d73a0 http://codereview.chromium.org/100225 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15102 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/file_stream_posix.cc27
-rw-r--r--net/base/listen_socket.cc8
-rw-r--r--net/base/listen_socket_unittest.cc12
-rw-r--r--net/base/tcp_client_socket_libevent.cc18
-rw-r--r--net/base/telnet_server.cc3
5 files changed, 34 insertions, 34 deletions
diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc
index d1b70eb..8fca162 100644
--- a/net/base/file_stream_posix.cc
+++ b/net/base/file_stream_posix.cc
@@ -14,6 +14,7 @@
#include <errno.h>
#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
@@ -51,30 +52,20 @@ int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
// read(..., 0) returns 0 to indicate end-of-file.
// Loop in the case of getting interrupted by a signal.
- for (;;) {
- ssize_t res = read(file, buf, static_cast<size_t>(buf_len));
- if (res == static_cast<ssize_t>(-1)) {
- if (errno == EINTR)
- continue;
- return MapErrorCode(errno);
- }
- return static_cast<int>(res);
- }
+ ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
+ if (res == static_cast<ssize_t>(-1))
+ return MapErrorCode(errno);
+ return static_cast<int>(res);
}
// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes. It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
- while (true) {
- ssize_t res = write(file, buf, buf_len);
- if (res == -1) {
- if (errno == EINTR)
- continue;
- return MapErrorCode(errno);
- }
- return res;
- }
+ ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
+ if (res == -1)
+ return MapErrorCode(errno);
+ return res;
}
// BackgroundReadTask is a simple task that reads a file and then runs
diff --git a/net/base/listen_socket.cc b/net/base/listen_socket.cc
index a172e46..a9d16ef 100644
--- a/net/base/listen_socket.cc
+++ b/net/base/listen_socket.cc
@@ -16,6 +16,7 @@
#include "third_party/libevent/event.h"
#endif
+#include "base/eintr_wrapper.h"
#include "net/base/net_util.h"
#include "net/base/listen_socket.h"
@@ -93,7 +94,8 @@ void ListenSocket::Listen() {
SOCKET ListenSocket::Accept(SOCKET s) {
sockaddr_in from;
socklen_t from_len = sizeof(from);
- SOCKET conn = accept(s, reinterpret_cast<sockaddr*>(&from), &from_len);
+ SOCKET conn =
+ HANDLE_EINTR(accept(s, reinterpret_cast<sockaddr*>(&from), &from_len));
if (conn != INVALID_SOCKET) {
net::SetNonBlocking(conn);
}
@@ -119,7 +121,7 @@ void ListenSocket::Read() {
char buf[kReadBufSize + 1]; // +1 for null termination
int len;
do {
- len = recv(socket_, buf, kReadBufSize, 0);
+ len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
if (len == SOCKET_ERROR) {
#if defined(OS_WIN)
int err = WSAGetLastError();
@@ -188,7 +190,7 @@ void ListenSocket::WatchSocket(WaitState state) {
}
void ListenSocket::SendInternal(const char* bytes, int len) {
- int sent = send(socket_, bytes, len, 0);
+ int sent = HANDLE_EINTR(send(socket_, bytes, len, 0));
if (sent == SOCKET_ERROR) {
#if defined(OS_WIN)
int err = WSAGetLastError();
diff --git a/net/base/listen_socket_unittest.cc b/net/base/listen_socket_unittest.cc
index b08edc2..584d086 100644
--- a/net/base/listen_socket_unittest.cc
+++ b/net/base/listen_socket_unittest.cc
@@ -6,6 +6,7 @@
#include <fcntl.h>
+#include "base/eintr_wrapper.h"
#include "net/base/net_util.h"
#include "testing/platform_test.h"
@@ -57,8 +58,9 @@ void ListenSocketTester::SetUp() {
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(kLoopback);
client.sin_port = htons(kTestPort);
- int ret = connect(test_socket_,
- reinterpret_cast<sockaddr*>(&client), sizeof(client));
+ int ret =
+ HANDLE_EINTR(connect(test_socket_, reinterpret_cast<sockaddr*>(&client),
+ sizeof(client)));
ASSERT_NE(ret, SOCKET_ERROR);
net::SetNonBlocking(test_socket_);
@@ -154,7 +156,7 @@ int ListenSocketTester::ClearTestSocket() {
int len_ret = 0;
int time_out = 0;
do {
- int len = recv(test_socket_, buf, kReadBufSize, 0);
+ int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0));
#if defined(OS_WIN)
if (len == SOCKET_ERROR) {
int err = WSAGetLastError();
@@ -219,7 +221,7 @@ void ListenSocketTester::DidClose(ListenSocket *sock) {
bool ListenSocketTester::Send(SOCKET sock, const std::string& str) {
int len = static_cast<int>(str.length());
- int send_len = send(sock, str.data(), len, 0);
+ int send_len = HANDLE_EINTR(send(sock, str.data(), len, 0));
if (send_len == SOCKET_ERROR) {
LOG(ERROR) << "send failed: " << errno;
return false;
@@ -273,7 +275,7 @@ void ListenSocketTester::TestServerSend() {
char buf[buf_len+1];
int recv_len;
do {
- recv_len = recv(test_socket_, buf, buf_len, 0);
+ recv_len = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0));
#if defined(OS_POSIX)
} while (recv_len == SOCKET_ERROR && errno == EINTR);
#else
diff --git a/net/base/tcp_client_socket_libevent.cc b/net/base/tcp_client_socket_libevent.cc
index f6672c4..3e23f1c 100644
--- a/net/base/tcp_client_socket_libevent.cc
+++ b/net/base/tcp_client_socket_libevent.cc
@@ -9,6 +9,7 @@
#include <netdb.h>
#include <sys/socket.h>
+#include "base/eintr_wrapper.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/trace_event.h"
@@ -93,7 +94,8 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
if (rv != OK)
return rv;
- if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
+ if (!HANDLE_EINTR(connect(socket_, ai->ai_addr,
+ static_cast<int>(ai->ai_addrlen)))) {
TRACE_EVENT_END("socket.connect", this, "");
// Connected without waiting!
return OK;
@@ -147,7 +149,7 @@ bool TCPClientSocketLibevent::IsConnected() const {
// Check if connection is alive.
char c;
- int rv = recv(socket_, &c, 1, MSG_PEEK);
+ int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
if (rv == 0)
return false;
if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
@@ -163,7 +165,7 @@ bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
// Check if connection is alive and we haven't received any data
// unexpectedly.
char c;
- int rv = recv(socket_, &c, 1, MSG_PEEK);
+ int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
if (rv >= 0)
return false;
if (errno != EAGAIN && errno != EWOULDBLOCK)
@@ -183,7 +185,7 @@ int TCPClientSocketLibevent::Read(IOBuffer* buf,
DCHECK_GT(buf_len, 0);
TRACE_EVENT_BEGIN("socket.read", this, "");
- int nread = read(socket_, buf->data(), buf_len);
+ int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
if (nread >= 0) {
TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", nread));
return nread;
@@ -217,7 +219,7 @@ int TCPClientSocketLibevent::Write(IOBuffer* buf,
DCHECK_GT(buf_len, 0);
TRACE_EVENT_BEGIN("socket.write", this, "");
- int nwrite = write(socket_, buf->data(), buf_len);
+ int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
if (nwrite >= 0) {
TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", nwrite));
return nwrite;
@@ -309,7 +311,8 @@ void TCPClientSocketLibevent::DidCompleteConnect() {
void TCPClientSocketLibevent::DidCompleteRead() {
int bytes_transferred;
- bytes_transferred = read(socket_, read_buf_->data(), read_buf_len_);
+ bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
+ read_buf_len_));
int result;
if (bytes_transferred >= 0) {
@@ -330,7 +333,8 @@ void TCPClientSocketLibevent::DidCompleteRead() {
void TCPClientSocketLibevent::DidCompleteWrite() {
int bytes_transferred;
- bytes_transferred = write(socket_, write_buf_->data(), write_buf_len_);
+ bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
+ write_buf_len_));
int result;
if (bytes_transferred >= 0) {
diff --git a/net/base/telnet_server.cc b/net/base/telnet_server.cc
index 8cd2451..51ebf35 100644
--- a/net/base/telnet_server.cc
+++ b/net/base/telnet_server.cc
@@ -17,6 +17,7 @@
#include "base/message_pump_libevent.h"
#endif
+#include "base/eintr_wrapper.h"
#include "net/base/telnet_server.h"
#if defined(OS_POSIX)
@@ -250,7 +251,7 @@ void TelnetServer::Read() {
char buf[kReadBufSize + 1];
int len;
do {
- len = recv(socket_, buf, kReadBufSize, 0);
+ len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0));
#if defined(OS_WIN)
if (len == SOCKET_ERROR) {