Browse Source

Callback of Terminal::get().async_process is now run in the main thread

pipelines/280567345
eidheim 5 years ago
parent
commit
92b7cbdb2b
  1. 24
      src/cmake.cpp
  2. 24
      src/meson.cpp
  3. 14
      src/project.cpp
  4. 8
      src/terminal.cpp
  5. 1
      src/terminal.hpp
  6. 2
      src/window.cpp
  7. 48
      tests/terminal_test.cpp

24
src/cmake.cpp

@ -64,24 +64,24 @@ bool CMake::update_default_build(const boost::filesystem::path &default_build_pa
Dialog::Message message("Creating/updating default build", [&canceled] {
canceled = true;
});
std::promise<int> promise;
boost::optional<int> exit_status;
auto process = Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
default_build_path,
[&promise](int exit_status) {
promise.set_value(exit_status);
[&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
message.hide();
if(future.get() == 0) {
if(exit_status == 0) {
#ifdef _WIN32 //Temporary fix to MSYS2's libclang
auto compile_commands_file = filesystem::read(compile_commands_path);
auto replace_drive = [&compile_commands_file](const std::string &param) {
@ -124,24 +124,24 @@ bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path,
Dialog::Message message("Creating/updating debug build", [&canceled] {
canceled = true;
});
std::promise<int> promise;
boost::optional<int> exit_status;
auto process = Terminal::get().async_process(Config::get().project.cmake.command + ' ' + filesystem::escape_argument(project_path.string()) + " -DCMAKE_BUILD_TYPE=Debug",
debug_build_path,
[&promise](int exit_status) {
promise.set_value(exit_status);
[&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
message.hide();
return future.get() == 0;
return exit_status == 0;
}
boost::filesystem::path CMake::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {

24
src/meson.cpp

@ -64,24 +64,24 @@ bool Meson::update_default_build(const boost::filesystem::path &default_build_pa
Dialog::Message message("Creating/updating default build", [&canceled] {
canceled = true;
});
std::promise<int> promise;
boost::optional<int> exit_status;
auto process = Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype plain " + filesystem::escape_argument(project_path.string()),
default_build_path,
[&promise](int exit_status) {
promise.set_value(exit_status);
[&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
message.hide();
return future.get() == 0;
return exit_status == 0;
}
bool Meson::update_debug_build(const boost::filesystem::path &debug_build_path, bool force) {
@ -106,24 +106,24 @@ bool Meson::update_debug_build(const boost::filesystem::path &debug_build_path,
Dialog::Message message("Creating/updating debug build", [&canceled] {
canceled = true;
});
std::promise<int> promise;
boost::optional<int> exit_status;
auto process = Terminal::get().async_process(Config::get().project.meson.command + ' ' + (compile_commands_exists ? "--internal regenerate " : "") + "--buildtype debug " + filesystem::escape_argument(project_path.string()),
debug_build_path,
[&promise](int exit_status) {
promise.set_value(exit_status);
[&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = promise.get_future();
bool killed = false;
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
if(canceled && !killed) {
process->kill();
killed = true;
}
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
message.hide();
return future.get() == 0;
return exit_status == 0;
}
boost::filesystem::path Meson::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {

14
src/project.cpp

@ -386,7 +386,6 @@ void Project::LLDB::debug_start() {
if(exit_status != EXIT_SUCCESS)
debugging = false;
else {
self->dispatcher.post([self, run_arguments, project_path] {
std::vector<std::pair<boost::filesystem::path, int>> breakpoints;
for(size_t c = 0; c < Notebook::get().size(); c++) {
auto view = Notebook::get().get_view(c);
@ -488,7 +487,6 @@ void Project::LLDB::debug_start() {
}
}
Debug::LLDB::get().start(*run_arguments, *project_path, breakpoints, startup_commands, remote_host);
});
}
});
}
@ -893,7 +891,7 @@ void Project::Clang::compile_and_run() {
compiling = false;
if(exit_status == 0) {
Terminal::get().async_process(arguments, project_path, [arguments](int exit_status) {
Terminal::get().async_print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
});
@ -973,7 +971,7 @@ void Project::Markdown::compile_and_run() {
Terminal::get().async_process(
command, "", [command](int exit_status) {
if(exit_status == 127)
Terminal::get().async_print("\e[31mError\e[m: executable not found: " + command + "\n", true);
Terminal::get().print("\e[31mError\e[m: executable not found: " + command + "\n", true);
},
true);
}
@ -1001,7 +999,7 @@ void Project::Python::compile_and_run() {
Terminal::get().print("\e[2mRunning " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().async_print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
@ -1027,7 +1025,7 @@ void Project::JavaScript::compile_and_run() {
Terminal::get().print("\e[2mRunning " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().async_print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
@ -1040,7 +1038,7 @@ void Project::HTML::compile_and_run() {
Terminal::get().print("\e[2mRunning " + command + "\e[m\n");
Terminal::get().async_process(command, build->project_path, [command](int exit_status) {
Terminal::get().async_print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
else if(auto view = Notebook::get().get_current_view())
@ -1088,7 +1086,7 @@ void Project::Rust::compile_and_run() {
compiling = false;
if(exit_status == 0) {
Terminal::get().async_process(arguments, self->build->project_path, [arguments](int exit_status) {
Terminal::get().async_print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
});

8
src/terminal.cpp

@ -337,7 +337,7 @@ std::shared_ptr<TinyProcessLib::Process> Terminal::async_process(const std::stri
processes.emplace_back(process);
}
std::thread exit_status_thread([this, process, pid, callback = std::move(callback)]() {
std::thread([this, process, pid, callback = std::move(callback)]() mutable {
auto exit_status = process->get_exit_status();
{
LockGuard lock(processes_mutex);
@ -348,10 +348,12 @@ std::shared_ptr<TinyProcessLib::Process> Terminal::async_process(const std::stri
}
}
}
if(callback)
if(callback) {
dispatcher.post([callback = std::move(callback), exit_status] {
callback(exit_status);
});
exit_status_thread.detach();
}
}).detach();
return process;
}

1
src/terminal.hpp

@ -21,6 +21,7 @@ public:
int process(const std::string &command, const boost::filesystem::path &path = "", bool use_pipes = true);
int process(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path = "", std::ostream *stderr_stream = nullptr);
/// The callback is run in the main thread.
std::shared_ptr<TinyProcessLib::Process> async_process(const std::string &command, const boost::filesystem::path &path = "", std::function<void(int exit_status)> callback = nullptr, bool quiet = false);
void kill_last_async_process(bool force = false);
void kill_async_processes(bool force = false);

2
src/window.cpp

@ -1391,7 +1391,7 @@ void Window::set_menu_actions() {
Terminal::get().async_print("\e[2mRunning: " + content + "\e[m\n");
Terminal::get().async_process(content, directory_folder, [content](int exit_status) {
Terminal::get().async_print("\e[2m" + content + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
Terminal::get().print("\e[2m" + content + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
});
}
if(Config::get().terminal.hide_entry_on_run_command)

48
tests/terminal_test.cpp

@ -281,68 +281,68 @@ int main() {
// async_process tests
{
terminal.clear();
std::promise<int> done;
terminal.async_process("echo test", "", [&done](int exit_status) {
done.set_value(exit_status);
boost::optional<int> exit_status;
terminal.async_process("echo test", "", [&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = done.get_future();
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
assert(future.get() == 0);
assert(exit_status == 0);
assert(buffer->get_text() == "test\n");
assert(!buffer->begin().starts_tag(terminal.bold_tag));
assert(!buffer->end().ends_tag(terminal.bold_tag));
}
{
terminal.clear();
std::promise<int> done;
boost::optional<int> exit_status;
terminal.async_process(
"echo test", "", [&done](int exit_status) {
done.set_value(exit_status);
"echo test", "", [&exit_status](int exit_status_) {
exit_status = exit_status_;
},
true);
auto future = done.get_future();
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
assert(future.get() == 0);
assert(exit_status == 0);
assert(buffer->get_text() == "");
}
{
terminal.clear();
std::promise<int> done;
terminal.async_process("testing_invalid_command", "", [&done](int exit_status) {
done.set_value(exit_status);
boost::optional<int> exit_status;
terminal.async_process("testing_invalid_command", "", [&exit_status](int exit_status_) {
exit_status = exit_status_;
});
auto future = done.get_future();
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
assert(future.get() != 0);
assert(exit_status != 0);
assert(buffer->begin().starts_tag(terminal.bold_tag));
assert(buffer->end().ends_tag(terminal.bold_tag));
assert(buffer->get_text() != "");
}
{
terminal.clear();
std::promise<int> done;
boost::optional<int> exit_status;
terminal.async_process(
"testing_invalid_command", "", [&done](int exit_status) {
done.set_value(exit_status);
"testing_invalid_command", "", [&exit_status](int exit_status_) {
exit_status = exit_status_;
},
true);
auto future = done.get_future();
while(future.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {
while(!exit_status) {
while(Gtk::Main::events_pending())
Gtk::Main::iteration();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
assert(future.get() != 0);
assert(exit_status != 0);
assert(buffer->get_text() == "");
}

Loading…
Cancel
Save