Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix shutdown issues. #179

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion include/cling/UserInterface/UserInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,24 @@ namespace cling {
///
class UserInterface {
private:
class TextInputHolder;
std::unique_ptr<TextInputHolder> m_TextInput;
std::unique_ptr<MetaProcessor> m_MetaProcessor;

///\brief Prints cling's startup logo
///
void PrintLogo();
public:
UserInterface(Interpreter& interp);
UserInterface();
~UserInterface();

MetaProcessor* getMetaProcessor() { return m_MetaProcessor.get(); }

///\brief Attach this instance to the given Interpreter.
/// @param[in] Interp - The interpreter to attach to.
///
void attach(Interpreter& Interp);

///\brief Drives the interactive prompt talking to the user.
/// @param[in] nologo - whether to show cling's welcome logo or not
///
Expand Down
62 changes: 36 additions & 26 deletions lib/UserInterface/UserInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,67 @@ namespace {
return true;
}
};
}

namespace cling {

///\brief Delays ~TextInput until after ~StreamReader and ~TerminalDisplay
///
class TextInputHolder {
class UserInterface::TextInputHolder {
textinput::StreamReader* m_Reader;
textinput::TerminalDisplay* m_Display;
textinput::TextInput m_Input;

class HistoryFile {
llvm::SmallString<512> Path;

public:
HistoryFile(const char* Env = "CLING_NOHISTORY",
const char* Name = ".cling_history") {
if (getenv(Env)) return;
// History file is $HOME/.cling_history
if (llvm::sys::path::home_directory(Path))
llvm::sys::path::append(Path, Name);
}
const char* c_str() { return Path.empty() ? nullptr : Path.c_str(); }
};

public:
TextInputHolder(llvm::SmallString<512>& Hist)
TextInputHolder(HistoryFile HistFile = HistoryFile())
: m_Reader(textinput::StreamReader::Create()),
m_Display(textinput::TerminalDisplay::Create()),
m_Input(*m_Reader, *m_Display, Hist.empty() ? 0 : Hist.c_str()) {}
m_Input(*m_Reader, *m_Display, HistFile.c_str()) {
}

~TextInputHolder() {
delete m_Reader;
delete m_Display;
}

textinput::TextInput* operator -> () { return &m_Input; }
operator textinput::TextInput& () { return m_Input; }
};
}

namespace cling {

UserInterface::UserInterface(Interpreter& interp) {
m_MetaProcessor.reset(new MetaProcessor(interp, cling::outs()));
UserInterface::UserInterface() {
llvm::install_fatal_error_handler(&CompilationException::throwingHandler);
}

UserInterface::~UserInterface() {}
UserInterface::~UserInterface() { llvm::remove_fatal_error_handler(); }

void UserInterface::attach(Interpreter& Interp) {
m_MetaProcessor.reset(new MetaProcessor(Interp, cling::outs()));
}

void UserInterface::runInteractively(bool nologo /* = false */) {
if (!nologo) {
assert(m_MetaProcessor.get() && "Not attached to an Interpreter.");
if (!nologo)
PrintLogo();
}

llvm::SmallString<512> histfilePath;
if (!getenv("CLING_NOHISTORY")) {
// History file is $HOME/.cling_history
if (llvm::sys::path::home_directory(histfilePath))
llvm::sys::path::append(histfilePath, ".cling_history");
}

TextInputHolder TI(histfilePath);
m_TextInput.reset(new TextInputHolder);
textinput::TextInput& TI = *m_TextInput;

// Inform text input about the code complete consumer
// TextInput owns the TabCompletion.
UITabCompletion* Completion =
new UITabCompletion(m_MetaProcessor->getInterpreter());
TI->SetCompletion(Completion);
TI.SetCompletion(new UITabCompletion(m_MetaProcessor->getInterpreter()));

bool Done = false;
std::string Line;
Expand All @@ -107,9 +117,9 @@ namespace cling {
m_MetaProcessor->getOuts().flush();
{
MetaProcessor::MaybeRedirectOutputRAII RAII(*m_MetaProcessor);
TI->SetPrompt(Prompt.c_str());
Done = TI->ReadInput() == textinput::TextInput::kRREOF;
TI->TakeInput(Line);
TI.SetPrompt(Prompt.c_str());
Done = TI.ReadInput() == textinput::TextInput::kRREOF;
TI.TakeInput(Line);
if (Done && Line.empty())
break;
}
Expand Down
12 changes: 9 additions & 3 deletions lib/Utils/PlatformWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,11 +788,17 @@ void RegisterEHFrames(uintptr_t ImgBs, const EHFrameInfos& Frames, bool Block) {
void DeRegisterEHFrames(uintptr_t ImgBase, const EHFrameInfos& Frames) {
if (Frames.empty())
return;
assert(getImageBaseMap().find(ImgBase) != getImageBaseMap().end());

// Remove the ImageBase from lookup
// There is a chance that DeRegisterEHFrames will have been called without a
// preceeding call to RegisterEHFrames. Rather than tracking such cases,
// just ignore the requests when ImgBase was never registered.
ImageBaseMap& Unwind = getImageBaseMap();
Unwind.erase(Unwind.find(ImgBase));
auto Itr = Unwind.find(ImgBase);
if (Itr == Unwind.end())
return;

// Remove the ImageBase from lookup
Unwind.erase(Itr);

// Unregister all the PRUNTIME_FUNCTIONs
for (auto&& Frame : Frames)
Expand Down
5 changes: 4 additions & 1 deletion tools/driver/cling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ static int checkDiagErrors(clang::CompilerInstance* CI, unsigned* OutErrs = 0) {


int main( int argc, char **argv ) {
// Force the UserInterface to be destroyed last, so any file manipulation,
// pipes, or dups are active for the entire process.
cling::UserInterface Ui;

llvm::llvm_shutdown_obj shutdownTrigger;

Expand Down Expand Up @@ -105,7 +108,7 @@ int main( int argc, char **argv ) {
for (const std::string& Lib : Opts.LibsToLoad)
Interp.loadFile(Lib);

cling::UserInterface Ui(Interp);
Ui.attach(Interp);
// If we are not interactive we're supposed to parse files
if (!Opts.IsInteractive()) {
for (const std::string &Input : Opts.Inputs) {
Expand Down