labath updated this revision to Diff 55397.
labath added a comment.

Added proper handling of the timeout after retries, and moved the functionality 
into
Connection::Read. I have called the parameter read_full_buffer, as I think that 
better reflects
its intended use. I did not want to add a default value for it, since default 
values on virtual
functions can produce unexpected results. I've also had to increase the timeout 
in AdbClient,
since now it actually had a meaning (it seems that ReadAll was spinning in a 
loop also in case
the server was sending no data at all).  The patch has grown bigger, but this 
is mostly due to
me refactoring unit tests to promote code reuse.


http://reviews.llvm.org/D19533

Files:
  include/lldb/Core/Connection.h
  include/lldb/Core/ConnectionSharedMemory.h
  include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
  source/Core/Communication.cpp
  source/Core/ConnectionSharedMemory.cpp
  source/Host/common/Editline.cpp
  source/Host/posix/ConnectionFileDescriptorPosix.cpp
  source/Plugins/Platform/Android/AdbClient.cpp
  unittests/Host/CMakeLists.txt
  unittests/Host/ConnectionFileDescriptorPosixTest.cpp
  unittests/Host/SocketTest.cpp
  unittests/Host/SocketUtil.h

Index: unittests/Host/SocketUtil.h
===================================================================
--- /dev/null
+++ unittests/Host/SocketUtil.h
@@ -0,0 +1,66 @@
+//===-- SocketUtil.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_unittests_Host_SocketUtil_h
+#define lldb_unittests_Host_SocketUtil_h
+
+#include <future>
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/common/TCPSocket.h"
+
+template <typename SocketType>
+std::pair<std::unique_ptr<SocketType>, std::unique_ptr<SocketType>>
+CreateConnectedSockets(const char *listen_remote_address,
+                       const std::function<std::string(const SocketType &)> &get_connect_addr)
+{
+    using namespace lldb_private;
+
+    const bool child_processes_inherit = false;
+    Error error;
+    std::unique_ptr<SocketType> listen_socket_up(new SocketType(child_processes_inherit, error));
+    EXPECT_FALSE(error.Fail());
+    error = listen_socket_up->Listen(listen_remote_address, 5);
+    EXPECT_FALSE(error.Fail());
+    EXPECT_TRUE(listen_socket_up->IsValid());
+
+    Socket *accept_socket;
+    std::future<Error> accept_error = std::async(std::launch::async, [&]() {
+        return listen_socket_up->Accept(listen_remote_address, child_processes_inherit, accept_socket);
+    });
+
+    std::string connect_remote_address = get_connect_addr(*listen_socket_up);
+    std::unique_ptr<SocketType> connect_socket_up(new SocketType(child_processes_inherit, error));
+    EXPECT_FALSE(error.Fail());
+    error = connect_socket_up->Connect(connect_remote_address.c_str());
+    EXPECT_FALSE(error.Fail());
+    EXPECT_NE(nullptr, connect_socket_up);
+    EXPECT_TRUE(connect_socket_up->IsValid());
+
+    EXPECT_TRUE(accept_error.get().Success());
+    EXPECT_NE(nullptr, accept_socket);
+    EXPECT_TRUE(accept_socket->IsValid());
+
+    return {std::move(connect_socket_up), std::unique_ptr<SocketType>(static_cast<SocketType *>(accept_socket))};
+}
+
+inline std::pair<std::unique_ptr<lldb_private::TCPSocket>, std::unique_ptr<lldb_private::TCPSocket>>
+CreateConnectedTCPSockets()
+{
+    return CreateConnectedSockets<lldb_private::TCPSocket>("127.0.0.1:0", [=](const lldb_private::TCPSocket &s) {
+        char connect_remote_address[64];
+        snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber());
+        return std::string(connect_remote_address);
+    });
+}
+
+#endif /* lldb_unittests_Host_SocketUtil_h */
Index: unittests/Host/SocketTest.cpp
===================================================================
--- unittests/Host/SocketTest.cpp
+++ unittests/Host/SocketTest.cpp
@@ -19,9 +19,9 @@
 
 #include "gtest/gtest.h"
 
