Skip to content

Commit

Permalink
Add Pipe::WriteWithTimeout method
Browse files Browse the repository at this point in the history
Summary:
This commit adds a WriteWithTimeout method to time Pipe class, analogous to the existing
ReadWithTimeout(). It also changes the meaning of passing zero as a timeout value. Previously,
zero was used as an infinite timeout value. Now, the meaning of zero timeout to return the data
avaiable without sleeping (basically, a non-blocking operation). This makes the behaviour of Pipe
consistent with the Communication/Connection classes. For blocking operatios with infinite
timeout, I introduce a special constant for this purpose.

Reviewers: ovyalov, zturner

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D11358

llvm-svn: 242764
  • Loading branch information
labath committed Jul 21, 2015
1 parent d818e38 commit 9f0701f
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 14 deletions.
6 changes: 5 additions & 1 deletion lldb/include/lldb/Host/PipeBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ class PipeBase
// Delete named pipe.
virtual Error Delete(llvm::StringRef name) = 0;

virtual Error Write(const void *buf, size_t size, size_t &bytes_written) = 0;
virtual Error WriteWithTimeout(const void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_written) = 0;
virtual Error ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) = 0;

Error Read(void *buf, size_t size, size_t &bytes_read);
Error Write(const void *buf, size_t size, size_t &bytes_written);

static const std::chrono::microseconds kInfiniteTimeout;
};
}

Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/Host/posix/PipePosix.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class PipePosix : public PipeBase
Delete(llvm::StringRef name) override;

Error
Write(const void *buf, size_t size, size_t &bytes_written) override;
WriteWithTimeout(const void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_written) override;
Error
ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) override;

Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/Host/windows/PipeWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class PipeWindows : public PipeBase

Error Delete(llvm::StringRef name) override;

Error Write(const void *buf, size_t size, size_t &bytes_written) override;
Error WriteWithTimeout(const void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_written) override;
Error ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) override;

// PipeWindows specific methods. These allow access to the underlying OS handle.
Expand Down
11 changes: 9 additions & 2 deletions lldb/source/Host/common/PipeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,24 @@

using namespace lldb_private;

const std::chrono::microseconds PipeBase::kInfiniteTimeout(-1);

PipeBase::~PipeBase() = default;

Error
PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit)
{
return OpenAsWriterWithTimeout(name, child_process_inherit, std::chrono::microseconds::zero());
return OpenAsWriterWithTimeout(name, child_process_inherit, kInfiniteTimeout);
}

Error
PipeBase::Read(void *buf, size_t size, size_t &bytes_read)
{
return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(), bytes_read);
return ReadWithTimeout(buf, size, kInfiniteTimeout, bytes_read);
}

Error
PipeBase::Write(const void *buf, size_t size, size_t &bytes_written)
{
return WriteWithTimeout(buf, size, kInfiniteTimeout, bytes_written);
}
16 changes: 10 additions & 6 deletions lldb/source/Host/posix/PipePosix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler
while (!done)
{
struct timeval tv = {0, 0};
if (timeout != microseconds::zero())
struct timeval *tv_p = &tv;
if (timeout != PipeBase::kInfiniteTimeout)
{
const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
if (remaining_dur.count() <= 0)
Expand All @@ -88,15 +89,15 @@ SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler
tv.tv_usec = dur_usecs.count();
}
else
tv.tv_sec = 1;
tv_p = nullptr;

FD_ZERO(&fds);
FD_SET(handle, &fds);

const auto retval = ::select(handle + 1,
(is_read) ? &fds : nullptr,
(is_read) ? nullptr : &fds,
nullptr, &tv);
nullptr, tv_p);
if (retval == -1)
{
if (errno == EINTR)
Expand Down Expand Up @@ -270,7 +271,7 @@ PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inhe

while (!CanWrite())
{
if (timeout != microseconds::zero())
if (timeout != kInfiniteTimeout)
{
const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
if (dur <= 0)
Expand Down Expand Up @@ -401,7 +402,10 @@ PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microsecon
}

Error
PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
PipePosix::WriteWithTimeout(const void *buf,
size_t size,
const std::chrono::microseconds &timeout,
size_t &bytes_written)
{
bytes_written = 0;
if (!CanWrite())
Expand All @@ -427,5 +431,5 @@ PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)

return error;
},
std::chrono::microseconds::zero());
timeout);
}
33 changes: 30 additions & 3 deletions lldb/source/Host/windows/PipeWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ PipeWindows::ReadWithTimeout(void *buf, size_t size, const std::chrono::microsec
if (!result && GetLastError() != ERROR_IO_PENDING)
return Error(::GetLastError(), eErrorTypeWin32);

DWORD timeout = (duration == std::chrono::microseconds::zero()) ? INFINITE : duration.count() * 1000;
DWORD timeout = (duration == kInfiniteTimeout) ? INFINITE : duration.count() * 1000;
DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout);
if (wait_result != WAIT_OBJECT_0)
{
Expand Down Expand Up @@ -319,7 +319,10 @@ PipeWindows::ReadWithTimeout(void *buf, size_t size, const std::chrono::microsec
}

Error
PipeWindows::Write(const void *buf, size_t num_bytes, size_t &bytes_written)
PipeWindows::WriteWithTimeout(const void *buf,
size_t num_bytes,
const std::chrono::microseconds &duration,
size_t &bytes_written)
{
if (!CanWrite())
return Error(ERROR_INVALID_HANDLE, eErrorTypeWin32);
Expand All @@ -329,8 +332,32 @@ PipeWindows::Write(const void *buf, size_t num_bytes, size_t &bytes_written)
if (!write_result && GetLastError() != ERROR_IO_PENDING)
return Error(::GetLastError(), eErrorTypeWin32);

BOOL result = GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_written, TRUE);
DWORD timeout = (duration == kInfiniteTimeout) ? INFINITE : duration.count() * 1000;
DWORD wait_result = ::WaitForSingleObject(m_write_overlapped.hEvent, timeout);
if (wait_result != WAIT_OBJECT_0)
{
// The operation probably failed. However, if it timed out, we need to cancel the I/O.
// Between the time we returned from WaitForSingleObject and the time we call CancelIoEx,
// the operation may complete. If that hapens, CancelIoEx will fail and return ERROR_NOT_FOUND.
// If that happens, the original operation should be considered to have been successful.
bool failed = true;
DWORD failure_error = ::GetLastError();
if (wait_result == WAIT_TIMEOUT)
{
BOOL cancel_result = CancelIoEx(m_read, &m_write_overlapped);
if (!cancel_result && GetLastError() == ERROR_NOT_FOUND)
failed = false;
}
if (failed)
return Error(failure_error, eErrorTypeWin32);
}

// Now we call GetOverlappedResult setting bWait to false, since we've already waited
// as long as we're willing to.
BOOL result = GetOverlappedResult(m_write, &m_write_overlapped, &sys_bytes_written, FALSE);
if (!result)
return Error(::GetLastError(), eErrorTypeWin32);

bytes_written = sys_bytes_written;
return Error();
}

0 comments on commit 9f0701f

Please sign in to comment.