forked from OSchip/llvm-project
update ScriptInterpreterPython to use File, not FILE*
Summary: ScriptInterpreterPython needs to save and restore sys.stdout and friends when LLDB runs a python script. It currently does this using FILE*, which is not optimal. If whatever was in sys.stdout can not be represented as a FILE*, then it will not be restored correctly when the script is finished. It also means that if the debugger's own output stream is not representable as a file, ScriptInterpreterPython will not be able to redirect python's output correctly. This patch updates ScriptInterpreterPython to represent files with lldb_private::File, and to represent whatever the user had in sys.stdout as simply a PythonObject. This will make lldb interoperate better with other scripts or programs that need to manipulate sys.stdout. Reviewers: JDevlieghere, jasonmolenda, labath Reviewed By: labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D68962 llvm-svn: 374964
This commit is contained in:
parent
9d10b9d99b
commit
b07823f3e2
|
@ -445,9 +445,8 @@ class FileHandleTestCase(lldbtest.TestBase):
|
|||
self.assertTrue(re.search(r'error:.*lolwut', errors))
|
||||
self.assertTrue(re.search(r'zork', errors))
|
||||
|
||||
#FIXME This shouldn't fail for python2 either.
|
||||
|
||||
@add_test_categories(['pyapi'])
|
||||
@skipIf(py_version=['<', (3,)])
|
||||
def test_replace_stdout(self):
|
||||
f = io.StringIO()
|
||||
with replace_stdout(f):
|
||||
|
@ -458,7 +457,6 @@ class FileHandleTestCase(lldbtest.TestBase):
|
|||
|
||||
|
||||
@add_test_categories(['pyapi'])
|
||||
@expectedFailureAll() #FIXME bug in ScriptInterpreterPython
|
||||
def test_replace_stdout_with_nonfile(self):
|
||||
debugger = self.debugger
|
||||
f = io.StringIO()
|
||||
|
|
|
@ -973,34 +973,31 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
|
|||
std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
|
||||
IOHandlerSP top_reader_sp(m_input_reader_stack.Top());
|
||||
// If no STDIN has been set, then set it appropriately
|
||||
if (!in) {
|
||||
if (!in || !in->IsValid()) {
|
||||
if (top_reader_sp)
|
||||
in = top_reader_sp->GetInputFileSP();
|
||||
else
|
||||
in = GetInputFileSP();
|
||||
|
||||
// If there is nothing, use stdin
|
||||
if (!in)
|
||||
in = std::make_shared<NativeFile>(stdin, false);
|
||||
}
|
||||
// If no STDOUT has been set, then set it appropriately
|
||||
if (!out) {
|
||||
if (!out || !out->GetFile().IsValid()) {
|
||||
if (top_reader_sp)
|
||||
out = top_reader_sp->GetOutputStreamFileSP();
|
||||
else
|
||||
out = GetOutputStreamSP();
|
||||
|
||||
// If there is nothing, use stdout
|
||||
if (!out)
|
||||
out = std::make_shared<StreamFile>(stdout, false);
|
||||
}
|
||||
// If no STDERR has been set, then set it appropriately
|
||||
if (!err) {
|
||||
if (!err || !err->GetFile().IsValid()) {
|
||||
if (top_reader_sp)
|
||||
err = top_reader_sp->GetErrorStreamFileSP();
|
||||
else
|
||||
err = GetErrorStreamSP();
|
||||
|
||||
// If there is nothing, use stderr
|
||||
if (!err)
|
||||
err = std::make_shared<StreamFile>(stderr, false);
|
||||
|
|
|
@ -370,7 +370,7 @@ void ScriptInterpreterPython::Terminate() {}
|
|||
|
||||
ScriptInterpreterPythonImpl::Locker::Locker(
|
||||
ScriptInterpreterPythonImpl *py_interpreter, uint16_t on_entry,
|
||||
uint16_t on_leave, FILE *in, FILE *out, FILE *err)
|
||||
uint16_t on_leave, FileSP in, FileSP out, FileSP err)
|
||||
: ScriptInterpreterLocker(),
|
||||
m_teardown_session((on_leave & TearDownSession) == TearDownSession),
|
||||
m_python_interpreter(py_interpreter) {
|
||||
|
@ -400,8 +400,8 @@ bool ScriptInterpreterPythonImpl::Locker::DoAcquireLock() {
|
|||
}
|
||||
|
||||
bool ScriptInterpreterPythonImpl::Locker::DoInitSession(uint16_t on_entry_flags,
|
||||
FILE *in, FILE *out,
|
||||
FILE *err) {
|
||||
FileSP in, FileSP out,
|
||||
FileSP err) {
|
||||
if (!m_python_interpreter)
|
||||
return false;
|
||||
return m_python_interpreter->EnterSession(on_entry_flags, in, out, err);
|
||||
|
@ -636,28 +636,31 @@ void ScriptInterpreterPythonImpl::LeaveSession() {
|
|||
m_session_is_active = false;
|
||||
}
|
||||
|
||||
bool ScriptInterpreterPythonImpl::SetStdHandle(File &file, const char *py_name,
|
||||
PythonFile &save_file,
|
||||
bool ScriptInterpreterPythonImpl::SetStdHandle(FileSP file_sp,
|
||||
const char *py_name,
|
||||
PythonObject &save_file,
|
||||
const char *mode) {
|
||||
if (file.IsValid()) {
|
||||
// Flush the file before giving it to python to avoid interleaved output.
|
||||
file.Flush();
|
||||
|
||||
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
|
||||
|
||||
save_file = sys_module_dict.GetItemForKey(PythonString(py_name))
|
||||
.AsType<PythonFile>();
|
||||
|
||||
PythonFile new_file(file, mode);
|
||||
sys_module_dict.SetItemForKey(PythonString(py_name), new_file);
|
||||
return true;
|
||||
} else
|
||||
if (!file_sp || !*file_sp) {
|
||||
save_file.Reset();
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
File &file = *file_sp;
|
||||
|
||||
// Flush the file before giving it to python to avoid interleaved output.
|
||||
file.Flush();
|
||||
|
||||
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
|
||||
|
||||
save_file = sys_module_dict.GetItemForKey(PythonString(py_name));
|
||||
|
||||
PythonFile new_file(file, mode);
|
||||
sys_module_dict.SetItemForKey(PythonString(py_name), new_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags,
|
||||
FILE *in, FILE *out, FILE *err) {
|
||||
FileSP in_sp, FileSP out_sp,
|
||||
FileSP err_sp) {
|
||||
// If we have already entered the session, without having officially 'left'
|
||||
// it, then there is no need to 'enter' it again.
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
|
||||
|
@ -706,33 +709,29 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags,
|
|||
|
||||
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
|
||||
if (sys_module_dict.IsValid()) {
|
||||
NativeFile in_file(in, false);
|
||||
NativeFile out_file(out, false);
|
||||
NativeFile err_file(err, false);
|
||||
|
||||
lldb::FileSP in_sp;
|
||||
lldb::StreamFileSP out_sp;
|
||||
lldb::StreamFileSP err_sp;
|
||||
if (!in_file.IsValid() || !out_file.IsValid() || !err_file.IsValid())
|
||||
m_debugger.AdoptTopIOHandlerFilesIfInvalid(in_sp, out_sp, err_sp);
|
||||
lldb::FileSP top_in_sp;
|
||||
lldb::StreamFileSP top_out_sp, top_err_sp;
|
||||
if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp)
|
||||
m_debugger.AdoptTopIOHandlerFilesIfInvalid(top_in_sp, top_out_sp,
|
||||
top_err_sp);
|
||||
|
||||
if (on_entry_flags & Locker::NoSTDIN) {
|
||||
m_saved_stdin.Reset();
|
||||
} else {
|
||||
if (!SetStdHandle(in_file, "stdin", m_saved_stdin, "r")) {
|
||||
if (in_sp)
|
||||
SetStdHandle(*in_sp, "stdin", m_saved_stdin, "r");
|
||||
if (!SetStdHandle(in_sp, "stdin", m_saved_stdin, "r")) {
|
||||
if (top_in_sp)
|
||||
SetStdHandle(top_in_sp, "stdin", m_saved_stdin, "r");
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetStdHandle(out_file, "stdout", m_saved_stdout, "w")) {
|
||||
if (out_sp)
|
||||
SetStdHandle(out_sp->GetFile(), "stdout", m_saved_stdout, "w");
|
||||
if (!SetStdHandle(out_sp, "stdout", m_saved_stdout, "w")) {
|
||||
if (top_out_sp)
|
||||
SetStdHandle(top_out_sp->GetFileSP(), "stdout", m_saved_stdout, "w");
|
||||
}
|
||||
|
||||
if (!SetStdHandle(err_file, "stderr", m_saved_stderr, "w")) {
|
||||
if (err_sp)
|
||||
SetStdHandle(err_sp->GetFile(), "stderr", m_saved_stderr, "w");
|
||||
if (!SetStdHandle(err_sp, "stderr", m_saved_stderr, "w")) {
|
||||
if (top_err_sp)
|
||||
SetStdHandle(top_err_sp->GetFileSP(), "stderr", m_saved_stderr, "w");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -909,9 +908,6 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
|
|||
error_file_sp = output_file_sp = std::make_shared<StreamFile>(std::move(nullout.get()));
|
||||
}
|
||||
|
||||
FILE *in_file = input_file_sp->GetStream();
|
||||
FILE *out_file = output_file_sp->GetFile().GetStream();
|
||||
FILE *err_file = error_file_sp->GetFile().GetStream();
|
||||
bool success = false;
|
||||
{
|
||||
// WARNING! It's imperative that this RAII scope be as tight as
|
||||
|
@ -927,8 +923,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
|
|||
Locker::AcquireLock | Locker::InitSession |
|
||||
(options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) |
|
||||
((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN),
|
||||
Locker::FreeAcquiredLock | Locker::TearDownSession, in_file, out_file,
|
||||
err_file);
|
||||
Locker::FreeAcquiredLock | Locker::TearDownSession, input_file_sp,
|
||||
output_file_sp->GetFileSP(), error_file_sp->GetFileSP());
|
||||
|
||||
// Find the correct script interpreter dictionary in the main module.
|
||||
PythonDictionary &session_dict = GetSessionDictionary();
|
||||
|
@ -955,9 +951,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
|
|||
}
|
||||
|
||||
// Flush our output and error file handles
|
||||
::fflush(out_file);
|
||||
if (out_file != err_file)
|
||||
::fflush(err_file);
|
||||
output_file_sp->Flush();
|
||||
error_file_sp->Flush();
|
||||
}
|
||||
|
||||
if (join_read_thread) {
|
||||
|
|
|
@ -294,17 +294,19 @@ public:
|
|||
TearDownSession = 0x0004
|
||||
};
|
||||
|
||||
Locker(ScriptInterpreterPythonImpl *py_interpreter = nullptr,
|
||||
Locker(ScriptInterpreterPythonImpl *py_interpreter,
|
||||
uint16_t on_entry = AcquireLock | InitSession,
|
||||
uint16_t on_leave = FreeLock | TearDownSession, FILE *in = nullptr,
|
||||
FILE *out = nullptr, FILE *err = nullptr);
|
||||
uint16_t on_leave = FreeLock | TearDownSession,
|
||||
lldb::FileSP in = nullptr, lldb::FileSP out = nullptr,
|
||||
lldb::FileSP err = nullptr);
|
||||
|
||||
~Locker() override;
|
||||
|
||||
private:
|
||||
bool DoAcquireLock();
|
||||
|
||||
bool DoInitSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err);
|
||||
bool DoInitSession(uint16_t on_entry_flags, lldb::FileSP in,
|
||||
lldb::FileSP out, lldb::FileSP err);
|
||||
|
||||
bool DoFreeLock();
|
||||
|
||||
|
@ -312,7 +314,6 @@ public:
|
|||
|
||||
bool m_teardown_session;
|
||||
ScriptInterpreterPythonImpl *m_python_interpreter;
|
||||
// FILE* m_tmp_fh;
|
||||
PyGILState_STATE m_GILState;
|
||||
};
|
||||
|
||||
|
@ -341,7 +342,8 @@ public:
|
|||
|
||||
static void AddToSysPath(AddLocation location, std::string path);
|
||||
|
||||
bool EnterSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err);
|
||||
bool EnterSession(uint16_t on_entry_flags, lldb::FileSP in, lldb::FileSP out,
|
||||
lldb::FileSP err);
|
||||
|
||||
void LeaveSession();
|
||||
|
||||
|
@ -369,12 +371,12 @@ public:
|
|||
|
||||
bool GetEmbeddedInterpreterModuleObjects();
|
||||
|
||||
bool SetStdHandle(File &file, const char *py_name, PythonFile &save_file,
|
||||
const char *mode);
|
||||
bool SetStdHandle(lldb::FileSP file, const char *py_name,
|
||||
PythonObject &save_file, const char *mode);
|
||||
|
||||
PythonFile m_saved_stdin;
|
||||
PythonFile m_saved_stdout;
|
||||
PythonFile m_saved_stderr;
|
||||
PythonObject m_saved_stdin;
|
||||
PythonObject m_saved_stdout;
|
||||
PythonObject m_saved_stderr;
|
||||
PythonObject m_main_module;
|
||||
PythonDictionary m_session_dict;
|
||||
PythonDictionary m_sys_module_dict;
|
||||
|
|
Loading…
Reference in New Issue