+#include "SocketUtil.h"
+
 #include "lldb/Host/Config.h"
-#include "lldb/Host/Socket.h"
-#include "lldb/Host/common/TCPSocket.h"
 #include "lldb/Host/common/UDPSocket.h"
 
 #ifndef LLDB_DISABLE_POSIX
@@ -49,52 +49,6 @@
         ::WSACleanup();
 #endif
     }
-
-  protected:
-    static void
-    AcceptThread(Socket *listen_socket, const char *listen_remote_address, bool child_processes_inherit,
-                 Socket **accept_socket, Error *error)
-    {
-        *error = listen_socket->Accept(listen_remote_address, child_processes_inherit, *accept_socket);
-    }
-
-    template<typename SocketType>
-    void
-    CreateConnectedSockets(const char *listen_remote_address, const std::function<std::string(const SocketType&)> &get_connect_addr, std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up)
-    {
-        bool child_processes_inherit = false;
-        Error error;
-        std::unique_ptr<SocketType> listen_socket_up(new SocketType(child_processes_inherit, error));
-        EXPECT_FALSE(error.Fail());
-        error = listen_socket_up->Listen(listen_remote_address, 5);
-        EXPECT_FALSE(error.Fail());
-        EXPECT_TRUE(listen_socket_up->IsValid());
-
-        Error accept_error;
-        Socket *accept_socket;
-        std::thread accept_thread(AcceptThread, listen_socket_up.get(), listen_remote_address, child_processes_inherit,
-                                  &accept_socket, &accept_error);
-
-        std::string connect_remote_address = get_connect_addr(*listen_socket_up);
-        std::unique_ptr<SocketType> connect_socket_up(new SocketType(child_processes_inherit, error));
-        EXPECT_FALSE(error.Fail());
-        error = connect_socket_up->Connect(connect_remote_address.c_str());
-        EXPECT_FALSE(error.Fail());
-        EXPECT_TRUE(connect_socket_up->IsValid());
-
-        a_up->swap(connect_socket_up);
-        EXPECT_TRUE(error.Success());
-        EXPECT_NE(nullptr, a_up->get());
-        EXPECT_TRUE((*a_up)->IsValid());
-
-        accept_thread.join();
-        b_up->reset(static_cast<SocketType*>(accept_socket));
-        EXPECT_TRUE(accept_error.Success());
-        EXPECT_NE(nullptr, b_up->get());
-        EXPECT_TRUE((*b_up)->IsValid());
-
-        listen_socket_up.reset();
-    }
 };
 
 TEST_F (SocketTest, DecodeHostAndPort)
@@ -148,44 +102,20 @@
     const std::string file_name(file_name_str);
     free(file_name_str);
 
