Browse Source

Clang parse cleanup, at least somewhat more understandable now. Also more robust.

merge-requests/365/head
eidheim 10 years ago
parent
commit
7b78a6aea9
  1. 126
      src/source_clang.cc
  2. 26
      src/source_clang.h

126
src/source_clang.cc

@ -21,7 +21,7 @@ namespace sigc {
clang::Index Source::ClangViewParse::clang_index(0, 0); clang::Index Source::ClangViewParse::clang_index(0, 0);
Source::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): Source::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language):
Source::View(file_path, project_path, language), parse_error(false) { Source::View(file_path, project_path, language) {
JDEBUG("start"); JDEBUG("start");
auto tag_table=get_buffer()->get_tag_table(); auto tag_table=get_buffer()->get_tag_table();
@ -35,36 +35,35 @@ Source::View(file_path, project_path, language), parse_error(false) {
parsing_in_progress=Singleton::terminal->print_in_progress("Parsing "+file_path.string()); parsing_in_progress=Singleton::terminal->print_in_progress("Parsing "+file_path.string());
//GTK-calls must happen in main thread, so the parse_thread //GTK-calls must happen in main thread, so the parse_thread
//sends signals to the main thread that it is to call the following functions: //sends signals to the main thread that it is to call the following functions:
parse_start_connection=parse_start.connect([this]{ parse_start_connection=parse_preprocess.connect([this]{
if(parse_thread_buffer_mutex.try_lock()) { auto expected=ParseProcessState::PREPROCESSING;
parse_thread_buffer=get_buffer()->get_text(); if(parse_mutex.try_lock()) {
parse_thread_mapped=true; if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::PROCESSING))
parse_thread_buffer_mutex.unlock(); parse_thread_buffer=get_buffer()->get_text();
parse_mutex.unlock();
} }
parse_thread_go=true; else
parse_process_state.compare_exchange_strong(expected, ParseProcessState::STARTING);
}); });
parse_done_connection=parse_done.connect([this](){ parse_done_connection=parse_postprocess.connect([this](){
if(parse_thread_mapped) { if(parse_mutex.try_lock()) {
if(parsing_mutex.try_lock()) { auto expected=ParseProcessState::POSTPROCESSING;
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::IDLE)) {
update_syntax(); update_syntax();
update_diagnostics(); update_diagnostics();
parsed=true; parsed=true;
set_status(""); set_status("");
parsing_mutex.unlock();
} }
parsing_in_progress->done("done"); parse_mutex.unlock();
}
else {
parse_thread_go=true;
} }
}); });
parse_fail_connection=parse_fail.connect([this](){ parse_fail_connection=parse_error.connect([this](){
Singleton::terminal->print("Error: failed to reparse "+this->file_path.string()+".\n", true); Singleton::terminal->print("Error: failed to reparse "+this->file_path.string()+".\n", true);
set_status(""); set_status("");
set_info(""); set_info("");
parsing_in_progress->cancel("failed"); parsing_in_progress->cancel("failed");
}); });
init_parse(); parse_initialize();
get_buffer()->signal_changed().connect([this]() { get_buffer()->signal_changed().connect([this]() {
soft_reparse(); soft_reparse();
@ -105,13 +104,14 @@ void Source::ClangViewParse::configure() {
no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else|try|do) *$"); no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else|try|do) *$");
} }
void Source::ClangViewParse::init_parse() { void Source::ClangViewParse::parse_initialize() {
type_tooltips.hide(); type_tooltips.hide();
diagnostic_tooltips.hide(); diagnostic_tooltips.hide();
parsed=false; parsed=false;
parse_thread_go=true; if(parse_thread.joinable())
parse_thread_mapped=false; parse_thread.join();
parse_thread_stop=false; parse_process_state=ParseProcessState::STARTING;
parse_state=ParseState::WORKING;
auto buffer=get_buffer()->get_text(); auto buffer=get_buffer()->get_text();
//Remove includes for first parse for initial syntax highlighting //Remove includes for first parse for initial syntax highlighting
@ -131,46 +131,53 @@ void Source::ClangViewParse::init_parse() {
update_syntax(); update_syntax();
set_status("parsing..."); set_status("parsing...");
if(parse_thread.joinable())
parse_thread.join();
parse_thread=std::thread([this]() { parse_thread=std::thread([this]() {
while(true) { while(true) {
while(!parse_thread_go && !parse_thread_stop) while(parse_state==ParseState::WORKING && (parse_process_state==ParseProcessState::IDLE || parse_process_state==ParseProcessState::PREPROCESSING || parse_process_state==ParseProcessState::POSTPROCESSING))
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
if(parse_thread_stop) if(parse_state!=ParseState::WORKING)
break; break;
if(!parse_thread_mapped) { auto expected=ParseProcessState::STARTING;
parse_thread_go=false; if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::PREPROCESSING))
parse_start(); parse_preprocess();
} else if (parse_process_state==ParseProcessState::PROCESSING && parse_mutex.try_lock()) {
else if (parse_thread_mapped && parsing_mutex.try_lock() && parse_thread_buffer_mutex.try_lock()) { if(parse_process_state==ParseProcessState::PROCESSING) {
auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer.raw()); auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer.raw());
if(status==0) parsing_in_progress->done("done");
clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer.bytes()-1); if(status==0) {
else auto expected=ParseProcessState::PROCESSING;
parse_error=true; if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::POSTPROCESSING)) {
parse_thread_go=false; clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer.bytes()-1);
parsing_mutex.unlock(); parse_mutex.unlock();
parse_thread_buffer_mutex.unlock(); parse_postprocess();
if(status!=0) { }
parse_fail(); else
parse_thread_stop=true; parse_mutex.unlock();
}
else {
parse_state=ParseState::STOP;
parse_mutex.unlock();
parse_error();
}
} }
else else
parse_done(); parse_mutex.unlock();
} }
} }
}); });
} }
void Source::ClangViewParse::soft_reparse() { void Source::ClangViewParse::soft_reparse() {
parse_thread_mapped=false;
parsed=false; parsed=false;
if(parse_state!=ParseState::WORKING)
return;
parse_process_state=ParseProcessState::IDLE;
delayed_reparse_connection.disconnect(); delayed_reparse_connection.disconnect();
delayed_reparse_connection=Glib::signal_timeout().connect([this]() { delayed_reparse_connection=Glib::signal_timeout().connect([this]() {
parsed=false; parsed=false;
parse_thread_go=true; auto expected=ParseProcessState::IDLE;
set_status("parsing..."); if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::STARTING))
set_status("parsing...");
return false; return false;
}, 1000); }, 1000);
} }
@ -655,7 +662,7 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_cancel_s
delete this; delete this;
}); });
do_full_reparse.connect([this](){ do_full_reparse.connect([this](){
init_parse(); parse_initialize();
full_reparse_running=false; full_reparse_running=false;
}); });
} }
@ -711,9 +718,8 @@ void Source::ClangViewAutocomplete::start_autocomplete() {
} }
void Source::ClangViewAutocomplete::autocomplete() { void Source::ClangViewAutocomplete::autocomplete() {
if(parse_thread_stop) { if(parse_state!=ParseState::WORKING)
return; return;
}
if(!autocomplete_starting) { if(!autocomplete_starting) {
autocomplete_starting=true; autocomplete_starting=true;
@ -815,14 +821,16 @@ void Source::ClangViewAutocomplete::autocomplete() {
pos--; pos--;
} }
autocomplete_thread=std::thread([this, ac_data, line_nr, column_nr, buffer](){ autocomplete_thread=std::thread([this, ac_data, line_nr, column_nr, buffer](){
parsing_mutex.lock(); parse_mutex.lock();
if(!parse_thread_stop) if(parse_state==ParseState::WORKING) {
parse_process_state=ParseProcessState::IDLE;
*ac_data=get_autocomplete_suggestions(buffer->raw(), line_nr, column_nr); *ac_data=get_autocomplete_suggestions(buffer->raw(), line_nr, column_nr);
if(!parse_thread_stop) }
if(parse_state==ParseState::WORKING)
autocomplete_done(); autocomplete_done();
else else
autocomplete_fail(); autocomplete_fail();
parsing_mutex.unlock(); parse_mutex.unlock();
}); });
} }
} }
@ -831,7 +839,8 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
std::vector<AutoCompleteData> suggestions; std::vector<AutoCompleteData> suggestions;
auto results=clang_tu->get_code_completions(buffer, line_number, column); auto results=clang_tu->get_code_completions(buffer, line_number, column);
if(results.cx_results==NULL) { if(results.cx_results==NULL) {
parse_thread_stop=true; auto expected=ParseState::WORKING;
parse_state.compare_exchange_strong(expected, ParseState::RESTARTING);
return suggestions; return suggestions;
} }
@ -863,7 +872,7 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
void Source::ClangViewAutocomplete::async_delete() { void Source::ClangViewAutocomplete::async_delete() {
parsing_in_progress->cancel("canceled, freeing resources in the background"); parsing_in_progress->cancel("canceled, freeing resources in the background");
parse_thread_stop=true; parse_state=ParseState::STOP;
delete_thread=std::thread([this](){ delete_thread=std::thread([this](){
//TODO: Is it possible to stop the clang-process in progress? //TODO: Is it possible to stop the clang-process in progress?
if(full_reparse_thread.joinable()) if(full_reparse_thread.joinable())
@ -877,10 +886,15 @@ void Source::ClangViewAutocomplete::async_delete() {
} }
bool Source::ClangViewAutocomplete::full_reparse() { bool Source::ClangViewAutocomplete::full_reparse() {
if(!full_reparse_running && !parse_error) { if(!full_reparse_running) {
auto expected=ParseState::WORKING;
if(!parse_state.compare_exchange_strong(expected, ParseState::RESTARTING)) {
expected=ParseState::RESTARTING;
if(!parse_state.compare_exchange_strong(expected, ParseState::RESTARTING))
return false;
}
soft_reparse_needed=false; soft_reparse_needed=false;
full_reparse_running=true; full_reparse_running=true;
parse_thread_stop=true;
if(full_reparse_thread.joinable()) if(full_reparse_thread.joinable())
full_reparse_thread.join(); full_reparse_thread.join();
full_reparse_thread=std::thread([this](){ full_reparse_thread=std::thread([this](){

26
src/source_clang.h

@ -12,6 +12,9 @@
namespace Source { namespace Source {
class ClangViewParse : public View { class ClangViewParse : public View {
protected:
enum class ParseProcessState {IDLE, STARTING, PREPROCESSING, PROCESSING, POSTPROCESSING};
enum class ParseState {WORKING, RESTARTING, STOP};
public: public:
class TokenRange { class TokenRange {
public: public:
@ -28,16 +31,12 @@ namespace Source {
void soft_reparse() override; void soft_reparse() override;
protected: protected:
void init_parse(); void parse_initialize();
std::unique_ptr<clang::TranslationUnit> clang_tu; std::unique_ptr<clang::TranslationUnit> clang_tu;
std::mutex parsing_mutex;
std::unique_ptr<clang::Tokens> clang_tokens; std::unique_ptr<clang::Tokens> clang_tokens;
sigc::connection delayed_reparse_connection; sigc::connection delayed_reparse_connection;
std::shared_ptr<Terminal::InProgress> parsing_in_progress; std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread;
std::atomic<bool> parse_thread_stop;
std::atomic<bool> parse_error;
void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override; void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override;
void show_type_tooltips(const Gdk::Rectangle &rectangle) override; void show_type_tooltips(const Gdk::Rectangle &rectangle) override;
@ -49,24 +48,25 @@ namespace Source {
std::set<int> diagnostic_offsets; std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its; std::vector<FixIt> fix_its;
std::thread parse_thread;
std::mutex parse_mutex;
std::atomic<ParseProcessState> parse_process_state;
std::atomic<ParseState> parse_state;
sigc::connection parse_done_connection; sigc::connection parse_done_connection;
sigc::connection parse_start_connection; sigc::connection parse_start_connection;
sigc::connection parse_fail_connection; sigc::connection parse_fail_connection;
private: private:
Glib::Dispatcher parse_preprocess;
Glib::Dispatcher parse_postprocess;
Glib::Dispatcher parse_error;
Glib::ustring parse_thread_buffer;
void update_syntax(); void update_syntax();
std::set<std::string> last_syntax_tags; std::set<std::string> last_syntax_tags;
void update_diagnostics(); void update_diagnostics();
static clang::Index clang_index; static clang::Index clang_index;
std::vector<std::string> get_compilation_commands(); std::vector<std::string> get_compilation_commands();
Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start;
Glib::Dispatcher parse_fail;
Glib::ustring parse_thread_buffer;
std::mutex parse_thread_buffer_mutex;
std::atomic<bool> parse_thread_go;
std::atomic<bool> parse_thread_mapped;
}; };
class ClangViewAutocomplete : public ClangViewParse { class ClangViewAutocomplete : public ClangViewParse {

Loading…
Cancel
Save