Browse Source

Fixed potential freeze on excessive terminal output

pipelines/235045657
eidheim 5 years ago
parent
commit
f6eb3cec14
  1. 56
      src/terminal.cpp
  2. 9
      src/terminal.hpp

56
src/terminal.cpp

@ -5,6 +5,7 @@
#include "notebook.hpp"
#include "project.hpp"
#include "utility.hpp"
#include <future>
#include <iostream>
#include <regex>
#include <thread>
@ -23,6 +24,44 @@ Terminal::Terminal() : Source::SearchView() {
link_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::HAND1);
default_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::XTERM);
message_queue_thread = std::thread([this] {
while(true) {
std::unique_lock<std::mutex> lock(message_queue_mutex);
while(message_queue.empty() && !message_queue_stop)
message_queue_condition_variable.wait(lock);
if(message_queue_stop)
break;
// Combine messages to avoid overloading GUI thread
for(auto it = message_queue.begin(); it != message_queue.end();) {
auto next = std::next(it);
if(next == message_queue.end())
break;
if(it->second == next->second) {
it->first += next->first;
message_queue.erase(next);
}
else
++it;
}
std::promise<void> messages_printed;
dispatcher.post([message_queue = std::move(message_queue), &messages_printed]() mutable {
while(!message_queue.empty()) {
Terminal::get().print(std::move(message_queue.begin()->first), message_queue.begin()->second);
message_queue.pop_front();
}
messages_printed.set_value();
});
message_queue.clear();
// Wait until messages have been printed
lock.unlock();
messages_printed.get_future().get();
}
});
// Apply link tags
get_buffer()->signal_insert().connect([this](const Gtk::TextIter &iter, const Glib::ustring &text, int /*bytes*/) {
std::string line_start;
@ -75,6 +114,15 @@ Terminal::Terminal() : Source::SearchView() {
});
}
Terminal::~Terminal() {
{
std::unique_lock<std::mutex> lock(message_queue_mutex);
message_queue_stop = true;
}
message_queue_condition_variable.notify_one();
message_queue_thread.join();
}
int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
perform_scroll_to_bottom = true;
std::unique_ptr<TinyProcessLib::Process> process;
@ -322,9 +370,11 @@ void Terminal::print(std::string message, bool bold) {
}
void Terminal::async_print(std::string message, bool bold) {
dispatcher.post([message = std::move(message), bold]() mutable {
Terminal::get().print(std::move(message), bold);
});
{
std::unique_lock<std::mutex> lock(message_queue_mutex);
message_queue.emplace_back(std::move(message), bold);
}
message_queue_condition_variable.notify_one();
}
void Terminal::configure() {

9
src/terminal.hpp

@ -5,6 +5,7 @@
#include "source_base.hpp"
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <condition_variable>
#include <functional>
#include <gtkmm.h>
#include <iostream>
@ -19,6 +20,8 @@ public:
return singleton;
}
~Terminal() override;
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);
void async_process(const std::string &command, const boost::filesystem::path &path = "", const std::function<void(int exit_status)> &callback = nullptr, bool quiet = false);
@ -47,6 +50,12 @@ private:
Glib::RefPtr<Gdk::Cursor> default_mouse_cursor;
size_t deleted_lines = 0;
std::thread message_queue_thread;
bool message_queue_stop = false;
std::condition_variable message_queue_condition_variable;
std::mutex message_queue_mutex;
std::list<std::pair<std::string, bool>> message_queue;
struct Link {
int start_pos, end_pos;
std::string path;

Loading…
Cancel
Save