-    std::unique_ptr<DomainSocket> socket_a_up;
-    std::unique_ptr<DomainSocket> socket_b_up;
-    CreateConnectedSockets<DomainSocket>(file_name.c_str(),
-                                      [=](const DomainSocket &)
-                                      {
-                                          return file_name;
-                                      },
-                                      &socket_a_up, &socket_b_up);
+    CreateConnectedSockets<DomainSocket>(file_name.c_str(), [=](const DomainSocket &) { return file_name; });
 }
 #endif
 
 TEST_F (SocketTest, TCPListen0ConnectAccept)
 {
-    std::unique_ptr<TCPSocket> socket_a_up;
-    std::unique_ptr<TCPSocket> socket_b_up;
-    CreateConnectedSockets<TCPSocket>("127.0.0.1:0",
-                                      [=](const TCPSocket &s)
-                                      {
-                                          char connect_remote_address[64];
-                                          snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber());
-                                          return std::string(connect_remote_address);
-                                      },
-                                      &socket_a_up, &socket_b_up);
+    CreateConnectedTCPSockets();
 }
 
 TEST_F (SocketTest, TCPGetAddress)
 {
     std::unique_ptr<TCPSocket> socket_a_up;
     std::unique_ptr<TCPSocket> socket_b_up;
-    CreateConnectedSockets<TCPSocket>("127.0.0.1:0",
-                                      [=](const TCPSocket &s)
-                                      {
-                                          char connect_remote_address[64];
-                                          snprintf(connect_remote_address, sizeof(connect_remote_address), "localhost:%u", s.GetLocalPortNumber());
-                                          return std::string(connect_remote_address);
-                                      },
-                                      &socket_a_up,
-                                      &socket_b_up);
+    std::tie(socket_a_up, socket_b_up) = CreateConnectedTCPSockets();
 
     EXPECT_EQ (socket_a_up->GetLocalPortNumber (), socket_b_up->GetRemotePortNumber ());
     EXPECT_EQ (socket_b_up->GetLocalPortNumber (), socket_a_up->GetRemotePortNumber ());
Index: unittests/Host/ConnectionFileDescriptorPosixTest.cpp
===================================================================
--- /dev/null
+++ unittests/Host/ConnectionFileDescriptorPosixTest.cpp
@@ -0,0 +1,135 @@
+//===-- ConnectionFileDescriptorPosixTest.cpp -------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#include "SocketUtil.h"
+
+#include "lldb/Host/ConnectionFileDescriptor.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+class ConnectionFileDescriptorPosixTest : public testing::Test
+{
+public:
+    void
+    SetUp() override
+    {
+#if defined(_MSC_VER)
+        WSADATA data;
+        ::WSAStartup(MAKEWORD(2, 2), &data);
+#endif
+    }
+
+    void
+    TearDown() override
+    {
+#if defined(_MSC_VER)
+        ::WSACleanup();
+#endif
+    }
+};
+
+TEST_F(ConnectionFileDescriptorPosixTest, ReadAll)
+{
+    const bool read_full_buffer = true;
+
+    std::unique_ptr<TCPSocket> socket_a_up;
+    std::unique_ptr<TCPSocket> socket_b_up;
+    std::tie(socket_a_up, socket_b_up) = CreateConnectedTCPSockets();
+
+    ConnectionFileDescriptor connection_a(socket_a_up.release());
+
+    // First, make sure Read returns nothing.
+    const auto k_reasonable_timeout_us = 10 * 1000;
+    char buffer[100];
+    ConnectionStatus status;
+    Error error;
+    size_t bytes_read =
+        connection_a.Read(buffer, sizeof buffer, k_reasonable_timeout_us, read_full_buffer, status, &error);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(eConnectionStatusTimedOut, status);
+    ASSERT_EQ(0u, bytes_read);
+
+    // Write some data, and make sure it arrives.
+    const char data[] = {1, 2, 3, 4};
+    size_t bytes_written = sizeof data;
+    error = socket_b_up->Write(data, bytes_written);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(sizeof data, bytes_written);
+    bytes_read = connection_a.Read(buffer, sizeof data, k_reasonable_timeout_us, read_full_buffer, status, &error);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(eConnectionStatusSuccess, status);
+    ASSERT_EQ(sizeof data, bytes_read);
+    ASSERT_EQ(0, memcmp(buffer, data, sizeof data));
+    memset(buffer, 0, sizeof buffer);
+
+    // Write the data in two chunks. Make sure we read all of it.
+    std::future<Error> future_error = std::async(std::launch::async, [&socket_b_up, data]() {
+        size_t bytes_written = sizeof(data) / 2;
+        Error error = socket_b_up->Write(data, bytes_written);
+        if (error.Fail())
+            return error;
+        std::this_thread::sleep_for(std::chrono::microseconds(k_reasonable_timeout_us / 10));
+        bytes_written = sizeof(data) / 2;
+        return socket_b_up->Write(data + bytes_written, bytes_written);
+    });
+    bytes_read = connection_a.Read(buffer, sizeof data, k_reasonable_timeout_us, read_full_buffer, status, &error);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(eConnectionStatusSuccess, status);
+    ASSERT_EQ(sizeof data, bytes_read);
+    ASSERT_TRUE(future_error.get().Success()) << future_error.get().AsCString();
+    ASSERT_EQ(0, memcmp(buffer, data, sizeof data));
+
+    // Close the remote end, make sure Read result is reasonable.
+    socket_b_up.reset();
+    bytes_read = connection_a.Read(buffer, sizeof buffer, k_reasonable_timeout_us, read_full_buffer, status, &error);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(eConnectionStatusEndOfFile, status);
+    ASSERT_EQ(0u, bytes_read);
+}
+
+TEST_F(ConnectionFileDescriptorPosixTest, Read)
+{
+    const bool read_full_buffer = false;
+
+    std::unique_ptr<TCPSocket> socket_a_up;
+    std::unique_ptr<TCPSocket> socket_b_up;
+    std::tie(socket_a_up, socket_b_up) = CreateConnectedTCPSockets();
+
+    ConnectionFileDescriptor connection_a(socket_a_up.release());
+
+    const uint32_t k_very_large_timeout_us = 10 * 1000 * 1000;
+    char buffer[100];
+    ConnectionStatus status;
+    Error error;
+
+    // Write some data (but not a full buffer). Make sure it arrives, and we do not wait too long.
+    const char data[] = {1, 2, 3, 4};
+    size_t bytes_written = sizeof data;
+    error = socket_b_up->Write(data, bytes_written);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(sizeof data, bytes_written);
+
+    const auto start = std::chrono::steady_clock::now();
+    size_t bytes_read =
+        connection_a.Read(buffer, sizeof buffer, k_very_large_timeout_us, read_full_buffer, status, &error);
+    ASSERT_TRUE(error.Success()) << error.AsCString();
+    ASSERT_EQ(eConnectionStatusSuccess, status);
+    ASSERT_EQ(sizeof data, bytes_read);
+    ASSERT_EQ(0, memcmp(buffer, data, sizeof data));
+    ASSERT_LT(std::chrono::steady_clock::now(), start + std::chrono::microseconds(k_very_large_timeout_us / 10));
+}
Index: unittests/Host/CMakeLists.txt
===================================================================
--- unittests/Host/CMakeLists.txt
+++ unittests/Host/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_unittest(HostTests
   FileSpecTest.cpp
+  ConnectionFileDescriptorPosixTest.cpp
   SocketAddressTest.cpp
   SocketTest.cpp
   SymbolsTest.cpp
Index: source/Plugins/Platform/Android/AdbClient.cpp
===================================================================
--- source/Plugins/Platform/Android/AdbClient.cpp
+++ source/Plugins/Platform/Android/AdbClient.cpp
@@ -34,7 +34,7 @@
 
 namespace {
 
-const uint32_t kReadTimeout = 1000000; // 1 second
+const uint32_t kReadTimeout = 4000000; // 4 seconds
 const char * kOKAY = "OKAY";
 const char * kFAIL = "FAIL";
 const char * kDATA = "DATA";
@@ -251,7 +251,9 @@
         if (elapsed_time >= timeout_ms)
             return Error("Timed out");
 
-        size_t n = m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error);
+        const bool read_full_buffer = true;
+        size_t n =
+            m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), read_full_buffer, status, &error);
         if (n > 0)
             message.insert(message.end(), &buffer[0], &buffer[n]);
     }
