llvm-project/llvm/lib/Support/Process.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

112 lines
3.4 KiB
C++
Raw Normal View History

//===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the operating system Process concept.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/Process.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include <stdlib.h> // for _Exit
[LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures This is a follow-up for D70378 (Cover usage of LLD as a library). While debugging an intermittent failure on a bot, I recalled this scenario which causes the issue: 1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(), then ELFFileBase::init(). 2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a half-initialized ObjFile instance. 3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we hapily restore the control flow to CrashRecoveryContext::RunSafely() then back in lld::safeLldMain(). 4.Before this patch, we called errorHandler().reset() just after, and this attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried to free the half-initialized ObjFile instance, and more precisely its ObjFile::dwarf member. Sometimes that worked, sometimes it failed and was catched by the CrashRecoveryContext. This scenario was the reason we called errorHandler().reset() through a CrashRecoveryContext. But in some rare cases, the above repro somehow corrupted the heap, creating a stack overflow. When the CrashRecoveryContext's filter (that is, __except (ExceptionFilter(GetExceptionInformation()))) tried to handle the exception, it crashed again since the stack was exhausted -- and that took the whole application down. That is the issue seen on the bot. Locally it happens about 1 times out of 15. Now this situation can happen anywhere in LLD. Since catching stack overflows is not a reliable scenario ATM when using CrashRecoveryContext, we're now preventing further re-entrance when such failures occur, by signaling lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above), only one iteration will be executed, instead of two. Differential Revision: https://reviews.llvm.org/D88348
2020-11-12 21:14:20 +08:00
using namespace llvm;
using namespace sys;
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
//=== independent code.
//===----------------------------------------------------------------------===//
Optional<std::string>
Process::FindInEnvPath(StringRef EnvName, StringRef FileName, char Separator) {
return FindInEnvPath(EnvName, FileName, {}, Separator);
}
Optional<std::string> Process::FindInEnvPath(StringRef EnvName,
StringRef FileName,
ArrayRef<std::string> IgnoreList,
char Separator) {
assert(!path::is_absolute(FileName));
Optional<std::string> FoundPath;
Optional<std::string> OptPath = Process::GetEnv(EnvName);
if (!OptPath.hasValue())
return FoundPath;
const char EnvPathSeparatorStr[] = {Separator, '\0'};
SmallVector<StringRef, 8> Dirs;
SplitString(OptPath.getValue(), Dirs, EnvPathSeparatorStr);
for (StringRef Dir : Dirs) {
if (Dir.empty())
continue;
if (any_of(IgnoreList, [&](StringRef S) { return fs::equivalent(S, Dir); }))
continue;
SmallString<128> FilePath(Dir);
path::append(FilePath, FileName);
if (fs::exists(Twine(FilePath))) {
FoundPath = std::string(FilePath.str());
break;
}
}
return FoundPath;
}
Add time getters to the process interface for requesting the elapsed wall time, user time, and system time since a process started. For walltime, we currently use TimeValue's interface and a global initializer to compute a close approximation of total process runtime. For user time, this adds support for an somewhat more precise timing mechanism -- clock_gettime with the CLOCK_PROCESS_CPUTIME_ID clock selected. For system time, we have to do a full getrusage call to extract the system time from the OS. This is expensive but unavoidable. In passing, clean up the implementation of the old APIs and fix some latent bugs in the Windows code. This might have manifested on Windows ARM systems or other systems with strange 64-bit integer behavior. The old API for this both user time and system time simultaneously from a single getrusage call. While this results in fewer system calls, it also results in a lower precision user time and if only user time is desired, it introduces a higher overhead. It may be worthwhile to switch some of the pass timers to not track system time and directly track user and wall time. The old API also tracked walltime in a confusing way -- it just set it to the current walltime rather than providing any measure of wall time since the process started the way buth user and system time are tracked. The new API is more consistent here. The plan is to eventually implement these methods for a *child* process by using the wait3(2) system call to populate an rusage struct representing the whole subprocess execution. That way, after waiting on a child process its stats will become accurate and cheap to query. llvm-svn: 171551
2013-01-05 07:19:55 +08:00
#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
#define ALLCOLORS(FGBG,BOLD) {\
COLOR(FGBG, "0", BOLD),\
COLOR(FGBG, "1", BOLD),\
COLOR(FGBG, "2", BOLD),\
COLOR(FGBG, "3", BOLD),\
COLOR(FGBG, "4", BOLD),\
COLOR(FGBG, "5", BOLD),\
COLOR(FGBG, "6", BOLD),\
COLOR(FGBG, "7", BOLD)\
}
static const char colorcodes[2][2][8][10] = {
{ ALLCOLORS("3",""), ALLCOLORS("3","1;") },
{ ALLCOLORS("4",""), ALLCOLORS("4","1;") }
};
// A CMake option controls wheter we emit core dumps by default. An application
// may disable core dumps by calling Process::PreventCoreFiles().
static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS;
bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; }
[[noreturn]] void Process::Exit(int RetCode, bool NoCleanup) {
if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent())
CRC->HandleExit(RetCode);
[LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures This is a follow-up for D70378 (Cover usage of LLD as a library). While debugging an intermittent failure on a bot, I recalled this scenario which causes the issue: 1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(), then ELFFileBase::init(). 2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a half-initialized ObjFile instance. 3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we hapily restore the control flow to CrashRecoveryContext::RunSafely() then back in lld::safeLldMain(). 4.Before this patch, we called errorHandler().reset() just after, and this attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried to free the half-initialized ObjFile instance, and more precisely its ObjFile::dwarf member. Sometimes that worked, sometimes it failed and was catched by the CrashRecoveryContext. This scenario was the reason we called errorHandler().reset() through a CrashRecoveryContext. But in some rare cases, the above repro somehow corrupted the heap, creating a stack overflow. When the CrashRecoveryContext's filter (that is, __except (ExceptionFilter(GetExceptionInformation()))) tried to handle the exception, it crashed again since the stack was exhausted -- and that took the whole application down. That is the issue seen on the bot. Locally it happens about 1 times out of 15. Now this situation can happen anywhere in LLD. Since catching stack overflows is not a reliable scenario ATM when using CrashRecoveryContext, we're now preventing further re-entrance when such failures occur, by signaling lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above), only one iteration will be executed, instead of two. Differential Revision: https://reviews.llvm.org/D88348
2020-11-12 21:14:20 +08:00
if (NoCleanup)
ExitNoCleanup(RetCode);
[LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures This is a follow-up for D70378 (Cover usage of LLD as a library). While debugging an intermittent failure on a bot, I recalled this scenario which causes the issue: 1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(), then ELFFileBase::init(). 2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a half-initialized ObjFile instance. 3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we hapily restore the control flow to CrashRecoveryContext::RunSafely() then back in lld::safeLldMain(). 4.Before this patch, we called errorHandler().reset() just after, and this attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried to free the half-initialized ObjFile instance, and more precisely its ObjFile::dwarf member. Sometimes that worked, sometimes it failed and was catched by the CrashRecoveryContext. This scenario was the reason we called errorHandler().reset() through a CrashRecoveryContext. But in some rare cases, the above repro somehow corrupted the heap, creating a stack overflow. When the CrashRecoveryContext's filter (that is, __except (ExceptionFilter(GetExceptionInformation()))) tried to handle the exception, it crashed again since the stack was exhausted -- and that took the whole application down. That is the issue seen on the bot. Locally it happens about 1 times out of 15. Now this situation can happen anywhere in LLD. Since catching stack overflows is not a reliable scenario ATM when using CrashRecoveryContext, we're now preventing further re-entrance when such failures occur, by signaling lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above), only one iteration will be executed, instead of two. Differential Revision: https://reviews.llvm.org/D88348
2020-11-12 21:14:20 +08:00
else
::exit(RetCode);
}
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Process.inc"
#endif
#ifdef _WIN32
#include "Windows/Process.inc"
#endif