diff options
Diffstat (limited to 'source/Host/posix')
-rw-r--r-- | source/Host/posix/ConnectionFileDescriptorPosix.cpp | 1381 | ||||
-rw-r--r-- | source/Host/posix/DomainSocket.cpp | 141 | ||||
-rw-r--r-- | source/Host/posix/FileSystem.cpp | 401 | ||||
-rw-r--r-- | source/Host/posix/HostInfoPosix.cpp | 323 | ||||
-rw-r--r-- | source/Host/posix/HostProcessPosix.cpp | 122 | ||||
-rw-r--r-- | source/Host/posix/HostThreadPosix.cpp | 83 | ||||
-rw-r--r-- | source/Host/posix/LockFilePosix.cpp | 69 | ||||
-rw-r--r-- | source/Host/posix/MainLoopPosix.cpp | 295 | ||||
-rw-r--r-- | source/Host/posix/PipePosix.cpp | 541 | ||||
-rw-r--r-- | source/Host/posix/ProcessLauncherPosix.cpp | 21 |
10 files changed, 1498 insertions, 1879 deletions
diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 52d65b1e9a97..64101fdc4267 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -17,15 +17,16 @@ #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Host/Config.h" #include "lldb/Host/IOObject.h" -#include "lldb/Host/SocketAddress.h" #include "lldb/Host/Socket.h" +#include "lldb/Host/SocketAddress.h" #include "lldb/Host/StringConvert.h" +#include "lldb/Utility/SelectHelper.h" // C Includes #include <errno.h> #include <fcntl.h> -#include <string.h> #include <stdlib.h> +#include <string.h> #include <sys/types.h> #ifndef LLDB_DISABLE_POSIX @@ -53,526 +54,492 @@ using namespace lldb; using namespace lldb_private; -const char* ConnectionFileDescriptor::LISTEN_SCHEME = "listen"; -const char* ConnectionFileDescriptor::ACCEPT_SCHEME = "accept"; -const char* ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept"; -const char* ConnectionFileDescriptor::CONNECT_SCHEME = "connect"; -const char* ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect"; -const char* ConnectionFileDescriptor::UDP_SCHEME = "udp"; -const char* ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect"; -const char* ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = "unix-abstract-connect"; -const char* ConnectionFileDescriptor::FD_SCHEME = "fd"; -const char* ConnectionFileDescriptor::FILE_SCHEME = "file"; +const char *ConnectionFileDescriptor::LISTEN_SCHEME = "listen"; +const char *ConnectionFileDescriptor::ACCEPT_SCHEME = "accept"; +const char *ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept"; +const char *ConnectionFileDescriptor::CONNECT_SCHEME = "connect"; +const char *ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect"; +const char *ConnectionFileDescriptor::UDP_SCHEME = "udp"; +const char *ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect"; +const char *ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = + "unix-abstract-connect"; +const char *ConnectionFileDescriptor::FD_SCHEME = "fd"; +const char *ConnectionFileDescriptor::FILE_SCHEME = "file"; namespace { -const char* -GetURLAddress(const char *url, const char *scheme) -{ - const auto prefix = std::string(scheme) + "://"; - if (strstr(url, prefix.c_str()) != url) - return nullptr; - - return url + prefix.size(); +llvm::Optional<llvm::StringRef> GetURLAddress(llvm::StringRef url, + llvm::StringRef scheme) { + if (!url.consume_front(scheme)) + return llvm::None; + if (!url.consume_front("://")) + return llvm::None; + return url; } - } ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) - : Connection(), - m_pipe(), - m_mutex(), - m_shutting_down(false), + : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), m_waiting_for_accept(false), - m_child_processes_inherit(child_processes_inherit) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this)); + m_child_processes_inherit(child_processes_inherit) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | + LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", + static_cast<void *>(this)); } ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) - : Connection(), - m_pipe(), - m_mutex(), - m_shutting_down(false), - m_waiting_for_accept(false), - m_child_processes_inherit(false) -{ - m_write_sp.reset(new File(fd, owns_fd)); - m_read_sp.reset(new File(fd, false)); - - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", - static_cast<void *>(this), fd, owns_fd); - OpenCommandPipe(); + : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), + m_waiting_for_accept(false), m_child_processes_inherit(false) { + m_write_sp.reset(new File(fd, owns_fd)); + m_read_sp.reset(new File(fd, false)); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | + LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = " + "%i, owns_fd = %i)", + static_cast<void *>(this), fd, owns_fd); + OpenCommandPipe(); } ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket) - : Connection(), - m_pipe(), - m_mutex(), - m_shutting_down(false), - m_waiting_for_accept(false), - m_child_processes_inherit(false) -{ - InitializeSocket(socket); + : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), + m_waiting_for_accept(false), m_child_processes_inherit(false) { + InitializeSocket(socket); } -ConnectionFileDescriptor::~ConnectionFileDescriptor() -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this)); - Disconnect(NULL); - CloseCommandPipe(); +ConnectionFileDescriptor::~ConnectionFileDescriptor() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | + LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", + static_cast<void *>(this)); + Disconnect(NULL); + CloseCommandPipe(); } -void -ConnectionFileDescriptor::OpenCommandPipe() -{ - CloseCommandPipe(); - - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - // Make the command file descriptor here: - Error result = m_pipe.CreateNew(m_child_processes_inherit); - if (!result.Success()) - { - if (log) - log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this), - result.AsCString()); - } - else - { - if (log) - log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this), - m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); - } -} +void ConnectionFileDescriptor::OpenCommandPipe() { + CloseCommandPipe(); -void -ConnectionFileDescriptor::CloseCommandPipe() -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + // Make the command file descriptor here: + Error result = m_pipe.CreateNew(m_child_processes_inherit); + if (!result.Success()) { if (log) - log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this)); - - m_pipe.Close(); + log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not " + "make pipe: %s", + static_cast<void *>(this), result.AsCString()); + } else { + if (log) + log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success " + "readfd=%d writefd=%d", + static_cast<void *>(this), m_pipe.GetReadFileDescriptor(), + m_pipe.GetWriteFileDescriptor()); + } } -bool -ConnectionFileDescriptor::IsConnected() const -{ - return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid()); -} +void ConnectionFileDescriptor::CloseCommandPipe() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", + static_cast<void *>(this)); -ConnectionStatus -ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s); + m_pipe.Close(); +} - OpenCommandPipe(); +bool ConnectionFileDescriptor::IsConnected() const { + return (m_read_sp && m_read_sp->IsValid()) || + (m_write_sp && m_write_sp->IsValid()); +} - if (s && s[0]) - { - const char *addr = nullptr; - if ((addr = GetURLAddress(s, LISTEN_SCHEME))) - { - // listen://HOST:PORT - return SocketListenAndAccept(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, ACCEPT_SCHEME))) - { - // unix://SOCKNAME - return NamedSocketAccept(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, UNIX_ACCEPT_SCHEME))) - { - // unix://SOCKNAME - return NamedSocketAccept(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, CONNECT_SCHEME))) - { - return ConnectTCP(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, TCP_CONNECT_SCHEME))) - { - return ConnectTCP(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, UDP_SCHEME))) - { - return ConnectUDP(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, UNIX_CONNECT_SCHEME))) - { - // unix-connect://SOCKNAME - return NamedSocketConnect(addr, error_ptr); - } - else if ((addr = GetURLAddress(s, UNIX_ABSTRACT_CONNECT_SCHEME))) - { - // unix-abstract-connect://SOCKNAME - return UnixAbstractSocketConnect(addr, error_ptr); - } +ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, + Error *error_ptr) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", + static_cast<void *>(this), path.str().c_str()); + + OpenCommandPipe(); + + if (!path.empty()) { + llvm::Optional<llvm::StringRef> addr; + if ((addr = GetURLAddress(path, LISTEN_SCHEME))) { + // listen://HOST:PORT + return SocketListenAndAccept(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, ACCEPT_SCHEME))) { + // unix://SOCKNAME + return NamedSocketAccept(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, UNIX_ACCEPT_SCHEME))) { + // unix://SOCKNAME + return NamedSocketAccept(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, CONNECT_SCHEME))) { + return ConnectTCP(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, TCP_CONNECT_SCHEME))) { + return ConnectTCP(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, UDP_SCHEME))) { + return ConnectUDP(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, UNIX_CONNECT_SCHEME))) { + // unix-connect://SOCKNAME + return NamedSocketConnect(*addr, error_ptr); + } else if ((addr = GetURLAddress(path, UNIX_ABSTRACT_CONNECT_SCHEME))) { + // unix-abstract-connect://SOCKNAME + return UnixAbstractSocketConnect(*addr, error_ptr); + } #ifndef LLDB_DISABLE_POSIX - else if ((addr = GetURLAddress(s, FD_SCHEME))) - { - // Just passing a native file descriptor within this current process - // that is already opened (possibly from a service or other source). - bool success = false; - int fd = StringConvert::ToSInt32(addr, -1, 0, &success); - - if (success) - { - // We have what looks to be a valid file descriptor, but we - // should make sure it is. We currently are doing this by trying to - // get the flags from the file descriptor and making sure it - // isn't a bad fd. - errno = 0; - int flags = ::fcntl(fd, F_GETFL, 0); - if (flags == -1 || errno == EBADF) - { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s); - m_read_sp.reset(); - m_write_sp.reset(); - return eConnectionStatusError; - } - else - { - // Don't take ownership of a file descriptor that gets passed - // to us since someone else opened the file descriptor and - // handed it to us. - // TODO: Since are using a URL to open connection we should - // eventually parse options using the web standard where we - // have "fd://123?opt1=value;opt2=value" and we can have an - // option be "owns=1" or "owns=0" or something like this to - // allow us to specify this. For now, we assume we must - // assume we don't own it. - - std::unique_ptr<TCPSocket> tcp_socket; - tcp_socket.reset(new TCPSocket(fd, false)); - // Try and get a socket option from this file descriptor to - // see if this is a socket and set m_is_socket accordingly. - int resuse; - bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); - if (is_socket) - { - m_read_sp = std::move(tcp_socket); - m_write_sp = m_read_sp; - } - else - { - m_read_sp.reset(new File(fd, false)); - m_write_sp.reset(new File(fd, false)); - } - m_uri.assign(addr); - return eConnectionStatusSuccess; - } - } - - if (error_ptr) - error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", s); - m_read_sp.reset(); - m_write_sp.reset(); - return eConnectionStatusError; - } - else if ((addr = GetURLAddress(s, FILE_SCHEME))) - { - // file:///PATH - const char *path = addr; - int fd = -1; - do - { - fd = ::open(path, O_RDWR); - } while (fd == -1 && errno == EINTR); - - if (fd == -1) - { - if (error_ptr) - error_ptr->SetErrorToErrno(); - return eConnectionStatusError; - } - - if (::isatty(fd)) - { - // Set up serial terminal emulation - struct termios options; - ::tcgetattr(fd, &options); - - // Set port speed to maximum - ::cfsetospeed(&options, B115200); - ::cfsetispeed(&options, B115200); - - // Raw input, disable echo and signals - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - - // Make sure only one character is needed to return from a read - options.c_cc[VMIN] = 1; - options.c_cc[VTIME] = 0; - - ::tcsetattr(fd, TCSANOW, &options); - } - - int flags = ::fcntl(fd, F_GETFL, 0); - if (flags >= 0) - { - if ((flags & O_NONBLOCK) == 0) - { - flags |= O_NONBLOCK; - ::fcntl(fd, F_SETFL, flags); - } - } - m_read_sp.reset(new File(fd, true)); + else if ((addr = GetURLAddress(path, FD_SCHEME))) { + // Just passing a native file descriptor within this current process + // that is already opened (possibly from a service or other source). + int fd = -1; + + if (!addr->getAsInteger(0, fd)) { + // We have what looks to be a valid file descriptor, but we + // should make sure it is. We currently are doing this by trying to + // get the flags from the file descriptor and making sure it + // isn't a bad fd. + errno = 0; + int flags = ::fcntl(fd, F_GETFL, 0); + if (flags == -1 || errno == EBADF) { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", + path.str().c_str()); + m_read_sp.reset(); + m_write_sp.reset(); + return eConnectionStatusError; + } else { + // Don't take ownership of a file descriptor that gets passed + // to us since someone else opened the file descriptor and + // handed it to us. + // TODO: Since are using a URL to open connection we should + // eventually parse options using the web standard where we + // have "fd://123?opt1=value;opt2=value" and we can have an + // option be "owns=1" or "owns=0" or something like this to + // allow us to specify this. For now, we assume we must + // assume we don't own it. + + std::unique_ptr<TCPSocket> tcp_socket; + tcp_socket.reset(new TCPSocket(fd, false)); + // Try and get a socket option from this file descriptor to + // see if this is a socket and set m_is_socket accordingly. + int resuse; + bool is_socket = + !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); + if (is_socket) { + m_read_sp = std::move(tcp_socket); + m_write_sp = m_read_sp; + } else { + m_read_sp.reset(new File(fd, false)); m_write_sp.reset(new File(fd, false)); - return eConnectionStatusSuccess; + } + m_uri = *addr; + return eConnectionStatusSuccess; } -#endif + } + + if (error_ptr) + error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", + path.str().c_str()); + m_read_sp.reset(); + m_write_sp.reset(); + return eConnectionStatusError; + } else if ((addr = GetURLAddress(path, FILE_SCHEME))) { + std::string addr_str = addr->str(); + // file:///PATH + int fd = -1; + do { + fd = ::open(addr_str.c_str(), O_RDWR); + } while (fd == -1 && errno == EINTR); + + if (fd == -1) { if (error_ptr) - error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s); + error_ptr->SetErrorToErrno(); return eConnectionStatusError; - } - if (error_ptr) - error_ptr->SetErrorString("invalid connect arguments"); - return eConnectionStatusError; -} + } -bool -ConnectionFileDescriptor::InterruptRead() -{ - size_t bytes_written = 0; - Error result = m_pipe.Write("i", 1, bytes_written); - return result.Success(); -} - -ConnectionStatus -ConnectionFileDescriptor::Disconnect(Error *error_ptr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this)); - - ConnectionStatus status = eConnectionStatusSuccess; + if (::isatty(fd)) { + // Set up serial terminal emulation + struct termios options; + ::tcgetattr(fd, &options); - if (!IsConnected()) - { - if (log) - log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this)); - return eConnectionStatusSuccess; - } + // Set port speed to maximum + ::cfsetospeed(&options, B115200); + ::cfsetispeed(&options, B115200); - if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket) - static_cast<Socket &>(*m_read_sp).PreDisconnect(); + // Raw input, disable echo and signals + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely - // because somebody is doing a blocking read on our file descriptor. If that's the case, - // then send the "q" char to the command file channel so the read will wake up and the connection - // will then know to shut down. + // Make sure only one character is needed to return from a read + options.c_cc[VMIN] = 1; + options.c_cc[VTIME] = 0; - m_shutting_down = true; + ::tcsetattr(fd, TCSANOW, &options); + } - std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); - if (!locker.try_lock()) - { - if (m_pipe.CanWrite()) - { - size_t bytes_written = 0; - Error result = m_pipe.Write("q", 1, bytes_written); - if (log) - log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.", - static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString()); - } - else if (log) - { - log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", - static_cast<void *>(this)); + int flags = ::fcntl(fd, F_GETFL, 0); + if (flags >= 0) { + if ((flags & O_NONBLOCK) == 0) { + flags |= O_NONBLOCK; + ::fcntl(fd, F_SETFL, flags); } - locker.lock(); + } + m_read_sp.reset(new File(fd, true)); + m_write_sp.reset(new File(fd, false)); + return eConnectionStatusSuccess; } - - Error error = m_read_sp->Close(); - Error error2 = m_write_sp->Close(); - if (error.Fail() || error2.Fail()) - status = eConnectionStatusError; +#endif if (error_ptr) - *error_ptr = error.Fail() ? error : error2; - - // Close any pipes we were using for async interrupts - m_pipe.Close(); - - m_uri.clear(); - m_shutting_down = false; - return status; + error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", + path.str().c_str()); + return eConnectionStatusError; + } + if (error_ptr) + error_ptr->SetErrorString("invalid connect arguments"); + return eConnectionStatusError; } -size_t -ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - - std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); - if (!locker.try_lock()) - { - if (log) - log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this)); - if (error_ptr) - error_ptr->SetErrorString("failed to get the connection lock for read."); - - status = eConnectionStatusTimedOut; - return 0; - } - - if (m_shutting_down) - { - status = eConnectionStatusError; - return 0; - } +bool ConnectionFileDescriptor::InterruptRead() { + size_t bytes_written = 0; + Error result = m_pipe.Write("i", 1, bytes_written); + return result.Success(); +} - status = BytesAvailable(timeout_usec, error_ptr); - if (status != eConnectionStatusSuccess) - return 0; +ConnectionStatus ConnectionFileDescriptor::Disconnect(Error *error_ptr) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("%p ConnectionFileDescriptor::Disconnect ()", + static_cast<void *>(this)); - Error error; - size_t bytes_read = dst_len; - error = m_read_sp->Read(dst, bytes_read); + ConnectionStatus status = eConnectionStatusSuccess; + if (!IsConnected()) { if (log) - { - 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()); - } - - if (bytes_read == 0) - { - error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. - status = eConnectionStatusEndOfFile; - } - - if (error_ptr) - *error_ptr = error; - - if (error.Fail()) - { - uint32_t error_value = error.GetError(); - switch (error_value) - { - case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. - if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) - status = eConnectionStatusTimedOut; - else - status = eConnectionStatusSuccess; - return 0; - - case EFAULT: // Buf points outside the allocated address space. - case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. - case EINVAL: // The pointer associated with fildes was negative. - case EIO: // An I/O error occurred while reading from the file system. - // The process group is orphaned. - // The file is a regular file, nbyte is greater than 0, - // the starting position is before the end-of-file, and - // the starting position is greater than or equal to the - // offset maximum established for the open file - // descriptor associated with fildes. - case EISDIR: // An attempt is made to read a directory. - case ENOBUFS: // An attempt to allocate a memory buffer fails. - case ENOMEM: // Insufficient memory is available. - status = eConnectionStatusError; - break; // Break to close.... - - case ENOENT: // no such file or directory - case EBADF: // fildes is not a valid file or socket descriptor open for reading. - case ENXIO: // An action is requested of a device that does not exist.. - // A requested action cannot be performed by the device. - case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. - case ENOTCONN: // A read is attempted on an unconnected socket. - status = eConnectionStatusLostConnection; - break; // Break to close.... - - case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. - status = eConnectionStatusTimedOut; - return 0; - - default: - if (log) - log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this), - strerror(error_value)); - status = eConnectionStatusError; - break; // Break to close.... - } - - return 0; + log->Printf( + "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", + static_cast<void *>(this)); + return eConnectionStatusSuccess; + } + + if (m_read_sp && m_read_sp->IsValid() && + m_read_sp->GetFdType() == IOObject::eFDTypeSocket) + static_cast<Socket &>(*m_read_sp).PreDisconnect(); + + // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite + // likely + // because somebody is doing a blocking read on our file descriptor. If + // that's the case, + // then send the "q" char to the command file channel so the read will wake up + // and the connection + // will then know to shut down. + + m_shutting_down = true; + + std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); + if (!locker.try_lock()) { + if (m_pipe.CanWrite()) { + size_t bytes_written = 0; + Error result = m_pipe.Write("q", 1, bytes_written); + if (log) + log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get " + "the lock, sent 'q' to %d, error = '%s'.", + static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), + result.AsCString()); + } else if (log) { + log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the " + "lock, but no command pipe is available.", + static_cast<void *>(this)); } - return bytes_read; + locker.lock(); + } + + Error error = m_read_sp->Close(); + Error error2 = m_write_sp->Close(); + if (error.Fail() || error2.Fail()) + status = eConnectionStatusError; + if (error_ptr) + *error_ptr = error.Fail() ? error : error2; + + // Close any pipes we were using for async interrupts + m_pipe.Close(); + + m_uri.clear(); + m_shutting_down = false; + return status; } -size_t -ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this), - static_cast<const void *>(src), static_cast<uint64_t>(src_len)); - - if (!IsConnected()) - { - if (error_ptr) - error_ptr->SetErrorString("not connected"); - status = eConnectionStatusNoConnection; - return 0; - } - - Error error; - - size_t bytes_sent = src_len; - error = m_write_sp->Write(src, bytes_sent); +size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len, + const Timeout<std::micro> &timeout, + ConnectionStatus &status, + Error *error_ptr) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); + if (!locker.try_lock()) { if (log) - { - log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", - static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src), - static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString()); - } - + log->Printf("%p ConnectionFileDescriptor::Read () failed to get the " + "connection lock.", + static_cast<void *>(this)); if (error_ptr) - *error_ptr = error; + error_ptr->SetErrorString("failed to get the connection lock for read."); + + status = eConnectionStatusTimedOut; + return 0; + } + + if (m_shutting_down) { + status = eConnectionStatusError; + return 0; + } + + status = BytesAvailable(timeout, error_ptr); + if (status != eConnectionStatusSuccess) + return 0; + + Error error; + size_t bytes_read = dst_len; + error = m_read_sp->Read(dst, bytes_read); + + if (log) { + 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()); + } + + if (bytes_read == 0) { + error.Clear(); // End-of-file. Do not automatically close; pass along for + // the end-of-file handlers. + status = eConnectionStatusEndOfFile; + } + + if (error_ptr) + *error_ptr = error; + + if (error.Fail()) { + uint32_t error_value = error.GetError(); + switch (error_value) { + case EAGAIN: // The file was marked for non-blocking I/O, and no data were + // ready to be read. + if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) + status = eConnectionStatusTimedOut; + else + status = eConnectionStatusSuccess; + return 0; + + case EFAULT: // Buf points outside the allocated address space. + case EINTR: // A read from a slow device was interrupted before any data + // arrived by the delivery of a signal. + case EINVAL: // The pointer associated with fildes was negative. + case EIO: // An I/O error occurred while reading from the file system. + // The process group is orphaned. + // The file is a regular file, nbyte is greater than 0, + // the starting position is before the end-of-file, and + // the starting position is greater than or equal to the + // offset maximum established for the open file + // descriptor associated with fildes. + case EISDIR: // An attempt is made to read a directory. + case ENOBUFS: // An attempt to allocate a memory buffer fails. + case ENOMEM: // Insufficient memory is available. + status = eConnectionStatusError; + break; // Break to close.... + + case ENOENT: // no such file or directory + case EBADF: // fildes is not a valid file or socket descriptor open for + // reading. + case ENXIO: // An action is requested of a device that does not exist.. + // A requested action cannot be performed by the device. + case ECONNRESET: // The connection is closed by the peer during a read + // attempt on a socket. + case ENOTCONN: // A read is attempted on an unconnected socket. + status = eConnectionStatusLostConnection; + break; // Break to close.... + + case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a + // socket. + status = eConnectionStatusTimedOut; + return 0; + + default: + if (log) + log->Printf( + "%p ConnectionFileDescriptor::Read (), unexpected error: %s", + static_cast<void *>(this), strerror(error_value)); + status = eConnectionStatusError; + break; // Break to close.... + } - if (error.Fail()) - { - switch (error.GetError()) - { - case EAGAIN: - case EINTR: - status = eConnectionStatusSuccess; - return 0; - - case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. - case ENOTCONN: // A read is attempted on an unconnected socket. - status = eConnectionStatusLostConnection; - break; // Break to close.... - - default: - status = eConnectionStatusError; - break; // Break to close.... - } + return 0; + } + return bytes_read; +} - return 0; +size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len, + ConnectionStatus &status, + Error *error_ptr) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf( + "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", + static_cast<void *>(this), static_cast<const void *>(src), + static_cast<uint64_t>(src_len)); + + if (!IsConnected()) { + if (error_ptr) + error_ptr->SetErrorString("not connected"); + status = eConnectionStatusNoConnection; + return 0; + } + + Error error; + + size_t bytes_sent = src_len; + error = m_write_sp->Write(src, bytes_sent); + + if (log) { + log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 + ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 + " (error = %s)", + static_cast<void *>(this), + static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), + static_cast<const void *>(src), static_cast<uint64_t>(src_len), + static_cast<uint64_t>(bytes_sent), error.AsCString()); + } + + if (error_ptr) + *error_ptr = error; + + if (error.Fail()) { + switch (error.GetError()) { + case EAGAIN: + case EINTR: + status = eConnectionStatusSuccess; + return 0; + + case ECONNRESET: // The connection is closed by the peer during a read + // attempt on a socket. + case ENOTCONN: // A read is attempted on an unconnected socket. + status = eConnectionStatusLostConnection; + break; // Break to close.... + + default: + status = eConnectionStatusError; + break; // Break to close.... } - status = eConnectionStatusSuccess; - return bytes_sent; -} + return 0; + } -std::string -ConnectionFileDescriptor::GetURI() -{ - return m_uri; + status = eConnectionStatusSuccess; + return bytes_sent; } -// This ConnectionFileDescriptor::BytesAvailable() uses select(). +std::string ConnectionFileDescriptor::GetURI() { return m_uri; } + +// This ConnectionFileDescriptor::BytesAvailable() uses select() via +// SelectHelper // // PROS: // - select is consistent across most unix platforms @@ -586,326 +553,248 @@ 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() +ConnectionStatus +ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout, + Error *error_ptr) { + // Don't need to take the mutex here separately since we are only called from + // Read. If we + // ever get used more generally we will need to lock here as well. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf( + "%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %lu)", + static_cast<void *>(this), long(timeout ? timeout->count() : -1)); + + // Make a copy of the file descriptors to make sure we don't + // have another thread change these values out from under us + // and cause problems in the loop below where like in FS_SET() + const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); + const int pipe_fd = m_pipe.GetReadFileDescriptor(); + + if (handle != IOObject::kInvalidHandleValue) { + SelectHelper select_helper; + if (timeout) + select_helper.SetTimeout(*timeout); + + 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 + // this will allow ::select() to not return an error. + const bool have_pipe_fd = false; #else -#define FD_SET_DATA(fds) &fds + const bool have_pipe_fd = pipe_fd >= 0; #endif + if (have_pipe_fd) + select_helper.FDSetRead(pipe_fd); -ConnectionStatus -ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr) -{ - // Don't need to take the mutex here separately since we are only called from Read. If we - // ever get used more generally we will need to lock here as well. + while (handle == m_read_sp->GetWaitableHandle()) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION)); - 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) - { - // Inifinite 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; - } + Error error = select_helper.Select(); - // Make a copy of the file descriptors to make sure we don't - // have another thread change these values out from under us - // and cause problems in the loop below where like in FS_SET() - const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); - const int pipe_fd = m_pipe.GetReadFileDescriptor(); + if (error_ptr) + *error_ptr = error; - if (handle != IOObject::kInvalidHandleValue) - { -#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 - // this will allow ::select() to not return an error. - 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 - 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)); + if (error.Fail()) { + switch (error.GetError()) { + case EBADF: // One of the descriptor sets specified an invalid + // descriptor. + return eConnectionStatusLostConnection; + + case EINVAL: // The specified time limit is invalid. One of its + // components is negative or too large. + 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 + case EINTR: // A signal was delivered before the time limit + // expired and before any of the selected events + // occurred. + break; // Lets keep reading to until we timeout + } + } else { + if (select_helper.FDIsSetRead(handle)) + return eConnectionStatusSuccess; - Error error; + if (select_helper.FDIsSetRead(pipe_fd)) { + // There is an interrupt or exit command in the command pipe + // Read the data from that pipe: + char buffer[1]; - 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(); + ssize_t bytes_read; + + do { + bytes_read = ::read(pipe_fd, buffer, sizeof(buffer)); + } while (bytes_read < 0 && errno == EINTR); + switch (buffer[0]) { + case 'q': 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()); - } - - if (error_ptr) - *error_ptr = error; - - if (error.Fail()) - { - switch (error.GetError()) - { - case EBADF: // One of the descriptor sets specified an invalid descriptor. - return eConnectionStatusLostConnection; - - case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. - default: // Other unknown error - return eConnectionStatusError; - - case EAGAIN: // The kernel was (perhaps temporarily) unable to - // allocate the requested number of file descriptors, - // or we have non-blocking IO - case EINTR: // A signal was delivered before the time limit - // expired and before any of the selected events - // occurred. - break; // Lets keep reading to until we timeout - } - } - else if (num_set_fds == 0) - { - return eConnectionStatusTimedOut; - } - else if (num_set_fds > 0) - { - if (FD_ISSET(handle, FD_SET_DATA(read_fds))) - return eConnectionStatusSuccess; - if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds))) - { - // There is an interrupt or exit command in the command pipe - // Read the data from that pipe: - char buffer[1]; - - ssize_t bytes_read; - - do - { - bytes_read = ::read(pipe_fd, buffer, sizeof(buffer)); - } while (bytes_read < 0 && errno == EINTR); - - switch (buffer[0]) - { - case 'q': - if (log) - log->Printf("%p ConnectionFileDescriptor::BytesAvailable() " - "got data: %c from the command channel.", - static_cast<void *>(this), buffer[0]); - return eConnectionStatusEndOfFile; - case 'i': - // Interrupt the current read - return eConnectionStatusInterrupted; - } - } - } + log->Printf("%p ConnectionFileDescriptor::BytesAvailable() " + "got data: %c from the command channel.", + static_cast<void *>(this), buffer[0]); + return eConnectionStatusEndOfFile; + case 'i': + // Interrupt the current read + return eConnectionStatusInterrupted; + } } + } } + } - if (error_ptr) - error_ptr->SetErrorString("not connected"); - return eConnectionStatusLostConnection; + if (error_ptr) + error_ptr->SetErrorString("not connected"); + return eConnectionStatusLostConnection; } ConnectionStatus -ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr) -{ - Socket *socket = nullptr; - Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) - { - return eConnectionStatusError; - } - m_uri.assign(socket_name); - return eConnectionStatusSuccess; +ConnectionFileDescriptor::NamedSocketAccept(llvm::StringRef socket_name, + Error *error_ptr) { + Socket *socket = nullptr; + Error error = + Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + if (error.Fail()) { + return eConnectionStatusError; + } + m_uri.assign(socket_name); + return eConnectionStatusSuccess; } ConnectionStatus -ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr) -{ - Socket *socket = nullptr; - Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) - { - return eConnectionStatusError; - } - m_uri.assign(socket_name); - return eConnectionStatusSuccess; +ConnectionFileDescriptor::NamedSocketConnect(llvm::StringRef socket_name, + Error *error_ptr) { + Socket *socket = nullptr; + Error error = + Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + if (error.Fail()) { + return eConnectionStatusError; + } + m_uri.assign(socket_name); + return eConnectionStatusSuccess; } lldb::ConnectionStatus -ConnectionFileDescriptor::UnixAbstractSocketConnect(const char *socket_name, Error *error_ptr) -{ - Socket *socket = nullptr; - Error error = Socket::UnixAbstractConnect(socket_name, m_child_processes_inherit, socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) - { - return eConnectionStatusError; - } - m_uri.assign(socket_name); - return eConnectionStatusSuccess; +ConnectionFileDescriptor::UnixAbstractSocketConnect(llvm::StringRef socket_name, + Error *error_ptr) { + Socket *socket = nullptr; + Error error = Socket::UnixAbstractConnect(socket_name, + m_child_processes_inherit, socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + if (error.Fail()) { + return eConnectionStatusError; + } + m_uri.assign(socket_name); + return eConnectionStatusSuccess; } ConnectionStatus -ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr) -{ - m_port_predicate.SetValue(0, eBroadcastNever); - - Socket *socket = nullptr; - m_waiting_for_accept = true; - Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate); - if (error_ptr) - *error_ptr = error; - if (error.Fail()) - return eConnectionStatusError; +ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s, + Error *error_ptr) { + m_port_predicate.SetValue(0, eBroadcastNever); + + Socket *socket = nullptr; + m_waiting_for_accept = true; + Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, + &m_port_predicate); + if (error_ptr) + *error_ptr = error; + if (error.Fail()) + return eConnectionStatusError; - std::unique_ptr<Socket> listening_socket_up; + std::unique_ptr<Socket> listening_socket_up; - listening_socket_up.reset(socket); - socket = nullptr; - error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); - listening_socket_up.reset(); - if (error_ptr) - *error_ptr = error; - if (error.Fail()) - return eConnectionStatusError; + listening_socket_up.reset(socket); + socket = nullptr; + error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); + listening_socket_up.reset(); + if (error_ptr) + *error_ptr = error; + if (error.Fail()) + return eConnectionStatusError; - InitializeSocket(socket); - return eConnectionStatusSuccess; + InitializeSocket(socket); + return eConnectionStatusSuccess; } -ConnectionStatus -ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr) -{ - Socket *socket = nullptr; - Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - if (error.Fail()) - { - return eConnectionStatusError; - } - m_uri.assign(s); - return eConnectionStatusSuccess; +ConnectionStatus ConnectionFileDescriptor::ConnectTCP(llvm::StringRef s, + Error *error_ptr) { + Socket *socket = nullptr; + Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + if (error.Fail()) { + return eConnectionStatusError; + } + m_uri.assign(s); + return eConnectionStatusSuccess; } -ConnectionStatus -ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr) -{ - Socket *send_socket = nullptr; - Socket *recv_socket = nullptr; - Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket); - if (error_ptr) - *error_ptr = error; - m_write_sp.reset(send_socket); - m_read_sp.reset(recv_socket); - if (error.Fail()) - { - return eConnectionStatusError; - } - m_uri.assign(s); - return eConnectionStatusSuccess; +ConnectionStatus ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s, + Error *error_ptr) { + Socket *send_socket = nullptr; + Socket *recv_socket = nullptr; + Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, + recv_socket); + if (error_ptr) + *error_ptr = error; + m_write_sp.reset(send_socket); + m_read_sp.reset(recv_socket); + if (error.Fail()) { + return eConnectionStatusError; + } + m_uri.assign(s); + return eConnectionStatusSuccess; } -uint16_t -ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec) -{ - uint16_t bound_port = 0; - if (timeout_sec == UINT32_MAX) - m_port_predicate.WaitForValueNotEqualTo(0, bound_port); - else - { - TimeValue timeout = TimeValue::Now(); - timeout.OffsetWithSeconds(timeout_sec); - m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout); - } - return bound_port; +uint16_t ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec) { + uint16_t bound_port = 0; + if (timeout_sec == UINT32_MAX) + m_port_predicate.WaitForValueNotEqualTo(0, bound_port); + else + m_port_predicate.WaitForValueNotEqualTo(0, bound_port, + std::chrono::seconds(timeout_sec)); + return bound_port; } -bool -ConnectionFileDescriptor::GetChildProcessesInherit() const -{ - return m_child_processes_inherit; +bool ConnectionFileDescriptor::GetChildProcessesInherit() const { + return m_child_processes_inherit; } -void -ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit) -{ - m_child_processes_inherit = child_processes_inherit; +void ConnectionFileDescriptor::SetChildProcessesInherit( + bool child_processes_inherit) { + m_child_processes_inherit = child_processes_inherit; } -void -ConnectionFileDescriptor::InitializeSocket(Socket* socket) -{ - assert(socket->GetSocketProtocol() == Socket::ProtocolTcp); - TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket); - - m_write_sp.reset(socket); - m_read_sp = m_write_sp; - StreamString strm; - strm.Printf("connect://%s:%u",tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber()); - m_uri.swap(strm.GetString()); +void ConnectionFileDescriptor::InitializeSocket(Socket *socket) { + assert(socket->GetSocketProtocol() == Socket::ProtocolTcp); + TCPSocket *tcp_socket = static_cast<TCPSocket *>(socket); + + m_write_sp.reset(socket); + m_read_sp = m_write_sp; + StreamString strm; + strm.Printf("connect://%s:%u", tcp_socket->GetRemoteIPAddress().c_str(), + tcp_socket->GetRemotePortNumber()); + m_uri = strm.GetString(); } diff --git a/source/Host/posix/DomainSocket.cpp b/source/Host/posix/DomainSocket.cpp index 9dc147196c08..cb0a1d057506 100644 --- a/source/Host/posix/DomainSocket.cpp +++ b/source/Host/posix/DomainSocket.cpp @@ -21,113 +21,100 @@ using namespace lldb_private; #ifdef __ANDROID__ // Android does not have SUN_LEN #ifndef SUN_LEN -#define SUN_LEN(ptr) (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) +#define SUN_LEN(ptr) \ + (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) #endif #endif // #ifdef __ANDROID__ namespace { const int kDomain = AF_UNIX; -const int kType = SOCK_STREAM; +const int kType = SOCK_STREAM; -bool SetSockAddr(llvm::StringRef name, - const size_t name_offset, - sockaddr_un* saddr_un, - socklen_t& saddr_un_len) -{ - if (name.size() + name_offset > sizeof(saddr_un->sun_path)) - return false; +bool SetSockAddr(llvm::StringRef name, const size_t name_offset, + sockaddr_un *saddr_un, socklen_t &saddr_un_len) { + if (name.size() + name_offset > sizeof(saddr_un->sun_path)) + return false; - memset(saddr_un, 0, sizeof(*saddr_un)); - saddr_un->sun_family = kDomain; + memset(saddr_un, 0, sizeof(*saddr_un)); + saddr_un->sun_family = kDomain; - memcpy(saddr_un->sun_path + name_offset, name.data(), name.size()); + memcpy(saddr_un->sun_path + name_offset, name.data(), name.size()); - // For domain sockets we can use SUN_LEN in order to calculate size of - // sockaddr_un, but for abstract sockets we have to calculate size manually - // because of leading null symbol. - if (name_offset == 0) - saddr_un_len = SUN_LEN(saddr_un); - else - saddr_un_len = offsetof(struct sockaddr_un, sun_path) + name_offset + name.size(); + // For domain sockets we can use SUN_LEN in order to calculate size of + // sockaddr_un, but for abstract sockets we have to calculate size manually + // because of leading null symbol. + if (name_offset == 0) + saddr_un_len = SUN_LEN(saddr_un); + else + saddr_un_len = + offsetof(struct sockaddr_un, sun_path) + name_offset + name.size(); #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - saddr_un->sun_len = saddr_un_len; + saddr_un->sun_len = saddr_un_len; #endif - return true; + return true; } - } DomainSocket::DomainSocket(NativeSocket socket) - : Socket(socket, ProtocolUnixDomain, true) -{ -} + : Socket(socket, ProtocolUnixDomain, true) {} DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) - : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) -{ -} - -DomainSocket::DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error) - : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), protocol, true) -{ -} - -Error -DomainSocket::Connect(llvm::StringRef name) -{ - sockaddr_un saddr_un; - socklen_t saddr_un_len; - if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) - return Error("Failed to set socket address"); - - Error error; - if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < 0) - SetLastError (error); + : DomainSocket( + CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} + +DomainSocket::DomainSocket(SocketProtocol protocol, + bool child_processes_inherit, Error &error) + : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), + protocol, true) {} + +Error DomainSocket::Connect(llvm::StringRef name) { + sockaddr_un saddr_un; + socklen_t saddr_un_len; + if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) + return Error("Failed to set socket address"); + + Error error; + if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < + 0) + SetLastError(error); - return error; + return error; } -Error -DomainSocket::Listen(llvm::StringRef name, int backlog) -{ - sockaddr_un saddr_un; - socklen_t saddr_un_len; - if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) - return Error("Failed to set socket address"); +Error DomainSocket::Listen(llvm::StringRef name, int backlog) { + sockaddr_un saddr_un; + socklen_t saddr_un_len; + if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) + return Error("Failed to set socket address"); - DeleteSocketFile(name); + DeleteSocketFile(name); - Error error; - if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 0) - if (::listen(GetNativeSocket(), backlog) == 0) - return error; + Error error; + if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == + 0) + if (::listen(GetNativeSocket(), backlog) == 0) + return error; - SetLastError(error); - return error; + SetLastError(error); + return error; } -Error -DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error); - if (error.Success()) - socket = new DomainSocket(conn_fd); +Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + Error error; + auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, + child_processes_inherit, error); + if (error.Success()) + socket = new DomainSocket(conn_fd); - return error; + return error; } -size_t -DomainSocket::GetNameOffset() const -{ - return 0; -} +size_t DomainSocket::GetNameOffset() const { return 0; } -void -DomainSocket::DeleteSocketFile(llvm::StringRef name) -{ - FileSystem::Unlink(FileSpec{name, true}); +void DomainSocket::DeleteSocketFile(llvm::StringRef name) { + FileSystem::Unlink(FileSpec{name, true}); } diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp index c8fa1bc9cf47..aaa53ce07723 100644 --- a/source/Host/posix/FileSystem.cpp +++ b/source/Host/posix/FileSystem.cpp @@ -16,9 +16,9 @@ #include <sys/stat.h> #include <sys/types.h> #ifdef __linux__ -#include <sys/statfs.h> -#include <sys/mount.h> #include <linux/magic.h> +#include <sys/mount.h> +#include <sys/statfs.h> #endif #if defined(__NetBSD__) #include <sys/statvfs.h> @@ -32,282 +32,231 @@ using namespace lldb; using namespace lldb_private; -const char * -FileSystem::DEV_NULL = "/dev/null"; +const char *FileSystem::DEV_NULL = "/dev/null"; -FileSpec::PathSyntax -FileSystem::GetNativePathSyntax() -{ - return FileSpec::ePathSyntaxPosix; +FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { + return FileSpec::ePathSyntaxPosix; } -Error -FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) -{ - if (file_spec) - { - Error error; - if (::mkdir(file_spec.GetCString(), file_permissions) == -1) - { - error.SetErrorToErrno(); - errno = 0; - switch (error.GetError()) - { - case ENOENT: - { - // Parent directory doesn't exist, so lets make it if we can - // Make the parent directory and try again - FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false}; - error = MakeDirectory(parent_file_spec, file_permissions); - if (error.Fail()) - return error; - // Try and make the directory again now that the parent directory was made successfully - if (::mkdir(file_spec.GetCString(), file_permissions) == -1) - { - error.SetErrorToErrno(); - } - return error; - } - break; - case EEXIST: - { - if (file_spec.IsDirectory()) - return Error(); // It is a directory and it already exists - } - break; - } +Error FileSystem::MakeDirectory(const FileSpec &file_spec, + uint32_t file_permissions) { + if (file_spec) { + Error error; + if (::mkdir(file_spec.GetCString(), file_permissions) == -1) { + error.SetErrorToErrno(); + errno = 0; + switch (error.GetError()) { + case ENOENT: { + // Parent directory doesn't exist, so lets make it if we can + // Make the parent directory and try again + FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false}; + error = MakeDirectory(parent_file_spec, file_permissions); + if (error.Fail()) + return error; + // Try and make the directory again now that the parent directory was + // made successfully + if (::mkdir(file_spec.GetCString(), file_permissions) == -1) { + error.SetErrorToErrno(); } return error; + } break; + case EEXIST: { + if (file_spec.IsDirectory()) + return Error(); // It is a directory and it already exists + } break; + } } - return Error("empty path"); + return error; + } + return Error("empty path"); } -Error -FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) -{ - Error error; - if (file_spec) - { - if (recurse) - { - // Save all sub directories in a list so we don't recursively call this function - // and possibly run out of file descriptors if the directory is too deep. - std::vector<FileSpec> sub_directories; - - FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult { - if (file_type == FileSpec::eFileTypeDirectory) - { - // Save all directorires and process them after iterating through this directory - sub_directories.push_back(spec); - } - else - { - // Update sub_spec to point to the current file and delete it - error = FileSystem::Unlink(spec); - } - // If anything went wrong, stop iterating, else process the next file - if (error.Fail()) - return FileSpec::eEnumerateDirectoryResultQuit; - else - return FileSpec::eEnumerateDirectoryResultNext; - }); +Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) { + Error error; + if (file_spec) { + if (recurse) { + // Save all sub directories in a list so we don't recursively call this + // function + // and possibly run out of file descriptors if the directory is too deep. + std::vector<FileSpec> sub_directories; - if (error.Success()) - { - // Now delete all sub directories with separate calls that aren't - // recursively calling into this function _while_ this function is - // iterating through the current directory. - for (const auto &sub_directory : sub_directories) - { - error = DeleteDirectory(sub_directory, recurse); - if (error.Fail()) - break; - } + FileSpec::ForEachItemInDirectory( + file_spec.GetCString(), + [&error, &sub_directories]( + FileSpec::FileType file_type, + const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult { + if (file_type == FileSpec::eFileTypeDirectory) { + // Save all directorires and process them after iterating through + // this directory + sub_directories.push_back(spec); + } else { + // Update sub_spec to point to the current file and delete it + error = FileSystem::Unlink(spec); } - } + // If anything went wrong, stop iterating, else process the next + // file + if (error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; + else + return FileSpec::eEnumerateDirectoryResultNext; + }); - if (error.Success()) - { - if (::rmdir(file_spec.GetCString()) != 0) - error.SetErrorToErrno(); + if (error.Success()) { + // Now delete all sub directories with separate calls that aren't + // recursively calling into this function _while_ this function is + // iterating through the current directory. + for (const auto &sub_directory : sub_directories) { + error = DeleteDirectory(sub_directory, recurse); + if (error.Fail()) + break; } + } } - else - { - error.SetErrorString("empty path"); - } - return error; -} -Error -FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) -{ - Error error; - struct stat file_stats; - if (::stat(file_spec.GetCString(), &file_stats) == 0) - { - // The bits in "st_mode" currently match the definitions - // for the file mode bits in unix. - file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - } - else - { + if (error.Success()) { + if (::rmdir(file_spec.GetCString()) != 0) error.SetErrorToErrno(); } - return error; + } else { + error.SetErrorString("empty path"); + } + return error; } -Error -FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) -{ - Error error; - if (::chmod(file_spec.GetCString(), file_permissions) != 0) - error.SetErrorToErrno(); - return error; +Error FileSystem::GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions) { + Error error; + struct stat file_stats; + if (::stat(file_spec.GetCString(), &file_stats) == 0) { + // The bits in "st_mode" currently match the definitions + // for the file mode bits in unix. + file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } else { + error.SetErrorToErrno(); + } + return error; } -lldb::user_id_t -FileSystem::GetFileSize(const FileSpec &file_spec) -{ - return file_spec.GetByteSize(); +Error FileSystem::SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions) { + Error error; + if (::chmod(file_spec.GetCString(), file_permissions) != 0) + error.SetErrorToErrno(); + return error; } -bool -FileSystem::GetFileExists(const FileSpec &file_spec) -{ - return file_spec.Exists(); +lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { + return file_spec.GetByteSize(); } -Error -FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) -{ - Error error; - if (::link(dst.GetCString(), src.GetCString()) == -1) - error.SetErrorToErrno(); - return error; +bool FileSystem::GetFileExists(const FileSpec &file_spec) { + return file_spec.Exists(); } -int -FileSystem::GetHardlinkCount(const FileSpec &file_spec) -{ - struct stat file_stat; - if (::stat(file_spec.GetCString(), &file_stat) == 0) - return file_stat.st_nlink; +Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { + Error error; + if (::link(dst.GetCString(), src.GetCString()) == -1) + error.SetErrorToErrno(); + return error; +} + +int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { + struct stat file_stat; + if (::stat(file_spec.GetCString(), &file_stat) == 0) + return file_stat.st_nlink; - return -1; + return -1; } -Error -FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) -{ - Error error; - if (::symlink(dst.GetCString(), src.GetCString()) == -1) - error.SetErrorToErrno(); - return error; +Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { + Error error; + if (::symlink(dst.GetCString(), src.GetCString()) == -1) + error.SetErrorToErrno(); + return error; } -Error -FileSystem::Unlink(const FileSpec &file_spec) -{ - Error error; - if (::unlink(file_spec.GetCString()) == -1) - error.SetErrorToErrno(); - return error; +Error FileSystem::Unlink(const FileSpec &file_spec) { + Error error; + if (::unlink(file_spec.GetCString()) == -1) + error.SetErrorToErrno(); + return error; } -Error -FileSystem::Readlink(const FileSpec &src, FileSpec &dst) -{ - Error error; - char buf[PATH_MAX]; - ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1); - if (count < 0) - error.SetErrorToErrno(); - else - { - buf[count] = '\0'; // Success - dst.SetFile(buf, false); - } - return error; +Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { + Error error; + char buf[PATH_MAX]; + ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1); + if (count < 0) + error.SetErrorToErrno(); + else { + buf[count] = '\0'; // Success + dst.SetFile(buf, false); + } + return error; } -Error -FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) -{ - char resolved_path[PATH_MAX]; - if (!src.GetPath (resolved_path, sizeof (resolved_path))) - { - return Error("Couldn't get the canonical path for %s", src.GetCString()); - } - - char real_path[PATH_MAX + 1]; - if (realpath(resolved_path, real_path) == nullptr) - { - Error err; - err.SetErrorToErrno(); - return err; - } - - dst = FileSpec(real_path, false); - - return Error(); +Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { + char resolved_path[PATH_MAX]; + if (!src.GetPath(resolved_path, sizeof(resolved_path))) { + return Error("Couldn't get the canonical path for %s", src.GetCString()); + } + + char real_path[PATH_MAX + 1]; + if (realpath(resolved_path, real_path) == nullptr) { + Error err; + err.SetErrorToErrno(); + return err; + } + + dst = FileSpec(real_path, false); + + return Error(); } #if defined(__NetBSD__) -static bool IsLocal(const struct statvfs& info) -{ - return (info.f_flag & MNT_LOCAL) != 0; +static bool IsLocal(const struct statvfs &info) { + return (info.f_flag & MNT_LOCAL) != 0; } #else -static bool IsLocal(const struct statfs& info) -{ +static bool IsLocal(const struct statfs &info) { #ifdef __linux__ - #define CIFS_MAGIC_NUMBER 0xFF534D42 - switch ((uint32_t)info.f_type) - { - case NFS_SUPER_MAGIC: - case SMB_SUPER_MAGIC: - case CIFS_MAGIC_NUMBER: - return false; - default: - return true; - } +#define CIFS_MAGIC_NUMBER 0xFF534D42 + switch ((uint32_t)info.f_type) { + case NFS_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + case CIFS_MAGIC_NUMBER: + return false; + default: + return true; + } #else - return (info.f_flags & MNT_LOCAL) != 0; + return (info.f_flags & MNT_LOCAL) != 0; #endif } #endif #if defined(__NetBSD__) -bool -FileSystem::IsLocal(const FileSpec &spec) -{ - struct statvfs statfs_info; - std::string path (spec.GetPath()); - if (statvfs(path.c_str(), &statfs_info) == 0) - return ::IsLocal(statfs_info); - return false; +bool FileSystem::IsLocal(const FileSpec &spec) { + struct statvfs statfs_info; + std::string path(spec.GetPath()); + if (statvfs(path.c_str(), &statfs_info) == 0) + return ::IsLocal(statfs_info); + return false; } #else -bool -FileSystem::IsLocal(const FileSpec &spec) -{ - struct statfs statfs_info; - std::string path (spec.GetPath()); - if (statfs(path.c_str(), &statfs_info) == 0) - return ::IsLocal(statfs_info); - return false; +bool FileSystem::IsLocal(const FileSpec &spec) { + struct statfs statfs_info; + std::string path(spec.GetPath()); + if (statfs(path.c_str(), &statfs_info) == 0) + return ::IsLocal(statfs_info); + return false; } #endif -FILE * -FileSystem::Fopen(const char *path, const char *mode) -{ - return ::fopen(path, mode); +FILE *FileSystem::Fopen(const char *path, const char *mode) { + return ::fopen(path, mode); } -int -FileSystem::Stat(const char *path, struct stat *stats) -{ - return ::stat(path, stats); +int FileSystem::Stat(const char *path, struct stat *stats) { + return ::stat(path, stats); } diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp index d0ef2ca37061..38aac59ecc40 100644 --- a/source/Host/posix/HostInfoPosix.cpp +++ b/source/Host/posix/HostInfoPosix.cpp @@ -14,7 +14,11 @@ #include "lldb/Core/Log.h" #include "lldb/Host/posix/HostInfoPosix.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <grp.h> @@ -28,30 +32,23 @@ using namespace lldb_private; -size_t -HostInfoPosix::GetPageSize() -{ - return ::getpagesize(); -} +size_t HostInfoPosix::GetPageSize() { return ::getpagesize(); } -bool -HostInfoPosix::GetHostname(std::string &s) -{ - char hostname[PATH_MAX]; - hostname[sizeof(hostname) - 1] = '\0'; - if (::gethostname(hostname, sizeof(hostname) - 1) == 0) - { - struct hostent *h = ::gethostbyname(hostname); - if (h) - s.assign(h->h_name); - else - s.assign(hostname); - return true; - } - return false; +bool HostInfoPosix::GetHostname(std::string &s) { + char hostname[PATH_MAX]; + hostname[sizeof(hostname) - 1] = '\0'; + if (::gethostname(hostname, sizeof(hostname) - 1) == 0) { + struct hostent *h = ::gethostbyname(hostname); + if (h) + s.assign(h->h_name); + else + s.assign(hostname); + return true; + } + return false; } -#ifdef __ANDROID_NDK__ +#ifdef __ANDROID__ #include <android/api-level.h> #endif #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 @@ -62,194 +59,174 @@ HostInfoPosix::GetHostname(std::string &s) static std::mutex s_getpwuid_lock; #endif -const char * -HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name) -{ +const char *HostInfoPosix::LookupUserName(uint32_t uid, + std::string &user_name) { #ifdef USE_GETPWUID - // getpwuid_r is missing from android-9 - // make getpwuid thread safe with a mutex - std::lock_guard<std::mutex> lock(s_getpwuid_lock); - struct passwd *user_info_ptr = ::getpwuid(uid); - if (user_info_ptr) - { - user_name.assign(user_info_ptr->pw_name); - return user_name.c_str(); - } + // getpwuid_r is missing from android-9 + // make getpwuid thread safe with a mutex + std::lock_guard<std::mutex> lock(s_getpwuid_lock); + struct passwd *user_info_ptr = ::getpwuid(uid); + if (user_info_ptr) { + user_name.assign(user_info_ptr->pw_name); + return user_name.c_str(); + } #else - struct passwd user_info; - struct passwd *user_info_ptr = &user_info; - char user_buffer[PATH_MAX]; - size_t user_buffer_size = sizeof(user_buffer); - if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size, &user_info_ptr) == 0) - { - if (user_info_ptr) - { - user_name.assign(user_info_ptr->pw_name); - return user_name.c_str(); - } + struct passwd user_info; + struct passwd *user_info_ptr = &user_info; + char user_buffer[PATH_MAX]; + size_t user_buffer_size = sizeof(user_buffer); + if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size, + &user_info_ptr) == 0) { + if (user_info_ptr) { + user_name.assign(user_info_ptr->pw_name); + return user_name.c_str(); } + } #endif - user_name.clear(); - return nullptr; + user_name.clear(); + return nullptr; } -const char * -HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name) -{ +const char *HostInfoPosix::LookupGroupName(uint32_t gid, + std::string &group_name) { #ifndef __ANDROID__ - char group_buffer[PATH_MAX]; - size_t group_buffer_size = sizeof(group_buffer); - struct group group_info; - struct group *group_info_ptr = &group_info; - // Try the threadsafe version first - if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size, &group_info_ptr) == 0) - { - if (group_info_ptr) - { - group_name.assign(group_info_ptr->gr_name); - return group_name.c_str(); - } + char group_buffer[PATH_MAX]; + size_t group_buffer_size = sizeof(group_buffer); + struct group group_info; + struct group *group_info_ptr = &group_info; + // Try the threadsafe version first + if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size, + &group_info_ptr) == 0) { + if (group_info_ptr) { + group_name.assign(group_info_ptr->gr_name); + return group_name.c_str(); } - else - { - // The threadsafe version isn't currently working for me on darwin, but the non-threadsafe version - // is, so I am calling it below. - group_info_ptr = ::getgrgid(gid); - if (group_info_ptr) - { - group_name.assign(group_info_ptr->gr_name); - return group_name.c_str(); - } + } else { + // The threadsafe version isn't currently working for me on darwin, but the + // non-threadsafe version + // is, so I am calling it below. + group_info_ptr = ::getgrgid(gid); + if (group_info_ptr) { + group_name.assign(group_info_ptr->gr_name); + return group_name.c_str(); } - group_name.clear(); + } + group_name.clear(); #else - assert(false && "getgrgid_r() not supported on Android"); + assert(false && "getgrgid_r() not supported on Android"); #endif - return NULL; + return NULL; } -uint32_t -HostInfoPosix::GetUserID() -{ - return getuid(); -} +uint32_t HostInfoPosix::GetUserID() { return getuid(); } -uint32_t -HostInfoPosix::GetGroupID() -{ - return getgid(); -} +uint32_t HostInfoPosix::GetGroupID() { return getgid(); } -uint32_t -HostInfoPosix::GetEffectiveUserID() -{ - return geteuid(); -} +uint32_t HostInfoPosix::GetEffectiveUserID() { return geteuid(); } -uint32_t -HostInfoPosix::GetEffectiveGroupID() -{ - return getegid(); -} +uint32_t HostInfoPosix::GetEffectiveGroupID() { return getegid(); } -FileSpec -HostInfoPosix::GetDefaultShell() -{ - return FileSpec("/bin/sh", false); -} +FileSpec HostInfoPosix::GetDefaultShell() { return FileSpec("/bin/sh", false); } + +bool HostInfoPosix::ComputePathRelativeToLibrary(FileSpec &file_spec, + llvm::StringRef dir) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); -bool -HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + FileSpec lldb_file_spec; + if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec)) + return false; + + std::string raw_path = lldb_file_spec.GetPath(); + // drop library directory + llvm::StringRef parent_path = llvm::sys::path::parent_path(raw_path); - FileSpec lldb_file_spec; - if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec)) - return false; + // Most Posix systems (e.g. Linux/*BSD) will attempt to replace a */lib with + // */bin as the base directory for helper exe programs. This will fail if the + // /lib and /bin directories are rooted in entirely different trees. + if (log) + log->Printf("HostInfoPosix::ComputePathRelativeToLibrary() attempting to " + "derive the %s path from this path: %s", + dir.data(), raw_path.c_str()); - char raw_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); + if (!parent_path.empty()) { + // Now write in bin in place of lib. + raw_path = (parent_path + dir).str(); - // Most Posix systems (e.g. Linux/*BSD) will attempt to replace a */lib with */bin as the base - // directory for helper exe programs. This will fail if the /lib and /bin directories are - // rooted in entirely different trees. if (log) - log->Printf("HostInfoPosix::ComputeSupportExeDirectory() attempting to derive the bin path (ePathTypeSupportExecutableDir) from " - "this path: %s", - raw_path); - char *lib_pos = ::strstr(raw_path, "/lib"); - if (lib_pos != nullptr) - { - // Now write in bin in place of lib. - ::snprintf(lib_pos, PATH_MAX - (lib_pos - raw_path), "/bin"); - - if (log) - log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__, raw_path); - } - else - { - if (log) - log->Printf("Host::%s() failed to find /lib/liblldb within the shared lib path, bailing on bin path construction", - __FUNCTION__); - } - file_spec.GetDirectory().SetCString(raw_path); - return (bool)file_spec.GetDirectory(); + log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__, + raw_path.c_str()); + } else { + if (log) + log->Printf("Host::%s() failed to find /lib/liblldb within the shared " + "lib path, bailing on bin path construction", + __FUNCTION__); + } + file_spec.GetDirectory().SetString(raw_path); + return (bool)file_spec.GetDirectory(); } -bool -HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) -{ - FileSpec temp_file("/opt/local/include/lldb", false); - file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); - return true; +bool HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec) { + return ComputePathRelativeToLibrary(file_spec, "/bin"); } -bool -HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec) -{ -#ifndef LLDB_DISABLE_PYTHON - FileSpec lldb_file_spec; - if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec)) - return false; +bool HostInfoPosix::ComputeClangDirectory(FileSpec &file_spec) { + return ComputePathRelativeToLibrary( + file_spec, (llvm::Twine("/lib") + CLANG_LIBDIR_SUFFIX + "/clang/" + + CLANG_VERSION_STRING) + .str()); +} - char raw_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); +bool HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec) { + FileSpec temp_file("/opt/local/include/lldb", false); + file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); + return true; +} -#if defined(LLDB_PYTHON_RELATIVE_LIBDIR) - // Build the path by backing out of the lib dir, then building - // with whatever the real python interpreter uses. (e.g. lib - // for most, lib64 on RHEL x86_64). - char python_path[PATH_MAX]; - ::snprintf(python_path, sizeof(python_path), "%s/../%s", raw_path, LLDB_PYTHON_RELATIVE_LIBDIR); +bool HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec) { +#ifndef LLDB_DISABLE_PYTHON + FileSpec lldb_file_spec; + if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec)) + return false; - char final_path[PATH_MAX]; - realpath(python_path, final_path); - file_spec.GetDirectory().SetCString(final_path); + char raw_path[PATH_MAX]; + lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); - return true; +#if defined(LLDB_PYTHON_RELATIVE_LIBDIR) + // Build the path by backing out of the lib dir, then building + // with whatever the real python interpreter uses. (e.g. lib + // for most, lib64 on RHEL x86_64). + char python_path[PATH_MAX]; + ::snprintf(python_path, sizeof(python_path), "%s/../%s", raw_path, + LLDB_PYTHON_RELATIVE_LIBDIR); + + char final_path[PATH_MAX]; + realpath(python_path, final_path); + file_spec.GetDirectory().SetCString(final_path); + + return true; #else - llvm::SmallString<256> python_version_dir; - llvm::raw_svector_ostream os(python_version_dir); - os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages"; + llvm::SmallString<256> python_version_dir; + llvm::raw_svector_ostream os(python_version_dir); + os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION + << "/site-packages"; - // We may get our string truncated. Should we protect this with an assert? - ::strncat(raw_path, python_version_dir.c_str(), sizeof(raw_path) - strlen(raw_path) - 1); + // We may get our string truncated. Should we protect this with an assert? + ::strncat(raw_path, python_version_dir.c_str(), + sizeof(raw_path) - strlen(raw_path) - 1); - file_spec.GetDirectory().SetCString(raw_path); - return true; + file_spec.GetDirectory().SetCString(raw_path); + return true; #endif #else - return false; + return false; #endif } -bool -HostInfoPosix::GetEnvironmentVar(const std::string &var_name, std::string &var) -{ - if (const char *pvar = ::getenv(var_name.c_str())) - { - var = std::string(pvar); - return true; - } - return false; +bool HostInfoPosix::GetEnvironmentVar(const std::string &var_name, + std::string &var) { + if (const char *pvar = ::getenv(var_name.c_str())) { + var = std::string(pvar); + return true; + } + return false; } diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp index 93844d9b99d3..9dd9fef94cdb 100644 --- a/source/Host/posix/HostProcessPosix.cpp +++ b/source/Host/posix/HostProcessPosix.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Host.h" -#include "lldb/Host/posix/HostProcessPosix.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/posix/HostProcessPosix.h" #include "llvm/ADT/STLExtras.h" @@ -17,97 +17,77 @@ using namespace lldb_private; -namespace -{ - const int kInvalidPosixProcess = 0; +namespace { +const int kInvalidPosixProcess = 0; } HostProcessPosix::HostProcessPosix() - : HostNativeProcessBase(kInvalidPosixProcess) -{ -} + : HostNativeProcessBase(kInvalidPosixProcess) {} HostProcessPosix::HostProcessPosix(lldb::process_t process) - : HostNativeProcessBase(process) -{ -} + : HostNativeProcessBase(process) {} -HostProcessPosix::~HostProcessPosix() -{ -} +HostProcessPosix::~HostProcessPosix() {} -Error HostProcessPosix::Signal(int signo) const -{ - if (m_process == kInvalidPosixProcess) - { - Error error; - error.SetErrorString("HostProcessPosix refers to an invalid process"); - return error; - } +Error HostProcessPosix::Signal(int signo) const { + if (m_process == kInvalidPosixProcess) { + Error error; + error.SetErrorString("HostProcessPosix refers to an invalid process"); + return error; + } - return HostProcessPosix::Signal(m_process, signo); + return HostProcessPosix::Signal(m_process, signo); } -Error HostProcessPosix::Signal(lldb::process_t process, int signo) -{ - Error error; +Error HostProcessPosix::Signal(lldb::process_t process, int signo) { + Error error; - if (-1 == ::kill(process, signo)) - error.SetErrorToErrno(); + if (-1 == ::kill(process, signo)) + error.SetErrorToErrno(); - return error; + return error; } -Error HostProcessPosix::Terminate() -{ - return Signal(SIGKILL); -} +Error HostProcessPosix::Terminate() { return Signal(SIGKILL); } -Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const -{ - Error error; +Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const { + Error error; - // Use special code here because proc/[pid]/exe is a symbolic link. - char link_path[PATH_MAX]; - if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_process) != 1) - { - error.SetErrorString("Unable to build /proc/<pid>/exe string"); - return error; - } - - error = FileSystem::Readlink(FileSpec{link_path, false}, file_spec); - if (!error.Success()) - return error; - - // If the binary has been deleted, the link name has " (deleted)" appended. - // Remove if there. - if (file_spec.GetFilename().GetStringRef().endswith(" (deleted)")) - { - const char *filename = file_spec.GetFilename().GetCString(); - static const size_t deleted_len = strlen(" (deleted)"); - const size_t len = file_spec.GetFilename().GetLength(); - file_spec.GetFilename().SetCStringWithLength(filename, len - deleted_len); - } + // Use special code here because proc/[pid]/exe is a symbolic link. + char link_path[PATH_MAX]; + if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_process) != 1) { + error.SetErrorString("Unable to build /proc/<pid>/exe string"); return error; -} + } -lldb::pid_t HostProcessPosix::GetProcessId() const -{ - return m_process; + error = FileSystem::Readlink(FileSpec{link_path, false}, file_spec); + if (!error.Success()) + return error; + + // If the binary has been deleted, the link name has " (deleted)" appended. + // Remove if there. + if (file_spec.GetFilename().GetStringRef().endswith(" (deleted)")) { + const char *filename = file_spec.GetFilename().GetCString(); + static const size_t deleted_len = strlen(" (deleted)"); + const size_t len = file_spec.GetFilename().GetLength(); + file_spec.GetFilename().SetCStringWithLength(filename, len - deleted_len); + } + return error; } -bool HostProcessPosix::IsRunning() const -{ - if (m_process == kInvalidPosixProcess) - return false; +lldb::pid_t HostProcessPosix::GetProcessId() const { return m_process; } + +bool HostProcessPosix::IsRunning() const { + if (m_process == kInvalidPosixProcess) + return false; - // Send this process the null signal. If it succeeds the process is running. - Error error = Signal(0); - return error.Success(); + // Send this process the null signal. If it succeeds the process is running. + Error error = Signal(0); + return error.Success(); } -HostThread -HostProcessPosix::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) -{ - return Host::StartMonitoringChildProcess(callback, m_process, monitor_signals); +HostThread HostProcessPosix::StartMonitoring( + const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { + return Host::StartMonitoringChildProcess(callback, m_process, + monitor_signals); } diff --git a/source/Host/posix/HostThreadPosix.cpp b/source/Host/posix/HostThreadPosix.cpp index f1a6d6f83142..ac398998c20f 100644 --- a/source/Host/posix/HostThreadPosix.cpp +++ b/source/Host/posix/HostThreadPosix.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/Error.h" #include "lldb/Host/posix/HostThreadPosix.h" +#include "lldb/Core/Error.h" #include <errno.h> #include <pthread.h> @@ -16,67 +16,50 @@ using namespace lldb; using namespace lldb_private; -HostThreadPosix::HostThreadPosix() -{ -} +HostThreadPosix::HostThreadPosix() {} HostThreadPosix::HostThreadPosix(lldb::thread_t thread) - : HostNativeThreadBase(thread) -{ -} + : HostNativeThreadBase(thread) {} -HostThreadPosix::~HostThreadPosix() -{ -} +HostThreadPosix::~HostThreadPosix() {} -Error -HostThreadPosix::Join(lldb::thread_result_t *result) -{ - Error error; - if (IsJoinable()) - { - int err = ::pthread_join(m_thread, result); - error.SetError(err, lldb::eErrorTypePOSIX); - } - else - { - if (result) - *result = NULL; - error.SetError(EINVAL, eErrorTypePOSIX); - } +Error HostThreadPosix::Join(lldb::thread_result_t *result) { + Error error; + if (IsJoinable()) { + int err = ::pthread_join(m_thread, result); + error.SetError(err, lldb::eErrorTypePOSIX); + } else { + if (result) + *result = NULL; + error.SetError(EINVAL, eErrorTypePOSIX); + } - Reset(); - return error; + Reset(); + return error; } -Error -HostThreadPosix::Cancel() -{ - Error error; - if (IsJoinable()) - { +Error HostThreadPosix::Cancel() { + Error error; + if (IsJoinable()) { #ifndef __ANDROID__ #ifndef __FreeBSD__ - assert(false && "someone is calling HostThread::Cancel()"); + assert(false && "someone is calling HostThread::Cancel()"); #endif - int err = ::pthread_cancel(m_thread); - error.SetError(err, eErrorTypePOSIX); + int err = ::pthread_cancel(m_thread); + error.SetError(err, eErrorTypePOSIX); #else - error.SetErrorString("HostThreadPosix::Cancel() not supported on Android"); + error.SetErrorString("HostThreadPosix::Cancel() not supported on Android"); #endif - } - return error; + } + return error; } -Error -HostThreadPosix::Detach() -{ - Error error; - if (IsJoinable()) - { - int err = ::pthread_detach(m_thread); - error.SetError(err, eErrorTypePOSIX); - } - Reset(); - return error; +Error HostThreadPosix::Detach() { + Error error; + if (IsJoinable()) { + int err = ::pthread_detach(m_thread); + error.SetError(err, eErrorTypePOSIX); + } + Reset(); + return error; } diff --git a/source/Host/posix/LockFilePosix.cpp b/source/Host/posix/LockFilePosix.cpp index e52b648799b7..d1cc617146d0 100644 --- a/source/Host/posix/LockFilePosix.cpp +++ b/source/Host/posix/LockFilePosix.cpp @@ -14,64 +14,47 @@ using namespace lldb; using namespace lldb_private; -namespace -{ +namespace { -Error fileLock (int fd, int cmd, int lock_type, const uint64_t start, const uint64_t len) -{ - struct flock fl; +Error fileLock(int fd, int cmd, int lock_type, const uint64_t start, + const uint64_t len) { + struct flock fl; - fl.l_type = lock_type; - fl.l_whence = SEEK_SET; - fl.l_start = start; - fl.l_len = len; - fl.l_pid = ::getpid (); + fl.l_type = lock_type; + fl.l_whence = SEEK_SET; + fl.l_start = start; + fl.l_len = len; + fl.l_pid = ::getpid(); - Error error; - if (::fcntl (fd, cmd, &fl) == -1) - error.SetErrorToErrno (); + Error error; + if (::fcntl(fd, cmd, &fl) == -1) + error.SetErrorToErrno(); - return error; + return error; } -} // namespace +} // namespace -LockFilePosix::LockFilePosix (int fd) - : LockFileBase (fd) -{ -} +LockFilePosix::LockFilePosix(int fd) : LockFileBase(fd) {} -LockFilePosix::~LockFilePosix () -{ - Unlock (); -} +LockFilePosix::~LockFilePosix() { Unlock(); } -Error -LockFilePosix::DoWriteLock (const uint64_t start, const uint64_t len) -{ - return fileLock (m_fd, F_SETLKW, F_WRLCK, start, len); +Error LockFilePosix::DoWriteLock(const uint64_t start, const uint64_t len) { + return fileLock(m_fd, F_SETLKW, F_WRLCK, start, len); } -Error -LockFilePosix::DoTryWriteLock (const uint64_t start, const uint64_t len) -{ - return fileLock (m_fd, F_SETLK, F_WRLCK, start, len); +Error LockFilePosix::DoTryWriteLock(const uint64_t start, const uint64_t len) { + return fileLock(m_fd, F_SETLK, F_WRLCK, start, len); } -Error -LockFilePosix::DoReadLock (const uint64_t start, const uint64_t len) -{ - return fileLock (m_fd, F_SETLKW, F_RDLCK, start, len); +Error LockFilePosix::DoReadLock(const uint64_t start, const uint64_t len) { + return fileLock(m_fd, F_SETLKW, F_RDLCK, start, len); } -Error -LockFilePosix::DoTryReadLock (const uint64_t start, const uint64_t len) -{ - return fileLock (m_fd, F_SETLK, F_RDLCK, start, len); +Error LockFilePosix::DoTryReadLock(const uint64_t start, const uint64_t len) { + return fileLock(m_fd, F_SETLK, F_RDLCK, start, len); } -Error -LockFilePosix::DoUnlock () -{ - return fileLock (m_fd, F_SETLK, F_UNLCK, m_start, m_len); +Error LockFilePosix::DoUnlock() { + return fileLock(m_fd, F_SETLK, F_UNLCK, m_start, m_len); } diff --git a/source/Host/posix/MainLoopPosix.cpp b/source/Host/posix/MainLoopPosix.cpp index 897f2d13c0c6..08c969e72a26 100644 --- a/source/Host/posix/MainLoopPosix.cpp +++ b/source/Host/posix/MainLoopPosix.cpp @@ -8,186 +8,175 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/posix/MainLoopPosix.h" - -#include <vector> - #include "lldb/Core/Error.h" +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <csignal> +#include <vector> +#include <sys/select.h> using namespace lldb; using namespace lldb_private; static sig_atomic_t g_signal_flags[NSIG]; -static void -SignalHandler(int signo, siginfo_t *info, void *) -{ - assert(signo < NSIG); - g_signal_flags[signo] = 1; +static void SignalHandler(int signo, siginfo_t *info, void *) { + assert(signo < NSIG); + g_signal_flags[signo] = 1; } - -MainLoopPosix::~MainLoopPosix() -{ - assert(m_read_fds.size() == 0); - assert(m_signals.size() == 0); +MainLoopPosix::~MainLoopPosix() { + assert(m_read_fds.size() == 0); + assert(m_signals.size() == 0); } MainLoopPosix::ReadHandleUP -MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error) -{ - if (!object_sp || !object_sp->IsValid()) - { - error.SetErrorString("IO object is not valid."); - return nullptr; - } - - const bool inserted = m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; - if (! inserted) - { - error.SetErrorStringWithFormat("File descriptor %d already monitored.", - object_sp->GetWaitableHandle()); - return nullptr; - } - - return CreateReadHandle(object_sp); +MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, + const Callback &callback, Error &error) { + if (!object_sp || !object_sp->IsValid()) { + error.SetErrorString("IO object is not valid."); + return nullptr; + } + + const bool inserted = + m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; + if (!inserted) { + error.SetErrorStringWithFormat("File descriptor %d already monitored.", + object_sp->GetWaitableHandle()); + return nullptr; + } + + return CreateReadHandle(object_sp); } -// We shall block the signal, then install the signal handler. The signal will be unblocked in +// We shall block the signal, then install the signal handler. The signal will +// be unblocked in // the Run() function to check for signal delivery. MainLoopPosix::SignalHandleUP -MainLoopPosix::RegisterSignal(int signo, const Callback &callback, Error &error) -{ - if (m_signals.find(signo) != m_signals.end()) - { - error.SetErrorStringWithFormat("Signal %d already monitored.", signo); - return nullptr; - } +MainLoopPosix::RegisterSignal(int signo, const Callback &callback, + Error &error) { + if (m_signals.find(signo) != m_signals.end()) { + error.SetErrorStringWithFormat("Signal %d already monitored.", signo); + return nullptr; + } + + SignalInfo info; + info.callback = callback; + struct sigaction new_action; + new_action.sa_sigaction = &SignalHandler; + new_action.sa_flags = SA_SIGINFO; + sigemptyset(&new_action.sa_mask); + sigaddset(&new_action.sa_mask, signo); + + sigset_t old_set; + if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) { + error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", + ret); + return nullptr; + } + + info.was_blocked = sigismember(&old_set, signo); + if (sigaction(signo, &new_action, &info.old_action) == -1) { + error.SetErrorToErrno(); + if (!info.was_blocked) + pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); + return nullptr; + } + + m_signals.insert({signo, info}); + g_signal_flags[signo] = 0; + + return SignalHandleUP(new SignalHandle(*this, signo)); +} - SignalInfo info; - info.callback = callback; - struct sigaction new_action; - new_action.sa_sigaction = &SignalHandler; - new_action.sa_flags = SA_SIGINFO; - sigemptyset(&new_action.sa_mask); - sigaddset(&new_action.sa_mask, signo); - - sigset_t old_set; - if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) - { - error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", ret); - return nullptr; - } +void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) { + bool erased = m_read_fds.erase(handle); + UNUSED_IF_ASSERT_DISABLED(erased); + assert(erased); +} - info.was_blocked = sigismember(&old_set, signo); - if (sigaction(signo, &new_action, &info.old_action) == -1) - { - error.SetErrorToErrno(); - if (!info.was_blocked) - pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); - return nullptr; - } +void MainLoopPosix::UnregisterSignal(int signo) { + // We undo the actions of RegisterSignal on a best-effort basis. + auto it = m_signals.find(signo); + assert(it != m_signals.end()); - m_signals.insert({signo, info}); - g_signal_flags[signo] = 0; + sigaction(signo, &it->second.old_action, nullptr); - return SignalHandleUP(new SignalHandle(*this, signo)); -} + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signo); + pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, + nullptr); -void -MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) -{ - bool erased = m_read_fds.erase(handle); - UNUSED_IF_ASSERT_DISABLED(erased); - assert(erased); + m_signals.erase(it); } -void -MainLoopPosix::UnregisterSignal(int signo) -{ - // We undo the actions of RegisterSignal on a best-effort basis. - auto it = m_signals.find(signo); - assert(it != m_signals.end()); +Error MainLoopPosix::Run() { + std::vector<int> signals; + sigset_t sigmask; + std::vector<int> read_fds; + fd_set read_fd_set; + m_terminate_request = false; + + // run until termination or until we run out of things to listen to + while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { + // To avoid problems with callbacks changing the things we're supposed to + // listen to, we + // will store the *real* list of events separately. + signals.clear(); + read_fds.clear(); + FD_ZERO(&read_fd_set); + int nfds = 0; + + if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) + return Error("pthread_sigmask failed with error %d\n", ret); + + for (const auto &fd : m_read_fds) { + read_fds.push_back(fd.first); + FD_SET(fd.first, &read_fd_set); + nfds = std::max(nfds, fd.first + 1); + } + + for (const auto &sig : m_signals) { + signals.push_back(sig.first); + sigdelset(&sigmask, sig.first); + } - sigaction(signo, &it->second.old_action, nullptr); + if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == + -1 && + errno != EINTR) + return Error(errno, eErrorTypePOSIX); - sigset_t set; - sigemptyset(&set); - sigaddset(&set, signo); - pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, nullptr); + for (int sig : signals) { + if (g_signal_flags[sig] == 0) + continue; // No signal + g_signal_flags[sig] = 0; - m_signals.erase(it); -} + auto it = m_signals.find(sig); + if (it == m_signals.end()) + continue; // Signal must have gotten unregistered in the meantime -Error -MainLoopPosix::Run() -{ - std::vector<int> signals; - sigset_t sigmask; - std::vector<int> read_fds; - fd_set read_fd_set; - m_terminate_request = false; - - // run until termination or until we run out of things to listen to - while (! m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) - { - // To avoid problems with callbacks changing the things we're supposed to listen to, we - // will store the *real* list of events separately. - signals.clear(); - read_fds.clear(); - FD_ZERO(&read_fd_set); - int nfds = 0; - - if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) - return Error("pthread_sigmask failed with error %d\n", ret); - - for (const auto &fd: m_read_fds) - { - read_fds.push_back(fd.first); - FD_SET(fd.first, &read_fd_set); - nfds = std::max(nfds, fd.first+1); - } - - for (const auto &sig: m_signals) - { - signals.push_back(sig.first); - sigdelset(&sigmask, sig.first); - } - - if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && errno != EINTR) - return Error(errno, eErrorTypePOSIX); - - for (int sig: signals) - { - if (g_signal_flags[sig] == 0) - continue; // No signal - g_signal_flags[sig] = 0; - - auto it = m_signals.find(sig); - if (it == m_signals.end()) - continue; // Signal must have gotten unregistered in the meantime - - it->second.callback(*this); // Do the work - - if (m_terminate_request) - return Error(); - } - - for (int fd: read_fds) - { - if (!FD_ISSET(fd, &read_fd_set)) - continue; // Not ready - - auto it = m_read_fds.find(fd); - if (it == m_read_fds.end()) - continue; // File descriptor must have gotten unregistered in the meantime - - it->second(*this); // Do the work - - if (m_terminate_request) - return Error(); - } + it->second.callback(*this); // Do the work + + if (m_terminate_request) + return Error(); } - return Error(); -} + for (int fd : read_fds) { + if (!FD_ISSET(fd, &read_fd_set)) + continue; // Not ready + + auto it = m_read_fds.find(fd); + if (it == m_read_fds.end()) + continue; // File descriptor must have gotten unregistered in the + // meantime + it->second(*this); // Do the work + + if (m_terminate_request) + return Error(); + } + } + return Error(); +} diff --git a/source/Host/posix/PipePosix.cpp b/source/Host/posix/PipePosix.cpp index 353faae1628e..4e0810c1a9b3 100644 --- a/source/Host/posix/PipePosix.cpp +++ b/source/Host/posix/PipePosix.cpp @@ -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" @@ -25,9 +26,9 @@ #include <errno.h> #include <fcntl.h> #include <limits.h> -#include <unistd.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> using namespace lldb; using namespace lldb_private; @@ -38,400 +39,280 @@ enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE // pipe2 is supported by a limited set of platforms // TODO: Add more platforms that support pipe2. -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ + defined(__NetBSD__) #define PIPE2_SUPPORTED 1 #else #define PIPE2_SUPPORTED 0 #endif -namespace -{ +namespace { constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100; #if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED -bool SetCloexecFlag(int fd) -{ - int flags = ::fcntl(fd, F_GETFD); - if (flags == -1) - return false; - return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0); +bool SetCloexecFlag(int fd) { + int flags = ::fcntl(fd, F_GETFD); + if (flags == -1) + return false; + return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0); } #endif -std::chrono::time_point<std::chrono::steady_clock> -Now() -{ - return std::chrono::steady_clock::now(); +std::chrono::time_point<std::chrono::steady_clock> 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() - : m_fds{ - PipePosix::kInvalidDescriptor, - PipePosix::kInvalidDescriptor - } {} + : m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {} -PipePosix::PipePosix(int read_fd, int write_fd) - : m_fds{read_fd, write_fd} {} +PipePosix::PipePosix(int read_fd, int write_fd) : m_fds{read_fd, write_fd} {} PipePosix::PipePosix(PipePosix &&pipe_posix) : PipeBase{std::move(pipe_posix)}, - m_fds{ - pipe_posix.ReleaseReadFileDescriptor(), - pipe_posix.ReleaseWriteFileDescriptor() - } {} - -PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) -{ - PipeBase::operator=(std::move(pipe_posix)); - m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor(); - m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor(); - return *this; + m_fds{pipe_posix.ReleaseReadFileDescriptor(), + pipe_posix.ReleaseWriteFileDescriptor()} {} + +PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) { + PipeBase::operator=(std::move(pipe_posix)); + m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor(); + m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor(); + return *this; } -PipePosix::~PipePosix() -{ - Close(); -} +PipePosix::~PipePosix() { Close(); } -Error -PipePosix::CreateNew(bool child_processes_inherit) -{ - if (CanRead() || CanWrite()) - return Error(EINVAL, eErrorTypePOSIX); +Error PipePosix::CreateNew(bool child_processes_inherit) { + if (CanRead() || CanWrite()) + return Error(EINVAL, eErrorTypePOSIX); - Error error; + Error error; #if PIPE2_SUPPORTED - if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0) - return error; + if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0) + return error; #else - if (::pipe(m_fds) == 0) - { + if (::pipe(m_fds) == 0) { #ifdef FD_CLOEXEC - if (!child_processes_inherit) - { - if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1])) - { - error.SetErrorToErrno(); - Close(); - return error; - } - } -#endif + if (!child_processes_inherit) { + if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1])) { + error.SetErrorToErrno(); + Close(); return error; + } } #endif - - error.SetErrorToErrno(); - m_fds[READ] = PipePosix::kInvalidDescriptor; - m_fds[WRITE] = PipePosix::kInvalidDescriptor; return error; + } +#endif + + error.SetErrorToErrno(); + m_fds[READ] = PipePosix::kInvalidDescriptor; + m_fds[WRITE] = PipePosix::kInvalidDescriptor; + return error; } -Error -PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) -{ - if (CanRead() || CanWrite()) - return Error("Pipe is already opened"); +Error PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) { + if (CanRead() || CanWrite()) + return Error("Pipe is already opened"); - Error error; - if (::mkfifo(name.data(), 0660) != 0) - error.SetErrorToErrno(); + Error error; + if (::mkfifo(name.data(), 0660) != 0) + error.SetErrorToErrno(); - return error; + return error; } -Error -PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name) -{ - llvm::SmallString<PATH_MAX> named_pipe_path; - llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str()); - FileSpec tmpdir_file_spec; - tmpdir_file_spec.Clear(); - if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) - { - tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); - } - else - { - tmpdir_file_spec.AppendPathComponent("/tmp"); - tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); - } - - // It's possible that another process creates the target path after we've - // verified it's available but before we create it, in which case we - // should try again. - Error error; - do { - llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path); - error = CreateNew(named_pipe_path, child_process_inherit); - } while (error.GetError() == EEXIST); - - if (error.Success()) - name = named_pipe_path; - return error; +Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix, + bool child_process_inherit, + llvm::SmallVectorImpl<char> &name) { + llvm::SmallString<PATH_MAX> named_pipe_path; + llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str()); + FileSpec tmpdir_file_spec; + tmpdir_file_spec.Clear(); + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { + tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); + } else { + tmpdir_file_spec.AppendPathComponent("/tmp"); + tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); + } + + // It's possible that another process creates the target path after we've + // verified it's available but before we create it, in which case we + // should try again. + Error error; + do { + llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(), + named_pipe_path); + error = CreateNew(named_pipe_path, child_process_inherit); + } while (error.GetError() == EEXIST); + + if (error.Success()) + name = named_pipe_path; + return error; } -Error -PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit) -{ - if (CanRead() || CanWrite()) - return Error("Pipe is already opened"); +Error PipePosix::OpenAsReader(llvm::StringRef name, + bool child_process_inherit) { + if (CanRead() || CanWrite()) + return Error("Pipe is already opened"); - int flags = O_RDONLY | O_NONBLOCK; - if (!child_process_inherit) - flags |= O_CLOEXEC; + int flags = O_RDONLY | O_NONBLOCK; + if (!child_process_inherit) + flags |= O_CLOEXEC; - Error error; - int fd = ::open(name.data(), flags); - if (fd != -1) - m_fds[READ] = fd; - else - error.SetErrorToErrno(); + Error error; + int fd = ::open(name.data(), flags); + if (fd != -1) + m_fds[READ] = fd; + else + error.SetErrorToErrno(); - return error; + return error; } -Error -PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout) -{ - if (CanRead() || CanWrite()) - return Error("Pipe is already opened"); - - int flags = O_WRONLY | O_NONBLOCK; - if (!child_process_inherit) - flags |= O_CLOEXEC; - - using namespace std::chrono; - const auto finish_time = Now() + timeout; - - while (!CanWrite()) - { - if (timeout != microseconds::zero()) - { - const auto dur = duration_cast<microseconds>(finish_time - Now()).count(); - if (dur <= 0) - return Error("timeout exceeded - reader hasn't opened so far"); - } - - errno = 0; - int fd = ::open(name.data(), flags); - if (fd == -1) - { - const auto errno_copy = errno; - // We may get ENXIO if a reader side of the pipe hasn't opened yet. - if (errno_copy != ENXIO) - return Error(errno_copy, eErrorTypePOSIX); - - std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS)); - } - else - { - m_fds[WRITE] = fd; - } +Error PipePosix::OpenAsWriterWithTimeout( + llvm::StringRef name, bool child_process_inherit, + const std::chrono::microseconds &timeout) { + if (CanRead() || CanWrite()) + return Error("Pipe is already opened"); + + int flags = O_WRONLY | O_NONBLOCK; + if (!child_process_inherit) + flags |= O_CLOEXEC; + + using namespace std::chrono; + const auto finish_time = Now() + timeout; + + while (!CanWrite()) { + if (timeout != microseconds::zero()) { + const auto dur = duration_cast<microseconds>(finish_time - Now()).count(); + if (dur <= 0) + return Error("timeout exceeded - reader hasn't opened so far"); } - return Error(); -} + errno = 0; + int fd = ::open(name.data(), flags); + if (fd == -1) { + const auto errno_copy = errno; + // We may get ENXIO if a reader side of the pipe hasn't opened yet. + if (errno_copy != ENXIO) + return Error(errno_copy, eErrorTypePOSIX); + + std::this_thread::sleep_for( + milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS)); + } else { + m_fds[WRITE] = fd; + } + } -int -PipePosix::GetReadFileDescriptor() const -{ - return m_fds[READ]; + return Error(); } -int -PipePosix::GetWriteFileDescriptor() const -{ - return m_fds[WRITE]; -} +int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; } -int -PipePosix::ReleaseReadFileDescriptor() -{ - const int fd = m_fds[READ]; - m_fds[READ] = PipePosix::kInvalidDescriptor; - return fd; +int PipePosix::GetWriteFileDescriptor() const { return m_fds[WRITE]; } + +int PipePosix::ReleaseReadFileDescriptor() { + const int fd = m_fds[READ]; + m_fds[READ] = PipePosix::kInvalidDescriptor; + return fd; } -int -PipePosix::ReleaseWriteFileDescriptor() -{ - const int fd = m_fds[WRITE]; - m_fds[WRITE] = PipePosix::kInvalidDescriptor; - return fd; +int PipePosix::ReleaseWriteFileDescriptor() { + const int fd = m_fds[WRITE]; + m_fds[WRITE] = PipePosix::kInvalidDescriptor; + return fd; } -void -PipePosix::Close() -{ - CloseReadFileDescriptor(); - CloseWriteFileDescriptor(); +void PipePosix::Close() { + CloseReadFileDescriptor(); + CloseWriteFileDescriptor(); } -Error -PipePosix::Delete(llvm::StringRef name) -{ - return FileSystem::Unlink(FileSpec{name.data(), true}); +Error PipePosix::Delete(llvm::StringRef name) { + return FileSystem::Unlink(FileSpec{name.data(), true}); } -bool -PipePosix::CanRead() const -{ - return m_fds[READ] != PipePosix::kInvalidDescriptor; +bool PipePosix::CanRead() const { + return m_fds[READ] != PipePosix::kInvalidDescriptor; } -bool -PipePosix::CanWrite() const -{ - return m_fds[WRITE] != PipePosix::kInvalidDescriptor; +bool PipePosix::CanWrite() const { + return m_fds[WRITE] != PipePosix::kInvalidDescriptor; } -void -PipePosix::CloseReadFileDescriptor() -{ - if (CanRead()) - { - close(m_fds[READ]); - m_fds[READ] = PipePosix::kInvalidDescriptor; - } +void PipePosix::CloseReadFileDescriptor() { + if (CanRead()) { + close(m_fds[READ]); + m_fds[READ] = PipePosix::kInvalidDescriptor; + } } -void -PipePosix::CloseWriteFileDescriptor() -{ - if (CanWrite()) - { - close(m_fds[WRITE]); - m_fds[WRITE] = PipePosix::kInvalidDescriptor; - } +void PipePosix::CloseWriteFileDescriptor() { + if (CanWrite()) { + close(m_fds[WRITE]); + m_fds[WRITE] = PipePosix::kInvalidDescriptor; + } } -Error -PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read) -{ - bytes_read = 0; - 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); +Error PipePosix::ReadWithTimeout(void *buf, size_t size, + const std::chrono::microseconds &timeout, + size_t &bytes_read) { + bytes_read = 0; + if (!CanRead()) + return Error(EINVAL, eErrorTypePOSIX); + + 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 -PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) -{ - bytes_written = 0; - 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()); +Error PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) { + bytes_written = 0; + if (!CanWrite()) + return Error(EINVAL, eErrorTypePOSIX); + + 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; } diff --git a/source/Host/posix/ProcessLauncherPosix.cpp b/source/Host/posix/ProcessLauncherPosix.cpp index dd5c5121a97b..f90bf0cd88a2 100644 --- a/source/Host/posix/ProcessLauncherPosix.cpp +++ b/source/Host/posix/ProcessLauncherPosix.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/posix/ProcessLauncherPosix.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostProcess.h" -#include "lldb/Host/posix/ProcessLauncherPosix.h" #include "lldb/Target/ProcessLaunchInfo.h" @@ -19,15 +19,16 @@ using namespace lldb; using namespace lldb_private; HostProcess -ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) -{ - lldb::pid_t pid; - char exe_path[PATH_MAX]; +ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, + Error &error) { + lldb::pid_t pid; + char exe_path[PATH_MAX]; - launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); + launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); - // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make MacOSX re-use this - // ProcessLauncher when it wants a posix_spawn launch. - error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid); - return HostProcess(pid); + // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make + // MacOSX re-use this + // ProcessLauncher when it wants a posix_spawn launch. + error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid); + return HostProcess(pid); } |