@@ -490,19 +492,15 @@
 Error
 AdbClient::ReadAllBytes (void *buffer, size_t size)
 {
+    const bool read_full_buffer = true;
     Error error;
     ConnectionStatus status;
-    char *read_buffer = static_cast<char*>(buffer);
-
-    size_t tota_read_bytes = 0;
-    while (tota_read_bytes < size)
-    {
-        auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error);
-        if (error.Fail ())
-            return error;
-        tota_read_bytes += read_bytes;
-    }
-    return error;
+    size_t read_bytes = m_conn.Read(buffer, size, kReadTimeout, read_full_buffer, status, &error);
+    if (error.Fail())
+        return error;
+    if (read_bytes < size)
+        return Error("Unable to read full buffer.");
+    return Error();
 }
 
 Error
Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp
===================================================================
--- source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -411,7 +411,8 @@
 }
 
 size_t
-ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
+ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, bool read_full_buffer,
+                               ConnectionStatus &status, Error *error_ptr)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
 
@@ -434,26 +435,36 @@
         return 0;
     }
 
-    status = BytesAvailable(timeout_usec, error_ptr);
-    if (status != eConnectionStatusSuccess)
-        return 0;
-
+    size_t total_bytes_read = 0;
+    char *dst_buf = static_cast<char *>(dst);
+    auto now = std::chrono::steady_clock::now();
+    const auto deadline = now + std::chrono::microseconds(timeout_usec);
     Error error;
