Index: compiler-rt/trunk/lib/xray/xray_basic_logging.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_basic_logging.cc +++ compiler-rt/trunk/lib/xray/xray_basic_logging.cc @@ -60,7 +60,7 @@ void *ShadowStack = nullptr; size_t StackSize = 0; size_t StackEntries = 0; - int Fd = -1; + LogWriter *LogWriter = nullptr; }; struct BasicLoggingOptions { @@ -83,10 +83,10 @@ static atomic_uint64_t TicksPerSec{0}; static atomic_uint64_t CycleFrequency{NanosecondsPerSecond}; -static int openLogFile() XRAY_NEVER_INSTRUMENT { - int F = getLogFD(); - if (F == -1) - return -1; +static LogWriter *getLog() XRAY_NEVER_INSTRUMENT { + LogWriter* LW = LogWriter::Open(); + if (LW == nullptr) + return LW; static pthread_once_t DetectOnce = PTHREAD_ONCE_INIT; pthread_once(&DetectOnce, +[] { @@ -108,16 +108,16 @@ // before setting the values in the header. Header.ConstantTSC = 1; Header.NonstopTSC = 1; - retryingWriteAll(F, reinterpret_cast(&Header), - reinterpret_cast(&Header) + sizeof(Header)); - return F; + LW->WriteAll(reinterpret_cast(&Header), + reinterpret_cast(&Header) + sizeof(Header)); + return LW; } -static int getGlobalFd() XRAY_NEVER_INSTRUMENT { +static LogWriter *getGlobalLog() XRAY_NEVER_INSTRUMENT { static pthread_once_t OnceInit = PTHREAD_ONCE_INIT; - static int Fd = 0; - pthread_once(&OnceInit, +[] { Fd = openLogFile(); }); - return Fd; + static LogWriter *LW = nullptr; + pthread_once(&OnceInit, +[] { LW = getLog(); }); + return LW; } static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT { @@ -129,7 +129,7 @@ return false; } pthread_setspecific(PThreadKey, &TLD); - TLD.Fd = getGlobalFd(); + TLD.LogWriter = getGlobalLog(); TLD.InMemoryBuffer = reinterpret_cast( InternalAlloc(sizeof(XRayRecord) * GlobalOptions.ThreadBufferSize, nullptr, alignof(XRayRecord))); @@ -157,8 +157,8 @@ void InMemoryRawLog(int32_t FuncId, XRayEntryType Type, RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT { auto &TLD = getThreadLocalData(); - int Fd = getGlobalFd(); - if (Fd == -1) + LogWriter *LW = getGlobalLog(); + if (LW == nullptr) return; // Use a simple recursion guard, to handle cases where we're already logging @@ -242,9 +242,9 @@ auto FirstEntry = reinterpret_cast(TLD.InMemoryBuffer); internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R)); if (++TLD.BufferOffset == TLD.BufferSize) { - SpinMutexLock L(&LogMutex); - retryingWriteAll(Fd, reinterpret_cast(FirstEntry), - reinterpret_cast(FirstEntry + TLD.BufferOffset)); + SpinMutexLock Lock(&LogMutex); + LW->WriteAll(reinterpret_cast(FirstEntry), + reinterpret_cast(FirstEntry + TLD.BufferOffset)); TLD.BufferOffset = 0; TLD.StackEntries = 0; } @@ -257,17 +257,17 @@ auto FirstEntry = reinterpret_cast(TLD.InMemoryBuffer); const auto &BuffLen = TLD.BufferSize; - int Fd = getGlobalFd(); - if (Fd == -1) + LogWriter *LW = getGlobalLog(); + if (LW == nullptr) return; // First we check whether there's enough space to write the data consecutively // in the thread-local buffer. If not, we first flush the buffer before // attempting to write the two records that must be consecutive. if (TLD.BufferOffset + 2 > BuffLen) { - SpinMutexLock L(&LogMutex); - retryingWriteAll(Fd, reinterpret_cast(FirstEntry), - reinterpret_cast(FirstEntry + TLD.BufferOffset)); + SpinMutexLock Lock(&LogMutex); + LW->WriteAll(reinterpret_cast(FirstEntry), + reinterpret_cast(FirstEntry + TLD.BufferOffset)); TLD.BufferOffset = 0; TLD.StackEntries = 0; } @@ -288,9 +288,9 @@ R.Arg = Arg1; internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R)); if (++TLD.BufferOffset == BuffLen) { - SpinMutexLock L(&LogMutex); - retryingWriteAll(Fd, reinterpret_cast(FirstEntry), - reinterpret_cast(FirstEntry + TLD.BufferOffset)); + SpinMutexLock Lock(&LogMutex); + LW->WriteAll(reinterpret_cast(FirstEntry), + reinterpret_cast(FirstEntry + TLD.BufferOffset)); TLD.BufferOffset = 0; TLD.StackEntries = 0; } @@ -347,25 +347,25 @@ Report("Cleaned up log for TID: %d\n", GetTid()); }); - if (TLD.Fd == -1 || TLD.BufferOffset == 0) { + if (TLD.LogWriter == nullptr || TLD.BufferOffset == 0) { if (Verbosity()) - Report("Skipping buffer for TID: %d; Fd = %d; Offset = %llu\n", GetTid(), - TLD.Fd, TLD.BufferOffset); + Report("Skipping buffer for TID: %d; Offset = %llu\n", GetTid(), + TLD.BufferOffset); return; } { SpinMutexLock L(&LogMutex); - retryingWriteAll(TLD.Fd, reinterpret_cast(TLD.InMemoryBuffer), - reinterpret_cast(TLD.InMemoryBuffer) + - (sizeof(XRayRecord) * TLD.BufferOffset)); + TLD.LogWriter->WriteAll(reinterpret_cast(TLD.InMemoryBuffer), + reinterpret_cast(TLD.InMemoryBuffer) + + (sizeof(XRayRecord) * TLD.BufferOffset)); } // Because this thread's exit could be the last one trying to write to // the file and that we're not able to close out the file properly, we // sync instead and hope that the pending writes are flushed as the // thread exits. - fsync(TLD.Fd); + TLD.LogWriter->Flush(); } XRayLogInitStatus basicLoggingInit(UNUSED size_t BufferSize, Index: compiler-rt/trunk/lib/xray/xray_fdr_logging.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_logging.cc +++ compiler-rt/trunk/lib/xray/xray_fdr_logging.cc @@ -838,8 +838,8 @@ // (fixed-sized) and let the tools reading the buffers deal with the data // afterwards. // - int Fd = getLogFD(); - if (Fd == -1) { + LogWriter* LW = LogWriter::Open(); + if (LW == nullptr) { auto Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; atomic_store(&LogFlushStatus, Result, memory_order_release); return Result; @@ -847,8 +847,8 @@ XRayFileHeader Header = fdrCommonHeaderInfo(); Header.FdrData = FdrAdditionalHeaderData{BQ->ConfiguredBufferSize()}; - retryingWriteAll(Fd, reinterpret_cast(&Header), - reinterpret_cast(&Header) + sizeof(Header)); + LW->WriteAll(reinterpret_cast(&Header), + reinterpret_cast(&Header) + sizeof(Header)); // Release the current thread's buffer before we attempt to write out all the // buffers. This ensures that in case we had only a single thread going, that @@ -871,11 +871,11 @@ uint8_t(MetadataRecord::RecordKinds::BufferExtents); internal_memcpy(ExtentsRecord.Data, &BufferExtents, sizeof(BufferExtents)); if (BufferExtents > 0) { - retryingWriteAll(Fd, reinterpret_cast(&ExtentsRecord), - reinterpret_cast(&ExtentsRecord) + - sizeof(MetadataRecord)); - retryingWriteAll(Fd, reinterpret_cast(B.Data), - reinterpret_cast(B.Data) + BufferExtents); + LW->WriteAll(reinterpret_cast(&ExtentsRecord), + reinterpret_cast(&ExtentsRecord) + + sizeof(MetadataRecord)); + LW->WriteAll(reinterpret_cast(B.Data), + reinterpret_cast(B.Data) + BufferExtents); } }); Index: compiler-rt/trunk/lib/xray/xray_profiling.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiling.cc +++ compiler-rt/trunk/lib/xray/xray_profiling.cc @@ -133,21 +133,20 @@ if (Verbosity()) Report("profiling: No data to flush.\n"); } else { - int Fd = getLogFD(); - if (Fd == -1) { + LogWriter* LW = LogWriter::Open(); + if (LW == nullptr) { if (Verbosity()) Report("profiling: Failed to flush to file, dropping data.\n"); } else { // Now for each of the buffers, write out the profile data as we would // see it in memory, verbatim. while (B.Data != nullptr && B.Size != 0) { - retryingWriteAll(Fd, reinterpret_cast(B.Data), - reinterpret_cast(B.Data) + B.Size); + LW->WriteAll(reinterpret_cast(B.Data), + reinterpret_cast(B.Data) + B.Size); B = profileCollectorService::nextBuffer(B); } - // Then we close out the file. - internal_close(Fd); } + LogWriter::Close(LW); } } Index: compiler-rt/trunk/lib/xray/xray_utils.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_utils.h +++ compiler-rt/trunk/lib/xray/xray_utils.h @@ -22,22 +22,28 @@ namespace __xray { +class LogWriter { +public: + explicit LogWriter(int Fd) : Fd(Fd) {} + ~LogWriter(); + + // Write a character range into a log. + void WriteAll(const char *Begin, const char *End); + + void Flush(); + + // Returns a new log instance initialized using the flag-provided values. + static LogWriter *Open(); + // Closes and deallocates the log instance. + static void Close(LogWriter *LogWriter); + +private: + int Fd = -1; +}; + // Default implementation of the reporting interface for sanitizer errors. void printToStdErr(const char *Buffer); -// EINTR-safe write routine, provided a file descriptor and a character range. -void retryingWriteAll(int Fd, const char *Begin, const char *End); - -// Reads a long long value from a provided file. -bool readValueFromFile(const char *Filename, long long *Value); - -// EINTR-safe read routine, providing a file descriptor and a character range. -std::pair retryingReadSome(int Fd, char *Begin, char *End); - -// EINTR-safe open routine, uses flag-provided values for initialising a log -// file. -int getLogFD(); - constexpr size_t gcd(size_t a, size_t b) { return (b == 0) ? a : gcd(b, a % b); } Index: compiler-rt/trunk/lib/xray/xray_utils.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_utils.cc +++ compiler-rt/trunk/lib/xray/xray_utils.cc @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #include "xray_utils.h" +#include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" +#include "xray_allocator.h" #include "xray_defs.h" #include "xray_flags.h" #include @@ -31,7 +33,11 @@ fprintf(stderr, "%s", Buffer); } -void retryingWriteAll(int Fd, const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT { +LogWriter::~LogWriter() { + internal_close(Fd); +} + +void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT { if (Begin == End) return; auto TotalBytes = std::distance(Begin, End); @@ -49,50 +55,11 @@ } } -std::pair retryingReadSome(int Fd, char *Begin, - char *End) XRAY_NEVER_INSTRUMENT { - auto BytesToRead = std::distance(Begin, End); - ssize_t BytesRead; - ssize_t TotalBytesRead = 0; - while (BytesToRead && (BytesRead = read(Fd, Begin, BytesToRead))) { - if (BytesRead == -1) { - if (errno == EINTR) - continue; - Report("Read error; errno = %d\n", errno); - return std::make_pair(TotalBytesRead, false); - } - - TotalBytesRead += BytesRead; - BytesToRead -= BytesRead; - Begin += BytesRead; - } - return std::make_pair(TotalBytesRead, true); +void LogWriter::Flush() XRAY_NEVER_INSTRUMENT { + fsync(Fd); } -bool readValueFromFile(const char *Filename, - long long *Value) XRAY_NEVER_INSTRUMENT { - int Fd = open(Filename, O_RDONLY | O_CLOEXEC); - if (Fd == -1) - return false; - static constexpr size_t BufSize = 256; - char Line[BufSize] = {}; - ssize_t BytesRead; - bool Success; - std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize); - if (!Success) - return false; - close(Fd); - const char *End = nullptr; - long long Tmp = internal_simple_strtoll(Line, &End, 10); - bool Result = false; - if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) { - *Value = Tmp; - Result = true; - } - return Result; -} - -int getLogFD() XRAY_NEVER_INSTRUMENT { +LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT { // Open a temporary file once for the log. char TmpFilename[256] = {}; char TmpWildcardPattern[] = "XXXXXX"; @@ -108,18 +75,25 @@ flags()->xray_logfile_base, Progname, TmpWildcardPattern); if (NeededLength > int(sizeof(TmpFilename))) { Report("XRay log file name too long (%d): %s\n", NeededLength, TmpFilename); - return -1; + return nullptr; } int Fd = mkstemp(TmpFilename); if (Fd == -1) { Report("XRay: Failed opening temporary file '%s'; not logging events.\n", TmpFilename); - return -1; + return nullptr; } if (Verbosity()) Report("XRay: Log file in '%s'\n", TmpFilename); - return Fd; + LogWriter *LW = allocate(); + new (LW) LogWriter(Fd); + return LW; +} + +void LogWriter::Close(LogWriter *LW) { + LW->~LogWriter(); + deallocate(LW); } } // namespace __xray