Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(473)

Side by Side Diff: base/sync_socket_posix.cc

Issue 2888403005: Change SyncSocket::ReceiveWithTimeout() to use poll() instead of select() on Posix platforms. (Closed)
Patch Set: Code review (thestig@). Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/sync_socket.h" 5 #include "base/sync_socket.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <limits.h> 9 #include <limits.h>
10 #include <poll.h>
10 #include <stddef.h> 11 #include <stddef.h>
11 #include <stdio.h> 12 #include <stdio.h>
12 #include <sys/ioctl.h> 13 #include <sys/ioctl.h>
13 #include <sys/socket.h> 14 #include <sys/socket.h>
14 #include <sys/types.h> 15 #include <sys/types.h>
15 16
16 #if defined(OS_SOLARIS) 17 #if defined(OS_SOLARIS)
17 #include <sys/filio.h> 18 #include <sys/filio.h>
18 #endif 19 #endif
19 20
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 } 136 }
136 137
137 size_t SyncSocket::ReceiveWithTimeout(void* buffer, 138 size_t SyncSocket::ReceiveWithTimeout(void* buffer,
138 size_t length, 139 size_t length,
139 TimeDelta timeout) { 140 TimeDelta timeout) {
140 ThreadRestrictions::AssertIOAllowed(); 141 ThreadRestrictions::AssertIOAllowed();
141 DCHECK_GT(length, 0u); 142 DCHECK_GT(length, 0u);
142 DCHECK_LE(length, kMaxMessageLength); 143 DCHECK_LE(length, kMaxMessageLength);
143 DCHECK_NE(handle_, kInvalidHandle); 144 DCHECK_NE(handle_, kInvalidHandle);
144 145
145 // TODO(dalecurtis): There's an undiagnosed issue on OSX where we're seeing
146 // large numbers of open files which prevents select() from being used. In
147 // this case, the best we can do is Peek() to see if we can Receive() now or
148 // return a timeout error (0) if not. See http://crbug.com/314364.
149 if (handle_ >= FD_SETSIZE)
150 return Peek() < length ? 0 : Receive(buffer, length);
151
152 // Only timeouts greater than zero and less than one second are allowed. 146 // Only timeouts greater than zero and less than one second are allowed.
153 DCHECK_GT(timeout.InMicroseconds(), 0); 147 DCHECK_GT(timeout.InMicroseconds(), 0);
154 DCHECK_LT(timeout.InMicroseconds(), 148 DCHECK_LT(timeout.InMicroseconds(),
155 base::TimeDelta::FromSeconds(1).InMicroseconds()); 149 TimeDelta::FromSeconds(1).InMicroseconds());
156 150
157 // Track the start time so we can reduce the timeout as data is read. 151 // Track the start time so we can reduce the timeout as data is read.
158 TimeTicks start_time = TimeTicks::Now(); 152 TimeTicks start_time = TimeTicks::Now();
159 const TimeTicks finish_time = start_time + timeout; 153 const TimeTicks finish_time = start_time + timeout;
160 154
161 fd_set read_fds; 155 struct pollfd pollfd;
162 size_t bytes_read_total; 156 pollfd.fd = handle_;
163 for (bytes_read_total = 0; 157 pollfd.events = POLLIN;
164 bytes_read_total < length && timeout.InMicroseconds() > 0; 158 pollfd.revents = 0;
165 timeout = finish_time - base::TimeTicks::Now()) {
166 FD_ZERO(&read_fds);
167 FD_SET(handle_, &read_fds);
168 159
169 // Wait for data to become available. 160 size_t bytes_read_total = 0;
170 struct timeval timeout_struct = 161 while (bytes_read_total < length) {
171 { 0, static_cast<suseconds_t>(timeout.InMicroseconds()) }; 162 const TimeDelta this_timeout = finish_time - TimeTicks::Now();
172 const int select_result = 163 const int timeout_ms =
173 select(handle_ + 1, &read_fds, NULL, NULL, &timeout_struct); 164 static_cast<int>(this_timeout.InMillisecondsRoundedUp());
165 if (timeout_ms <= 0)
166 break;
167 const int poll_result = poll(&pollfd, 1, timeout_ms);
174 // Handle EINTR manually since we need to update the timeout value. 168 // Handle EINTR manually since we need to update the timeout value.
175 if (select_result == -1 && errno == EINTR) 169 if (poll_result == -1 && errno == EINTR)
176 continue; 170 continue;
177 if (select_result <= 0) 171 // Return if other type of error or a timeout.
172 if (poll_result <= 0)
178 return bytes_read_total; 173 return bytes_read_total;
179 174
180 // select() only tells us that data is ready for reading, not how much. We 175 // poll() only tells us that data is ready for reading, not how much. We
181 // must Peek() for the amount ready for reading to avoid blocking. 176 // must Peek() for the amount ready for reading to avoid blocking.
182 DCHECK(FD_ISSET(handle_, &read_fds)); 177 // At hang up (POLLHUP), the write end has been closed and there might still
178 // be data to be read.
179 // No special handling is needed for error (POLLERR); we can let any of the
180 // following operations fail and handle it there.
181 DCHECK(pollfd.revents & (POLLIN | POLLHUP | POLLERR)) << pollfd.revents;
183 const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total); 182 const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total);
184 183
185 // There may be zero bytes to read if the socket at the other end closed. 184 // There may be zero bytes to read if the socket at the other end closed.
186 if (!bytes_to_read) 185 if (!bytes_to_read)
187 return bytes_read_total; 186 return bytes_read_total;
188 187
189 const size_t bytes_received = 188 const size_t bytes_received =
190 Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read); 189 Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read);
191 bytes_read_total += bytes_received; 190 bytes_read_total += bytes_received;
192 if (bytes_received != bytes_to_read) 191 if (bytes_received != bytes_to_read)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 return len; 244 return len;
246 } 245 }
247 246
248 // static 247 // static
249 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, 248 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
250 CancelableSyncSocket* socket_b) { 249 CancelableSyncSocket* socket_b) {
251 return SyncSocket::CreatePair(socket_a, socket_b); 250 return SyncSocket::CreatePair(socket_a, socket_b);
252 } 251 }
253 252
254 } // namespace base 253 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698