-    size_t bytes_read = dst_len;
-    error = m_read_sp->Read(dst, bytes_read);
-
-    if (log)
+    do
     {
-        log->Printf("%p ConnectionFileDescriptor::Read()  fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
-                    static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst),
-                    static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
-    }
+        timeout_usec = std::chrono::duration_cast<std::chrono::microseconds>(deadline - now).count();
+        status = BytesAvailable(timeout_usec, error_ptr);
+        if (status != eConnectionStatusSuccess)
+            return 0;
 
-    if (bytes_read == 0)
-    {
-        error.Clear(); // End-of-file.  Do not automatically close; pass along for the end-of-file handlers.
-        status = eConnectionStatusEndOfFile;
-    }
+        size_t bytes_read = dst_len - total_bytes_read;
+        error = m_read_sp->Read(dst_buf + total_bytes_read, bytes_read);
+        if (log)
+        {
+            log->Printf("%p ConnectionFileDescriptor::Read()  fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64
+                        ") => %" PRIu64 ", error = %s",
+                        this, static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), dst,
+                        static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
+        }
+        total_bytes_read += bytes_read;
+        if (bytes_read == 0)
+        {
+            // End-of-file.  Do not automatically close; pass along for the end-of-file handlers.
+            error.Clear();
+            status = eConnectionStatusEndOfFile;
+        }
+        now = std::chrono::steady_clock::now();
+    } while (read_full_buffer && total_bytes_read < dst_len && status == eConnectionStatusSuccess && now < deadline);
 
     if (error_ptr)
         *error_ptr = error;
@@ -509,7 +520,7 @@
 
         return 0;
     }
-    return bytes_read;
+    return total_bytes_read;
 }
 
 size_t
Index: source/Host/common/Editline.cpp
===================================================================
--- source/Host/common/Editline.cpp
+++ source/Host/common/Editline.cpp
@@ -580,20 +580,21 @@
     // Read an actual character
     while (true)
     {
+        const bool read_full_buffer = false; // Doesn't really matter, we're reading one byte only.
         lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
         char ch = 0;
 
         // This mutex is locked by our caller (GetLine). Unlock it while we read a character
         // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance
         // for someone to interrupt us. After Read returns, immediately lock the mutex again and
         // check if we were interrupted.
         m_output_mutex.Unlock();
-        int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+        int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, read_full_buffer, status, NULL);
         m_output_mutex.Lock();
         if (m_editor_status == EditorStatus::Interrupted)
         {
             while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
-                read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+                read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, read_full_buffer, status, NULL);
             lldbassert(status == lldb::eConnectionStatusInterrupted);
             return 0;
         }
Index: source/Core/ConnectionSharedMemory.cpp
===================================================================
--- source/Core/ConnectionSharedMemory.cpp
+++ source/Core/ConnectionSharedMemory.cpp
@@ -94,11 +94,8 @@
 }
 
 size_t
