[Lldb-commits] [lldb] r278299 - Centralize all select() calls into one place so that we can take advantage of system specific optimizations to deal with more file descriptors than FD_SETSIZE on some systems.
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 10 15:43:49 PDT 2016
Author: gclayton
Date: Wed Aug 10 17:43:48 2016
New Revision: 278299
URL: http://llvm.org/viewvc/llvm-project?rev=278299&view=rev
Log:
Centralize all select() calls into one place so that we can take advantage of system specific optimizations to deal with more file descriptors than FD_SETSIZE on some systems.
<rdar://problem/25325383>
https://reviews.llvm.org/D22950
Added:
lldb/trunk/include/lldb/Utility/SelectHelper.h
lldb/trunk/source/Utility/SelectHelper.cpp
Modified:
lldb/trunk/lldb.xcodeproj/project.pbxproj
lldb/trunk/source/Host/common/Editline.cpp
lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
lldb/trunk/source/Host/posix/PipePosix.cpp
lldb/trunk/source/Target/Process.cpp
lldb/trunk/source/Utility/CMakeLists.txt
Added: lldb/trunk/include/lldb/Utility/SelectHelper.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Utility/SelectHelper.h?rev=278299&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Utility/SelectHelper.h (added)
+++ lldb/trunk/include/lldb/Utility/SelectHelper.h Wed Aug 10 17:43:48 2016
@@ -0,0 +1,90 @@
+//===-- SelectHelper.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SelectHelper_h_
+#define liblldb_SelectHelper_h_
+
+// C Includes
+// C++ Includes
+#include <chrono>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+
+// Project includes
+#include "lldb/lldb-forward.h"
+
+class SelectHelper
+{
+public:
+
+ // Defaults to infinite wait for select unless you call SetTimeout()
+ SelectHelper();
+
+ // Call SetTimeout() before calling SelectHelper::Select() to set the
+ // timeout based on the current time + the timeout. This allows multiple
+ // calls to SelectHelper::Select() without having to worry about the
+ // absolute timeout as this class manages to set the relative timeout
+ // correctly.
+ void SetTimeout(const std::chrono::microseconds &timeout);
+
+ // Call the FDSet*() functions before calling SelectHelper::Select() to
+ // set the file descriptors that we will watch for when calling
+ // select. This will cause FD_SET() to be called prior to calling select
+ // using the "fd" provided.
+ void FDSetRead(int fd);
+ void FDSetWrite(int fd);
+ void FDSetError(int fd);
+
+ // Call the FDIsSet*() functions after calling SelectHelper::Select()
+ // to check which file descriptors are ready for read/write/error. This
+ // will contain the result of FD_ISSET after calling select for a given
+ // file descriptor.
+ bool FDIsSetRead(int fd) const;
+ bool FDIsSetWrite(int fd) const;
+ bool FDIsSetError(int fd) const;
+
+ // Call the system's select() to wait for descriptors using
+ // timeout provided in a call the SelectHelper::SetTimeout(),
+ // or infinite wait if no timeout was set.
+ lldb_private::Error Select();
+protected:
+ struct FDInfo
+ {
+ FDInfo() :
+ read_set(false),
+ write_set(false),
+ error_set(false),
+ read_is_set(false),
+ write_is_set(false),
+ error_is_set(false)
+ {
+ }
+
+ void
+ PrepareForSelect()
+ {
+ read_is_set = false;
+ write_is_set = false;
+ error_is_set = false;
+ }
+
+ bool read_set : 1,
+ write_set : 1,
+ error_set : 1,
+ read_is_set : 1,
+ write_is_set : 1,
+ error_is_set : 1;
+ };
+ llvm::DenseMap<int, FDInfo> m_fd_map;
+ llvm::Optional<std::chrono::steady_clock::time_point> m_end_time;
+};
+
+#endif // liblldb_SelectHelper_h_
Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Wed Aug 10 17:43:48 2016
@@ -579,6 +579,7 @@
2697A54D133A6305004E4240 /* PlatformDarwin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2697A54B133A6305004E4240 /* PlatformDarwin.cpp */; };
2698699B15E6CBD0002415FF /* OperatingSystemPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2698699815E6CBD0002415FF /* OperatingSystemPython.cpp */; };
269DDD4A1B8FD1C300D0DBD8 /* DWARFASTParserClang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 269DDD481B8FD1C300D0DBD8 /* DWARFASTParserClang.cpp */; };
+ 26A375811D59462700D6CBDB /* SelectHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A3757F1D59462700D6CBDB /* SelectHelper.cpp */; };
26A527C114E24F5F00F3A14A /* ProcessMachCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A527BD14E24F5F00F3A14A /* ProcessMachCore.cpp */; };
26A527C314E24F5F00F3A14A /* ThreadMachCore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A527BF14E24F5F00F3A14A /* ThreadMachCore.cpp */; };
26A69C5F137A17A500262477 /* RegisterValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C6886E137880C400407EDF /* RegisterValue.cpp */; };
@@ -1562,7 +1563,6 @@
265ABF6210F42EE900531910 /* DebugSymbols.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DebugSymbols.framework; path = /System/Library/PrivateFrameworks/DebugSymbols.framework; sourceTree = "<absolute>"; };
265E9BE1115C2BAA00D0DCCB /* debugserver.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = debugserver.xcodeproj; path = tools/debugserver/debugserver.xcodeproj; sourceTree = "<group>"; };
2660D9F611922A1300958FBD /* StringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractor.cpp; path = source/Utility/StringExtractor.cpp; sourceTree = "<group>"; };
- 2660D9F711922A1300958FBD /* StringExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringExtractor.h; path = source/Utility/StringExtractor.h; sourceTree = "<group>"; };
2660D9FE11922A7F00958FBD /* ThreadPlanStepUntil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepUntil.cpp; path = source/Target/ThreadPlanStepUntil.cpp; sourceTree = "<group>"; };
26651A14133BEC76005B64B7 /* lldb-public.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-public.h"; path = "include/lldb/lldb-public.h"; sourceTree = "<group>"; };
26651A15133BF9CC005B64B7 /* Opcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Opcode.h; path = include/lldb/Core/Opcode.h; sourceTree = "<group>"; };
@@ -1838,6 +1838,9 @@
26A0604711A5BC7A00F75969 /* Baton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Baton.h; path = include/lldb/Core/Baton.h; sourceTree = "<group>"; };
26A0604811A5D03C00F75969 /* Baton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Baton.cpp; path = source/Core/Baton.cpp; sourceTree = "<group>"; };
26A0DA4D140F721D006DA411 /* HashedNameToDIE.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HashedNameToDIE.h; sourceTree = "<group>"; };
+ 26A3757F1D59462700D6CBDB /* SelectHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SelectHelper.cpp; path = source/Utility/SelectHelper.cpp; sourceTree = "<group>"; };
+ 26A375831D59486000D6CBDB /* StringExtractor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = StringExtractor.h; path = include/lldb/Utility/StringExtractor.h; sourceTree = "<group>"; };
+ 26A375841D59487700D6CBDB /* SelectHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SelectHelper.h; path = include/lldb/Utility/SelectHelper.h; sourceTree = "<group>"; };
26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectContainerBSDArchive.cpp; sourceTree = "<group>"; };
26A3B4AD1181454800381BC2 /* ObjectContainerBSDArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectContainerBSDArchive.h; sourceTree = "<group>"; };
26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = LLDBWrapPython.cpp; sourceTree = BUILT_PRODUCTS_DIR; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
@@ -3917,10 +3920,12 @@
2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */,
2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */,
4CAB257C18EC9DB800BAD33E /* SafeMachO.h */,
+ 26A375841D59487700D6CBDB /* SelectHelper.h */,
+ 26A3757F1D59462700D6CBDB /* SelectHelper.cpp */,
261B5A5211C3F2AD00AABD0A /* SharingPtr.cpp */,
4C2FAE2E135E3A70001EDE44 /* SharedCluster.h */,
261B5A5311C3F2AD00AABD0A /* SharingPtr.h */,
- 2660D9F711922A1300958FBD /* StringExtractor.h */,
+ 26A375831D59486000D6CBDB /* StringExtractor.h */,
2660D9F611922A1300958FBD /* StringExtractor.cpp */,
2676A094119C93C8008A98EF /* StringExtractorGDBRemote.h */,
2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */,
@@ -7232,6 +7237,7 @@
2698699B15E6CBD0002415FF /* OperatingSystemPython.cpp in Sources */,
947A1D641616476B0017C8D1 /* CommandObjectPlugin.cpp in Sources */,
2666ADC81B3CB675001FAFD3 /* HexagonDYLDRendezvous.cpp in Sources */,
+ 26A375811D59462700D6CBDB /* SelectHelper.cpp in Sources */,
AE44FB471BB4BB090033EB62 /* GoLanguage.cpp in Sources */,
262ED0081631FA3A00879631 /* OptionGroupString.cpp in Sources */,
94F48F251A01C687005C0EC6 /* StringPrinter.cpp in Sources */,
Modified: lldb/trunk/source/Host/common/Editline.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Editline.cpp?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Editline.cpp (original)
+++ lldb/trunk/source/Host/common/Editline.cpp Wed Aug 10 17:43:48 2016
@@ -20,6 +20,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/SelectHelper.h"
using namespace lldb_private;
using namespace lldb_private::line_editor;
@@ -155,11 +156,10 @@ IsInputPending (FILE * file)
// instead use some kind of yet-to-be-created abstraction that select-like functionality on
// non-socket objects.
const int fd = fileno (file);
- fd_set fds;
- FD_ZERO (&fds);
- FD_SET (fd, &fds);
- timeval timeout = { 0, 0 };
- return select (fd + 1, &fds, NULL, NULL, &timeout);
+ SelectHelper select_helper;
+ select_helper.SetTimeout(std::chrono::microseconds(0));
+ select_helper.FDSetRead(fd);
+ return select_helper.Select().Success();
}
namespace lldb_private
Modified: lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp (original)
+++ lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp Wed Aug 10 17:43:48 2016
@@ -20,6 +20,7 @@
#include "lldb/Host/SocketAddress.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/SelectHelper.h"
// C Includes
#include <errno.h>
@@ -572,7 +573,7 @@ ConnectionFileDescriptor::GetURI()
return m_uri;
}
-// This ConnectionFileDescriptor::BytesAvailable() uses select().
+// This ConnectionFileDescriptor::BytesAvailable() uses select() via SelectHelper
//
// PROS:
// - select is consistent across most unix platforms
@@ -586,11 +587,6 @@ ConnectionFileDescriptor::GetURI()
// be used or a new version of ConnectionFileDescriptor::BytesAvailable()
// should be written for the system that is running into the limitations.
-#if defined(__APPLE__)
-#define FD_SET_DATA(fds) fds.data()
-#else
-#define FD_SET_DATA(fds) &fds
-#endif
ConnectionStatus
ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr)
@@ -602,21 +598,6 @@ ConnectionFileDescriptor::BytesAvailable
if (log)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec);
- struct timeval *tv_ptr;
- struct timeval tv;
- if (timeout_usec == UINT32_MAX)
- {
- // Infinite wait...
- tv_ptr = nullptr;
- }
- else
- {
- TimeValue time_value;
- time_value.OffsetWithMicroSeconds(timeout_usec);
- tv.tv_sec = time_value.seconds();
- tv.tv_usec = time_value.microseconds();
- tv_ptr = &tv;
- }
// Make a copy of the file descriptors to make sure we don't
// have another thread change these values out from under us
@@ -624,8 +605,14 @@ ConnectionFileDescriptor::BytesAvailable
const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
const int pipe_fd = m_pipe.GetReadFileDescriptor();
+
if (handle != IOObject::kInvalidHandleValue)
{
+ SelectHelper select_helper;
+ if (timeout_usec != UINT32_MAX)
+ select_helper.SetTimeout(std::chrono::microseconds(timeout_usec));
+
+ select_helper.FDSetRead(handle);
#if defined(_MSC_VER)
// select() won't accept pipes on Windows. The entire Windows codepath needs to be
// converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
@@ -633,62 +620,14 @@ ConnectionFileDescriptor::BytesAvailable
const bool have_pipe_fd = false;
#else
const bool have_pipe_fd = pipe_fd >= 0;
-#if !defined(__APPLE__)
- assert(handle < FD_SETSIZE);
- if (have_pipe_fd)
- assert(pipe_fd < FD_SETSIZE);
-#endif
#endif
+ if (have_pipe_fd)
+ select_helper.FDSetRead(pipe_fd);
+
while (handle == m_read_sp->GetWaitableHandle())
{
- const int nfds = std::max<int>(handle, pipe_fd) + 1;
-#if defined(__APPLE__)
- llvm::SmallVector<fd_set, 1> read_fds;
- read_fds.resize((nfds / FD_SETSIZE) + 1);
- for (size_t i = 0; i < read_fds.size(); ++i)
- FD_ZERO(&read_fds[i]);
-// FD_SET doesn't bounds check, it just happily walks off the end
-// but we have taken care of making the extra storage with our
-// SmallVector of fd_set objects
-#else
- fd_set read_fds;
- FD_ZERO(&read_fds);
-#endif
- FD_SET(handle, FD_SET_DATA(read_fds));
- if (have_pipe_fd)
- FD_SET(pipe_fd, FD_SET_DATA(read_fds));
- Error error;
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf(
- "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
- static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr));
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
- static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr));
- }
-
- const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
- if (num_set_fds < 0)
- error.SetErrorToErrno();
- else
- error.Clear();
-
- if (log)
- {
- if (have_pipe_fd)
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) "
- "=> %d, error = %s",
- static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds,
- error.AsCString());
- else
- log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => "
- "%d, error = %s",
- static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString());
- }
+ Error error = select_helper.Select();
if (error_ptr)
*error_ptr = error;
@@ -704,6 +643,9 @@ ConnectionFileDescriptor::BytesAvailable
default: // Other unknown error
return eConnectionStatusError;
+ case ETIMEDOUT:
+ return eConnectionStatusTimedOut;
+
case EAGAIN: // The kernel was (perhaps temporarily) unable to
// allocate the requested number of file descriptors,
// or we have non-blocking IO
@@ -713,15 +655,12 @@ ConnectionFileDescriptor::BytesAvailable
break; // Lets keep reading to until we timeout
}
}
- else if (num_set_fds == 0)
- {
- return eConnectionStatusTimedOut;
- }
- else if (num_set_fds > 0)
+ else
{
- if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
+ if (select_helper.FDIsSetRead(handle))
return eConnectionStatusSuccess;
- if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
+
+ if (select_helper.FDIsSetRead(pipe_fd))
{
// There is an interrupt or exit command in the command pipe
// Read the data from that pipe:
Modified: lldb/trunk/source/Host/posix/PipePosix.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/posix/PipePosix.cpp?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/source/Host/posix/PipePosix.cpp (original)
+++ lldb/trunk/source/Host/posix/PipePosix.cpp Wed Aug 10 17:43:48 2016
@@ -10,6 +10,7 @@
#include "lldb/Host/posix/PipePosix.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/SelectHelper.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
@@ -65,73 +66,6 @@ Now()
return std::chrono::steady_clock::now();
}
-Error
-SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler, const std::chrono::microseconds &timeout)
-{
- Error error;
- fd_set fds;
- bool done = false;
-
- using namespace std::chrono;
-
- const auto finish_time = Now() + timeout;
-
- while (!done)
- {
- struct timeval tv = {0, 0};
- if (timeout != microseconds::zero())
- {
- const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
- if (remaining_dur.count() <= 0)
- {
- error.SetErrorString("timeout exceeded");
- break;
- }
- const auto dur_secs = duration_cast<seconds>(remaining_dur);
- const auto dur_usecs = remaining_dur % seconds(1);
-
- tv.tv_sec = dur_secs.count();
- tv.tv_usec = dur_usecs.count();
- }
- else
- tv.tv_sec = 1;
-
- FD_ZERO(&fds);
- FD_SET(handle, &fds);
-
- const auto retval = ::select(handle + 1,
- (is_read) ? &fds : nullptr,
- (is_read) ? nullptr : &fds,
- nullptr, &tv);
- if (retval == -1)
- {
- if (errno == EINTR)
- continue;
- error.SetErrorToErrno();
- break;
- }
- if (retval == 0)
- {
- error.SetErrorString("timeout exceeded");
- break;
- }
- if (!FD_ISSET(handle, &fds))
- {
- error.SetErrorString("invalid state");
- break;
- }
-
- error = io_handler(done);
- if (error.Fail())
- {
- if (error.GetError() == EINTR)
- continue;
- break;
- }
- }
- return error;
-}
-
}
PipePosix::PipePosix()
@@ -383,27 +317,33 @@ PipePosix::ReadWithTimeout(void *buf, si
if (!CanRead())
return Error(EINVAL, eErrorTypePOSIX);
- auto handle = GetReadFileDescriptor();
- return SelectIO(handle,
- true,
- [=, &bytes_read](bool &done)
- {
- Error error;
- auto result = ::read(handle,
- reinterpret_cast<char*>(buf) + bytes_read,
- size - bytes_read);
- if (result != -1)
- {
- bytes_read += result;
- if (bytes_read == size || result == 0)
- done = true;
- }
- else
- error.SetErrorToErrno();
-
- return error;
- },
- timeout);
+ const int fd = GetReadFileDescriptor();
+
+ SelectHelper select_helper;
+ select_helper.SetTimeout(timeout);
+ select_helper.FDSetRead(fd);
+
+ Error error;
+ while (error.Success())
+ {
+ error = select_helper.Select();
+ if (error.Success())
+ {
+ auto result = ::read(fd, reinterpret_cast<char*>(buf) + bytes_read, size - bytes_read);
+ if (result != -1)
+ {
+ bytes_read += result;
+ if (bytes_read == size || result == 0)
+ break;
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ break;
+ }
+ }
+ }
+ return error;
}
Error
@@ -413,25 +353,29 @@ PipePosix::Write(const void *buf, size_t
if (!CanWrite())
return Error(EINVAL, eErrorTypePOSIX);
- auto handle = GetWriteFileDescriptor();
- return SelectIO(handle,
- false,
- [=, &bytes_written](bool &done)
- {
- Error error;
- auto result = ::write(handle,
- reinterpret_cast<const char*>(buf) + bytes_written,
- size - bytes_written);
- if (result != -1)
- {
- bytes_written += result;
- if (bytes_written == size)
- done = true;
- }
- else
- error.SetErrorToErrno();
-
- return error;
- },
- std::chrono::microseconds::zero());
+ const int fd = GetWriteFileDescriptor();
+ SelectHelper select_helper;
+ select_helper.SetTimeout(std::chrono::seconds(0));
+ select_helper.FDSetWrite(fd);
+
+ Error error;
+ while (error.Success())
+ {
+ error = select_helper.Select();
+ if (error.Success())
+ {
+ auto result = ::write(fd, reinterpret_cast<const char*>(buf) + bytes_written, size - bytes_written);
+ if (result != -1)
+ {
+ bytes_written += result;
+ if (bytes_written == size)
+ break;
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ }
+ }
+ }
+ return error;
}
Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Wed Aug 10 17:43:48 2016
@@ -62,6 +62,7 @@
#include "lldb/Target/ThreadPlanBase.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/SelectHelper.h"
using namespace lldb;
using namespace lldb_private;
@@ -4925,25 +4926,20 @@ public:
m_is_running = true;
while (!GetIsDone())
{
- fd_set read_fdset;
- FD_ZERO (&read_fdset);
- FD_SET (read_fd, &read_fdset);
- FD_SET (pipe_read_fd, &read_fdset);
- const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1;
- int num_set_fds = select(nfds, &read_fdset, nullptr, nullptr, nullptr);
+ SelectHelper select_helper;
+ select_helper.FDSetRead(read_fd);
+ select_helper.FDSetRead(pipe_read_fd);
+ Error error = select_helper.Select();
- if (num_set_fds < 0)
+ if (error.Fail())
{
- const int select_errno = errno;
-
- if (select_errno != EINTR)
- SetIsDone(true);
+ SetIsDone(true);
}
- else if (num_set_fds > 0)
+ else
{
char ch = 0;
size_t n;
- if (FD_ISSET (read_fd, &read_fdset))
+ if (select_helper.FDIsSetRead(read_fd))
{
n = 1;
if (m_read_file.Read(&ch, n).Success() && n == 1)
@@ -4954,7 +4950,7 @@ public:
else
SetIsDone(true);
}
- if (FD_ISSET (pipe_read_fd, &read_fdset))
+ if (select_helper.FDIsSetRead(pipe_read_fd))
{
size_t bytes_read;
// Consume the interrupt byte
Modified: lldb/trunk/source/Utility/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/CMakeLists.txt?rev=278299&r1=278298&r2=278299&view=diff
==============================================================================
--- lldb/trunk/source/Utility/CMakeLists.txt (original)
+++ lldb/trunk/source/Utility/CMakeLists.txt Wed Aug 10 17:43:48 2016
@@ -10,6 +10,7 @@ add_lldb_library(lldbUtility
PseudoTerminal.cpp
Range.cpp
RegisterNumber.cpp
+ SelectHelper.cpp
SharingPtr.cpp
StringExtractor.cpp
StringExtractorGDBRemote.cpp
Added: lldb/trunk/source/Utility/SelectHelper.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/SelectHelper.cpp?rev=278299&view=auto
==============================================================================
--- lldb/trunk/source/Utility/SelectHelper.cpp (added)
+++ lldb/trunk/source/Utility/SelectHelper.cpp Wed Aug 10 17:43:48 2016
@@ -0,0 +1,294 @@
+//===-- SelectHelper.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(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+// C Includes
+#include <errno.h>
+#if defined(_WIN32)
+// Define NOMINMAX to avoid macros that conflict with std::min and std::max
+#define NOMINMAX
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+// C++ Includes
+#include <algorithm>
+
+// Other libraries and framework includes
+#include "llvm/ADT/SmallVector.h"
+
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+SelectHelper::SelectHelper() :
+ m_fd_map(),
+ m_end_time() // Infinite timeout unless SelectHelper::SetTimeout() gets called
+{
+}
+
+void
+SelectHelper::SetTimeout(const std::chrono::microseconds &timeout)
+{
+ using namespace std::chrono;
+ m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
+}
+
+void
+SelectHelper::FDSetRead(int fd)
+{
+ m_fd_map[fd].read_set = true;
+}
+
+void
+SelectHelper::FDSetWrite(int fd)
+{
+ m_fd_map[fd].write_set = true;
+}
+
+void
+SelectHelper::FDSetError(int fd)
+{
+ m_fd_map[fd].error_set = true;
+}
+
+bool
+SelectHelper::FDIsSetRead(int fd) const
+{
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.read_is_set;
+ else
+ return false;
+}
+
+bool
+SelectHelper::FDIsSetWrite(int fd) const
+{
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.write_is_set;
+ else
+ return false;
+}
+
+bool
+SelectHelper::FDIsSetError(int fd) const
+{
+ auto pos = m_fd_map.find(fd);
+ if (pos != m_fd_map.end())
+ return pos->second.error_is_set;
+ else
+ return false;
+}
+
+lldb_private::Error
+SelectHelper::Select()
+{
+ lldb_private::Error error;
+
+ int max_read_fd = -1;
+ int max_write_fd = -1;
+ int max_error_fd = -1;
+ int max_fd = -1;
+ for (auto &pair : m_fd_map)
+ {
+ pair.second.PrepareForSelect();
+ const int fd = pair.first;
+#if !defined(__APPLE__)
+ lldbassert(fd < FD_SETSIZE);
+ if (fd >= FD_SETSIZE)
+ {
+ error.SetErrorStringWithFormat("%i is too large for select()", fd);
+ return error;
+ }
+#endif
+ if (pair.second.read_set)
+ {
+ max_read_fd = std::max<int>(fd, max_read_fd);
+ max_fd = std::max<int>(fd, max_fd);
+ }
+ if (pair.second.write_set)
+ {
+ max_write_fd = std::max<int>(fd, max_write_fd);
+ max_fd = std::max<int>(fd, max_fd);
+ }
+ if (pair.second.error_set)
+ {
+ max_error_fd = std::max<int>(fd, max_error_fd);
+ max_fd = std::max<int>(fd, max_fd);
+ }
+ }
+
+ if (max_fd == -1)
+ {
+ error.SetErrorString("no valid file descriptors");
+ return error;
+ }
+
+ const int nfds = max_fd + 1;
+ fd_set *read_fdset_ptr = nullptr;
+ fd_set *write_fdset_ptr = nullptr;
+ fd_set *error_fdset_ptr = nullptr;
+ //----------------------------------------------------------------------
+ // Initialize and zero out the fdsets
+ //----------------------------------------------------------------------
+#if defined(__APPLE__)
+ llvm::SmallVector<fd_set, 1> read_fdset;
+ llvm::SmallVector<fd_set, 1> write_fdset;
+ llvm::SmallVector<fd_set, 1> error_fdset;
+
+ if (max_read_fd >= 0)
+ {
+ read_fdset.resize((nfds / FD_SETSIZE) + 1);
+ read_fdset_ptr = read_fdset.data();
+ }
+ if (max_write_fd >= 0)
+ {
+ write_fdset.resize((nfds / FD_SETSIZE) + 1);
+ write_fdset_ptr = write_fdset.data();
+ }
+ if (max_error_fd >= 0)
+ {
+ error_fdset.resize((nfds / FD_SETSIZE) + 1);
+ error_fdset_ptr = error_fdset.data();
+ }
+ for (auto &fd_set : read_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : write_fdset)
+ FD_ZERO(&fd_set);
+ for (auto &fd_set : error_fdset)
+ FD_ZERO(&fd_set);
+#else
+ fd_set read_fdset;
+ fd_set write_fdset;
+ fd_set error_fdset;
+
+ if (max_read_fd >= 0)
+ {
+ FD_ZERO(&read_fdset);
+ read_fdset_ptr = &read_fdset;
+ }
+ if (max_write_fd >= 0)
+ {
+ FD_ZERO(&write_fdset);
+ write_fdset_ptr = &write_fdset;
+ }
+ if (max_error_fd >= 0)
+ {
+ FD_ZERO(&error_fdset);
+ error_fdset_ptr = &error_fdset;
+ }
+#endif
+ //----------------------------------------------------------------------
+ // Set the FD bits in the fdsets for read/write/error
+ //----------------------------------------------------------------------
+ for (auto &pair : m_fd_map)
+ {
+ const int fd = pair.first;
+
+ if (pair.second.read_set)
+ FD_SET(fd, read_fdset_ptr);
+
+ if (pair.second.write_set)
+ FD_SET(fd, write_fdset_ptr);
+
+ if (pair.second.error_set)
+ FD_SET(fd, error_fdset_ptr);
+ }
+
+ //----------------------------------------------------------------------
+ // Setup our timeout time value if needed
+ //----------------------------------------------------------------------
+ struct timeval *tv_ptr = nullptr;
+ struct timeval tv = {0, 0};
+
+ while (1)
+ {
+ using namespace std::chrono;
+ //------------------------------------------------------------------
+ // Setup out relative timeout based on the end time if we have one
+ //------------------------------------------------------------------
+ if (m_end_time.hasValue())
+ {
+ tv_ptr = &tv;
+ const auto remaining_dur = duration_cast<microseconds>(m_end_time.getValue() - steady_clock::now());
+ if (remaining_dur.count() > 0)
+ {
+ // Wait for a specific amount of time
+ const auto dur_secs = duration_cast<seconds>(remaining_dur);
+ const auto dur_usecs = remaining_dur % seconds(1);
+ tv.tv_sec = dur_secs.count();
+ tv.tv_usec = dur_usecs.count();
+ }
+ else
+ {
+ // Just poll once with no timeout
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ }
+ const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, error_fdset_ptr, tv_ptr);
+ if (num_set_fds < 0)
+ {
+ // We got an error
+ error.SetErrorToErrno();
+ if (error.GetError() == EINTR)
+ {
+ error.Clear();
+ continue; // Keep calling select if we get EINTR
+ }
+ else
+ return error;
+ }
+ else if (num_set_fds == 0)
+ {
+ // Timeout
+ error.SetError(ETIMEDOUT, lldb::eErrorTypePOSIX);
+ error.SetErrorString("timed out");
+ return error;
+ }
+ else
+ {
+ // One or more descriptors were set, update the FDInfo::select_is_set mask
+ // so users can ask the SelectHelper class so clients can call one of:
+
+ for (auto &pair : m_fd_map)
+ {
+ const int fd = pair.first;
+
+ if (pair.second.read_set)
+ {
+ if (FD_ISSET(fd, read_fdset_ptr))
+ pair.second.read_is_set = true;
+ }
+ if (pair.second.write_set)
+ {
+ if (FD_ISSET(fd, write_fdset_ptr))
+ pair.second.write_is_set = true;
+ }
+ if (pair.second.error_set)
+ {
+ if (FD_ISSET(fd, error_fdset_ptr))
+ pair.second.error_is_set = true;
+ }
+ }
+ break;
+ }
+ }
+ return error;
+}
More information about the lldb-commits
mailing list