libchromeos: Add ability to pass timeout to Stream::WaitForDataBlocking
To control the timeout when performing blocking I/O, added a |timeout|
parameter to Stream::WaitForDataBlocking.
BUG=brillo:1162
TEST=`FEATURES=test emerge-link libchromeos`
Change-Id: Icee2f7b0a8a93daf15b05bf5fbee2a4ec9410a17
Reviewed-on: https://chromium-review.googlesource.com/275027
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/chromeos/streams/fake_stream.cc b/chromeos/streams/fake_stream.cc
index 6e806c7..c786bca 100644
--- a/chromeos/streams/fake_stream.cc
+++ b/chromeos/streams/fake_stream.cc
@@ -378,6 +378,7 @@
}
bool FakeStream::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
const base::TimeDelta zero_delay;
@@ -391,6 +392,9 @@
GetMinDelayAndMode(clock_->Now(), read_requested, delay_input_until_,
write_requested, delay_output_until_, out_mode, &delay);
+ if (timeout < delay)
+ return stream_utils::ErrorOperationTimeout(FROM_HERE, error);
+
LOG(INFO) << "TEST: Would have blocked for " << delay.InMilliseconds()
<< " ms.";
diff --git a/chromeos/streams/fake_stream.h b/chromeos/streams/fake_stream.h
index 0990e28..690366e 100644
--- a/chromeos/streams/fake_stream.h
+++ b/chromeos/streams/fake_stream.h
@@ -112,6 +112,7 @@
const base::Callback<void(AccessMode)>& callback,
ErrorPtr* error) override;
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) override;
diff --git a/chromeos/streams/file_stream.cc b/chromeos/streams/file_stream.cc
index c1a4e49..d9ad3e6 100644
--- a/chromeos/streams/file_stream.cc
+++ b/chromeos/streams/file_stream.cc
@@ -104,6 +104,7 @@
}
int WaitForDataBlocking(Stream::AccessMode in_mode,
+ base::TimeDelta timeout,
Stream::AccessMode* out_mode) override {
fd_set read_fds;
fd_set write_fds;
@@ -120,9 +121,14 @@
FD_SET(fd_, &write_fds);
FD_SET(fd_, &error_fds);
+ timeval timeout_val = {};
+ if (!timeout.is_max()) {
+ const timespec ts = timeout.ToTimeSpec();
+ TIMESPEC_TO_TIMEVAL(&timeout_val, &ts);
+ }
int res = HANDLE_EINTR(select(fd_ + 1, &read_fds, &write_fds, &error_fds,
- nullptr));
- if (res >= 0 && out_mode) {
+ timeout.is_max() ? nullptr : &timeout_val));
+ if (res > 0 && out_mode) {
*out_mode = stream_utils::MakeAccessMode(FD_ISSET(fd_, &read_fds),
FD_ISSET(fd_, &write_fds));
}
@@ -492,15 +498,20 @@
}
bool FileStream::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
if (!IsOpen())
return stream_utils::ErrorStreamClosed(FROM_HERE, error);
- if (fd_interface_->WaitForDataBlocking(in_mode, out_mode) < 0) {
+ int ret = fd_interface_->WaitForDataBlocking(in_mode, timeout, out_mode);
+ if (ret < 0) {
errors::system::AddSystemError(error, FROM_HERE, errno);
return false;
}
+ if (ret == 0)
+ return stream_utils::ErrorOperationTimeout(FROM_HERE, error);
+
return true;
}
diff --git a/chromeos/streams/file_stream.h b/chromeos/streams/file_stream.h
index 8113a59..b793bd4 100644
--- a/chromeos/streams/file_stream.h
+++ b/chromeos/streams/file_stream.h
@@ -48,6 +48,7 @@
virtual void WaitForData(AccessMode mode,
const DataCallback& data_callback) = 0;
virtual int WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode) = 0;
virtual void CancelPendingAsyncOperations() = 0;
};
@@ -137,6 +138,7 @@
// Runs select() on the file descriptor to wait until we can do non-blocking
// I/O on it.
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) override;
diff --git a/chromeos/streams/file_stream_unittest.cc b/chromeos/streams/file_stream_unittest.cc
index a6fda48..0ca8acb 100644
--- a/chromeos/streams/file_stream_unittest.cc
+++ b/chromeos/streams/file_stream_unittest.cc
@@ -122,8 +122,8 @@
MOCK_METHOD0(Flush, int());
MOCK_METHOD0(Close, int());
MOCK_METHOD2(WaitForData, void(Stream::AccessMode, const DataCallback&));
- MOCK_METHOD2(WaitForDataBlocking,
- int(Stream::AccessMode, Stream::AccessMode*));
+ MOCK_METHOD3(WaitForDataBlocking,
+ int(Stream::AccessMode, base::TimeDelta, Stream::AccessMode*));
MOCK_METHOD0(CancelPendingAsyncOperations, void());
};
@@ -430,8 +430,8 @@
InSequence seq;
EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80)).WillOnce(Return(45));
}
EXPECT_TRUE(stream_->ReadBlocking(test_read_buffer_, 80, &size, nullptr));
@@ -447,7 +447,7 @@
InSequence seq;
EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _))
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
}
chromeos::ErrorPtr error;
@@ -463,18 +463,18 @@
EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100)).WillOnce(Return(20));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 20, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 20, 80))
.WillOnce(Return(45));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
.WillOnce(Return(35));
}
@@ -561,8 +561,8 @@
InSequence seq;
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80)).WillOnce(Return(45));
}
EXPECT_TRUE(stream_->WriteBlocking(test_write_buffer_, 80, &size, nullptr));
@@ -571,8 +571,8 @@
{
InSequence seq;
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 50)).WillOnce(Return(0));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 50)).WillOnce(Return(1));
}
EXPECT_TRUE(stream_->WriteBlocking(test_write_buffer_, 50, &size, nullptr));
@@ -584,7 +584,7 @@
InSequence seq;
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
}
chromeos::ErrorPtr error;
@@ -600,18 +600,18 @@
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 100)).WillOnce(Return(20));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 20, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 20, 80))
.WillOnce(Return(45));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
- .WillOnce(Return(0));
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(1));
EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
.WillOnce(Return(35));
}
@@ -623,7 +623,7 @@
InSequence seq;
EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
- EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _))
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
}
chromeos::ErrorPtr error;
@@ -632,6 +632,16 @@
EXPECT_EQ("EBADF", error->GetCode());
}
+TEST_F(FileStreamTest, WaitForDataBlocking_Timeout) {
+ EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+ .WillOnce(Return(0));
+ chromeos::ErrorPtr error;
+ EXPECT_FALSE(stream_->WaitForDataBlocking(Stream::AccessMode::WRITE, {},
+ nullptr, &error));
+ EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+ EXPECT_EQ(errors::stream::kTimeout, error->GetCode());
+}
+
TEST_F(FileStreamTest, FlushBlocking) {
EXPECT_TRUE(stream_->FlushBlocking(nullptr));
}
diff --git a/chromeos/streams/input_stream_set.cc b/chromeos/streams/input_stream_set.cc
index a2ba2ae..2a6e719 100644
--- a/chromeos/streams/input_stream_set.cc
+++ b/chromeos/streams/input_stream_set.cc
@@ -178,6 +178,7 @@
}
bool InputStreamSet::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
if (!IsOpen())
@@ -188,7 +189,7 @@
if (!source_streams_.empty()) {
Stream* stream = source_streams_.front();
- return stream->WaitForDataBlocking(in_mode, out_mode, error);
+ return stream->WaitForDataBlocking(in_mode, timeout, out_mode, error);
}
if (out_mode)
diff --git a/chromeos/streams/input_stream_set.h b/chromeos/streams/input_stream_set.h
index ec29ccb..a37ab08 100644
--- a/chromeos/streams/input_stream_set.h
+++ b/chromeos/streams/input_stream_set.h
@@ -100,6 +100,7 @@
ErrorPtr* error) override;
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) override;
diff --git a/chromeos/streams/input_stream_set_unittest.cc b/chromeos/streams/input_stream_set_unittest.cc
index de6e717..82ac60c 100644
--- a/chromeos/streams/input_stream_set_unittest.cc
+++ b/chromeos/streams/input_stream_set_unittest.cc
@@ -150,7 +150,7 @@
.WillOnce(DoAll(SetArgPointee<2>(0),
SetArgPointee<3>(false),
Return(true)));
- EXPECT_CALL(*itf2_, WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+ EXPECT_CALL(*itf2_, WaitForDataBlocking(Stream::AccessMode::READ, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(100),
diff --git a/chromeos/streams/memory_stream.cc b/chromeos/streams/memory_stream.cc
index 3a9fdff..eb2f829 100644
--- a/chromeos/streams/memory_stream.cc
+++ b/chromeos/streams/memory_stream.cc
@@ -195,6 +195,7 @@
}
bool MemoryStream::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
if (out_mode)
diff --git a/chromeos/streams/memory_stream.h b/chromeos/streams/memory_stream.h
index f36ee54..ac03440 100644
--- a/chromeos/streams/memory_stream.h
+++ b/chromeos/streams/memory_stream.h
@@ -183,6 +183,7 @@
ErrorPtr* error) override;
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) override;
diff --git a/chromeos/streams/mock_stream.h b/chromeos/streams/mock_stream.h
index 4fe3562..a1303c2 100644
--- a/chromeos/streams/mock_stream.h
+++ b/chromeos/streams/mock_stream.h
@@ -63,7 +63,8 @@
MOCK_METHOD3(WaitForData, bool(AccessMode,
const base::Callback<void(AccessMode)>&,
ErrorPtr*));
- MOCK_METHOD3(WaitForDataBlocking, bool(AccessMode, AccessMode*, ErrorPtr*));
+ MOCK_METHOD4(WaitForDataBlocking,
+ bool(AccessMode, base::TimeDelta, AccessMode*, ErrorPtr*));
private:
DISALLOW_COPY_AND_ASSIGN(MockStream);
diff --git a/chromeos/streams/stream.cc b/chromeos/streams/stream.cc
index 759360b..0e10f24 100644
--- a/chromeos/streams/stream.cc
+++ b/chromeos/streams/stream.cc
@@ -68,8 +68,10 @@
if (*size_read > 0 || eos)
break;
- if (!WaitForDataBlocking(AccessMode::READ, nullptr, error))
+ if (!WaitForDataBlocking(AccessMode::READ, base::TimeDelta::Max(), nullptr,
+ error)) {
return false;
+ }
}
return true;
}
@@ -133,8 +135,10 @@
if (*size_written > 0 || size_to_write == 0)
break;
- if (!WaitForDataBlocking(AccessMode::WRITE, nullptr, error))
+ if (!WaitForDataBlocking(AccessMode::WRITE, base::TimeDelta::Max(), nullptr,
+ error)) {
return false;
+ }
}
return true;
}
diff --git a/chromeos/streams/stream.h b/chromeos/streams/stream.h
index 4886fe6..13530b7 100644
--- a/chromeos/streams/stream.h
+++ b/chromeos/streams/stream.h
@@ -11,6 +11,7 @@
#include <base/callback.h>
#include <base/macros.h>
#include <base/memory/weak_ptr.h>
+#include <base/time/time.h>
#include <chromeos/errors/error.h>
#include <chromeos/chromeos_export.h>
@@ -379,7 +380,10 @@
// performed. For example, watching a stream for READ_WRITE while only
// READ can be performed, |out_mode| would contain READ even though |in_mode|
// was set to READ_WRITE.
+ // |timeout| is the maximum amount of time to wait. Set it to TimeDelta::Max()
+ // to wait indefinitely.
virtual bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) = 0;
diff --git a/chromeos/streams/stream_errors.cc b/chromeos/streams/stream_errors.cc
index 32def0f..35911c5 100644
--- a/chromeos/streams/stream_errors.cc
+++ b/chromeos/streams/stream_errors.cc
@@ -14,6 +14,7 @@
const char kOperationNotSupported[] = "operation_not_supported";
const char kPartialData[] = "partial_data";
const char kInvalidParameter[] = "invalid_parameter";
+const char kTimeout[] = "time_out";
} // namespace stream
} // namespace errors
diff --git a/chromeos/streams/stream_errors.h b/chromeos/streams/stream_errors.h
index 1c9c9e6..61f8a6f 100644
--- a/chromeos/streams/stream_errors.h
+++ b/chromeos/streams/stream_errors.h
@@ -18,6 +18,7 @@
CHROMEOS_EXPORT extern const char kOperationNotSupported[];
CHROMEOS_EXPORT extern const char kPartialData[];
CHROMEOS_EXPORT extern const char kInvalidParameter[];
+CHROMEOS_EXPORT extern const char kTimeout[];
} // namespace stream
} // namespace errors
diff --git a/chromeos/streams/stream_unittest.cc b/chromeos/streams/stream_unittest.cc
index ca1242a..9630d97 100644
--- a/chromeos/streams/stream_unittest.cc
+++ b/chromeos/streams/stream_unittest.cc
@@ -63,7 +63,8 @@
MOCK_METHOD3(WaitForData, bool(AccessMode,
const base::Callback<void(AccessMode)>&,
ErrorPtr*));
- MOCK_METHOD3(WaitForDataBlocking, bool(AccessMode, AccessMode*, ErrorPtr*));
+ MOCK_METHOD4(WaitForDataBlocking,
+ bool(AccessMode, base::TimeDelta, AccessMode*, ErrorPtr*));
private:
DISALLOW_COPY_AND_ASSIGN(MockStreamImpl);
@@ -232,13 +233,13 @@
.WillOnce(DoAll(SetArgPointee<2>(0),
SetArgPointee<3>(false),
Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(0),
SetArgPointee<3>(false),
Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(124),
@@ -254,7 +255,7 @@
.WillOnce(DoAll(SetArgPointee<2>(0),
SetArgPointee<3>(false),
Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
.WillOnce(Return(false));
}
EXPECT_FALSE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
@@ -366,11 +367,11 @@
InSequence seq;
EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
.WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
.WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
.WillOnce(DoAll(SetArgPointee<2>(124), Return(true)));
@@ -382,7 +383,7 @@
InSequence seq;
EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
.WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
- EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _))
+ EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
.WillOnce(Return(false));
}
EXPECT_FALSE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
diff --git a/chromeos/streams/stream_utils.cc b/chromeos/streams/stream_utils.cc
index 7e83737..1b2004c 100644
--- a/chromeos/streams/stream_utils.cc
+++ b/chromeos/streams/stream_utils.cc
@@ -41,6 +41,17 @@
return false;
}
+bool ErrorOperationTimeout(const tracked_objects::Location& location,
+ ErrorPtr* error) {
+ Error::AddTo(error,
+ location,
+ errors::stream::kDomain,
+ errors::stream::kTimeout,
+ "Operation timed out");
+ return false;
+}
+
+
bool CheckInt64Overflow(const tracked_objects::Location& location,
uint64_t position,
int64_t offset,
diff --git a/chromeos/streams/stream_utils.h b/chromeos/streams/stream_utils.h
index 33ae0bf..09ff38c 100644
--- a/chromeos/streams/stream_utils.h
+++ b/chromeos/streams/stream_utils.h
@@ -24,6 +24,10 @@
CHROMEOS_EXPORT bool ErrorReadPastEndOfStream(
const tracked_objects::Location& location, ErrorPtr* error);
+// Generates "Operation time out" error and returns false.
+CHROMEOS_EXPORT bool ErrorOperationTimeout(
+ const tracked_objects::Location& location, ErrorPtr* error);
+
// Checks if |position| + |offset| fit within the constraint of positive
// signed int64_t type. We use uint64_t for absolute stream pointer positions,
// however many implementations, including file-descriptor-based I/O do not
diff --git a/chromeos/streams/tls_stream.cc b/chromeos/streams/tls_stream.cc
index 107ea85..345a340 100644
--- a/chromeos/streams/tls_stream.cc
+++ b/chromeos/streams/tls_stream.cc
@@ -92,6 +92,7 @@
const base::Callback<void(AccessMode)>& callback,
ErrorPtr* error);
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error);
void CancelPendingAsyncOperations();
@@ -203,6 +204,8 @@
}
bool TlsStream::TlsStreamImpl::Close(ErrorPtr* error) {
+ // 2 seconds should be plenty here.
+ const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(2);
int retry_count = 0;
while (retry_count < 2) {
int ret = SSL_shutdown(ssl_.get());
@@ -216,11 +219,15 @@
int err = SSL_get_error(ssl_.get(), ret);
if (err == SSL_ERROR_WANT_READ) {
- if (!socket_->WaitForDataBlocking(AccessMode::READ, nullptr, error))
+ if (!socket_->WaitForDataBlocking(AccessMode::READ, kTimeout, nullptr,
+ error)) {
break;
+ }
} else if (err == SSL_ERROR_WANT_WRITE) {
- if (!socket_->WaitForDataBlocking(AccessMode::WRITE, nullptr, error))
+ if (!socket_->WaitForDataBlocking(AccessMode::WRITE, kTimeout, nullptr,
+ error)) {
break;
+ }
} else {
ReportError(error, FROM_HERE, "Failed to shut down TLS socket");
break;
@@ -248,6 +255,7 @@
}
bool TlsStream::TlsStreamImpl::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
bool is_read = stream_utils::IsReadAccessMode(in_mode);
@@ -261,7 +269,7 @@
return true;
}
in_mode = stream_utils::MakeAccessMode(is_read, is_write);
- return socket_->WaitForDataBlocking(in_mode, out_mode, error);
+ return socket_->WaitForDataBlocking(in_mode, timeout, out_mode, error);
}
void TlsStream::TlsStreamImpl::CancelPendingAsyncOperations() {
@@ -517,11 +525,12 @@
}
bool TlsStream::WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) {
if (!impl_)
return stream_utils::ErrorStreamClosed(FROM_HERE, error);
- return impl_->WaitForDataBlocking(in_mode, out_mode, error);
+ return impl_->WaitForDataBlocking(in_mode, timeout, out_mode, error);
}
void TlsStream::CancelPendingAsyncOperations() {
diff --git a/chromeos/streams/tls_stream.h b/chromeos/streams/tls_stream.h
index a888df2..fb5b323 100644
--- a/chromeos/streams/tls_stream.h
+++ b/chromeos/streams/tls_stream.h
@@ -64,6 +64,7 @@
const base::Callback<void(AccessMode)>& callback,
ErrorPtr* error) override;
bool WaitForDataBlocking(AccessMode in_mode,
+ base::TimeDelta timeout,
AccessMode* out_mode,
ErrorPtr* error) override;
void CancelPendingAsyncOperations() override;