-ConnectionSharedMemory::Read (void *dst, 
-                              size_t dst_len, 
-                              uint32_t timeout_usec,
-                              ConnectionStatus &status, 
-                              Error *error_ptr)
+ConnectionSharedMemory::Read(void *dst, size_t dst_len, uint32_t timeout_usec, bool read_full_buffer,
+                             ConnectionStatus &status, Error *error_ptr)
 {
     status = eConnectionStatusSuccess;
     return 0;
Index: source/Core/Communication.cpp
===================================================================
--- source/Core/Communication.cpp
+++ source/Core/Communication.cpp
@@ -191,7 +191,8 @@
     lldb::ConnectionSP connection_sp (m_connection_sp);
     if (connection_sp)
     {
-        return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
+        const bool read_full_buffer = false;
+        return connection_sp->Read(dst, dst_len, timeout_usec, read_full_buffer, status, error_ptr);
     }
 
     if (error_ptr)
@@ -326,7 +327,8 @@
                                    Error *error_ptr)
 {
     lldb::ConnectionSP connection_sp(m_connection_sp);
-    return (connection_sp ? connection_sp->Read(dst, dst_len, timeout_usec, status, error_ptr) : 0);
+    const bool read_full_buffer = false;
+    return (connection_sp ? connection_sp->Read(dst, dst_len, read_full_buffer, timeout_usec, status, error_ptr) : 0);
 }
 
 bool
Index: include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
===================================================================
--- include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
+++ include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
@@ -59,7 +59,9 @@
 
     lldb::ConnectionStatus Disconnect(Error *error_ptr) override;
 
-    size_t Read(void *dst, size_t dst_len, uint32_t timeout_usec, lldb::ConnectionStatus &status, Error *error_ptr) override;
+    size_t
+    Read(void *dst, size_t dst_len, uint32_t timeout_usec, bool read_full_buffer, lldb::ConnectionStatus &status,
+         Error *error_ptr) override;
 
     size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr) override;
 
Index: include/lldb/Core/ConnectionSharedMemory.h
===================================================================
--- include/lldb/Core/ConnectionSharedMemory.h
+++ include/lldb/Core/ConnectionSharedMemory.h
@@ -43,11 +43,8 @@
     Disconnect (Error *error_ptr) override;
 
     size_t
-    Read (void *dst, 
-          size_t dst_len, 
-          uint32_t timeout_usec,
-          lldb::ConnectionStatus &status, 
-          Error *error_ptr) override;
+    Read(void *dst, size_t dst_len, uint32_t timeout_usec, bool read_full_buffer, lldb::ConnectionStatus &status,
+         Error *error_ptr) override;
 
     size_t
     Write (const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr) override;
Index: include/lldb/Core/Connection.h
===================================================================
--- include/lldb/Core/Connection.h
+++ include/lldb/Core/Connection.h
@@ -114,6 +114,14 @@
     /// @param[in] timeout_usec
     ///     The number of microseconds to wait for the data.
     ///
+    /// @param[in] read_full_buffer
+    ///     If true, continues reading until the specified number of bytes is
+    ///     read or some exceptional event occurs, which would prevent the
+    ///     buffer from being filled (timeout, end of file, I/O error, etc.).
+    ///     If false, the function returns as soon as at least some part of
+    ///     the data is available (traditional behavior of the read system
+    ///     call).
+    ///
     /// @param[out] status
     ///     On return, indicates whether the call was successful or terminated
     ///     due to some error condition.
@@ -129,11 +137,8 @@
     /// @see size_t Communication::Read (void *, size_t, uint32_t);
     //------------------------------------------------------------------
     virtual size_t
-    Read (void *dst, 
-          size_t dst_len, 
-          uint32_t timeout_usec,
-          lldb::ConnectionStatus &status, 
-          Error *error_ptr) = 0;
+    Read(void *dst, size_t dst_len, uint32_t timeout_usec, bool read_full_buffer, lldb::ConnectionStatus &status,
+         Error *error_ptr) = 0;
 
     //------------------------------------------------------------------
     /// The actual write function that attempts to write to the
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to