From 7490dcd95691b94b20d2103cf43281b356e29299 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 25 May 2017 17:46:25 -0400 Subject: [PATCH 22/28] FIXME: initial hacked up multithreaded implementation --- gcc/checkers.c | 145 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 34 deletions(-) diff --git a/gcc/checkers.c b/gcc/checkers.c index 38a8067..9487c5d 100644 --- a/gcc/checkers.c +++ b/gcc/checkers.c @@ -22,9 +22,10 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "options.h" #include "diagnostic.h" -#include "selftest.h" // FIXME +#include "selftest.h" #include "firehose.h" #include "json.h" +#include /* FIXME. */ @@ -234,6 +235,19 @@ auto_argvec::~auto_argvec () /* FIXME. */ +struct thread_result +{ + thread_result (char *utf8_buffer, char *err) + : m_utf8_buffer (utf8_buffer), m_err (err) {} + + ~thread_result () { free (m_utf8_buffer); free (m_err); } + + char *m_utf8_buffer; + char *m_err; +}; + +/* FIXME. */ + class checker { public: @@ -242,12 +256,20 @@ class checker static checker *from_json (const json::value *jv, char *&out_err); - void run (); + void start (); + void finish (); + void run_single_threaded (); - char *m_executable; + const char *get_executable () const { return m_executable; } private: + static void *run_checker_thread (void *ptr); + thread_result *run_in_thread (); + char *capture_stdout (char *&out_err); void make_args (auto_argvec &out) const; + + char *m_executable; + pthread_t m_tid; }; /* FIXME. */ @@ -295,38 +317,94 @@ checker::from_json (const json::value *jv, char *&out_err) return ch; } -#if 0 +void * +checker::run_checker_thread (void *ptr) +{ + checker *ch = static_cast (ptr); + return ch->run_in_thread (); +} + +/* FIXME. */ -class pex_wrapper +void +checker::start () { - public: - pex_wrapper (int flags, const char *pname, const char *tempbase); - ~pex_wrapper (); + pthread_create (&m_tid, + NULL, + run_checker_thread, + this); +} - private: - pex_wrapper_obj *m_obj; -}; +// FIXME: hacking in -lpthread for now /* FIXME. */ -pex_wrapper::pex_wrapper (int flags, const char *pname, const char *tempbase) +// This is run on the main thread + +void +checker::finish () { - m_obj = pex_init (flags, pname, tempbase); + /* Wait for the thread to finish. */ + void *retval; + if (!pthread_join (m_tid, &retval)) + ; // FIXME + thread_result *result = static_cast (retval); + + /* Process the output. */ + if (!result->m_utf8_buffer) + { + error_at (UNKNOWN_LOCATION, "error invoking checker %qs: %qs", + m_executable, result->m_err); + delete result; + return; + } + handle_json (result->m_utf8_buffer); + delete result; } /* FIXME. */ +// This is run within the per-checker thread -pex_wrapper::~pex_wrapper () +thread_result * +checker::run_in_thread () { - pex_free (m_obj); -} + // FIXME: error-handling in capture_stdout isn't fully thread-safe yet + char *err = NULL; + char *utf8_buffer = capture_stdout (err); -#endif + return new thread_result (utf8_buffer, err); +} /* FIXME. */ void -checker::run () +checker::run_single_threaded () +{ + char *err = NULL; + char *utf8_buffer = capture_stdout (err); + if (!utf8_buffer) + { + error_at (UNKNOWN_LOCATION, "error invoking checker %qs: %qs", + m_executable, err); + free (err); + return; + } + handle_json (utf8_buffer); + free (utf8_buffer); +} + +/* Run the checker, capturing its stdout. + + Return a buffer containing the captured stdout, which must be freed + by the caller. */ + +// FIXME: not thread-safe: error-handling can call error_at +// maybe make error-handling work by writing to an out_err + +// FIXME: this assumes that pex is thread-safe + +char * +checker::capture_stdout (char *&out_err) { auto_argvec argvec; @@ -357,16 +435,15 @@ checker::run () if (!pex_get_status (obj, 1, &exit_status)) { err = 0; - errmsg = "pex_get_status failed"; + out_err = xstrdup ("pex_get_status failed"); } } FILE *outf = pex_read_output (obj, 0); if (!outf) { - error_at (UNKNOWN_LOCATION, "error invoking checker %qs: %qs", - m_executable, "unable to read stdout"); - return; + out_err = xstrdup ("unable to read stdout"); + return NULL; } /* "outf" is owned by "obj". */ @@ -378,21 +455,17 @@ checker::run () if (errmsg) { - error_at (UNKNOWN_LOCATION, "error invoking checker %qs: %qs", - m_executable, errmsg); - return; + out_err = xstrdup (errmsg); + return NULL; } if (exit_status || err) { - error_at (UNKNOWN_LOCATION, - "error invoking checker %qs: exit_status: %i err: %i", - m_executable, exit_status, err); - return; + out_err = xasprintf ("exit_status: %i err: %i", + exit_status, err); + return NULL; } - // FIXME: error-checking - handle_json (utf8_buffer); - free (utf8_buffer); + return utf8_buffer; } /* FIXME. */ @@ -486,7 +559,11 @@ run_analyzers (const char *path) int i; checker *ch; FOR_EACH_VEC_ELT (p.m_checkers, i, ch) - ch->run (); + ch->start (); + + FOR_EACH_VEC_ELT (p.m_checkers, i, ch) + ch->finish (); + } #if CHECKING_P @@ -510,7 +587,7 @@ test_policy_parsing () ASSERT_EQ (4, p.m_checkers.length ()); ASSERT_STREQ ("../../src/checkers/clang_analyzer.py", - p.m_checkers[0]->m_executable); + p.m_checkers[0]->get_executable ()); } /* Run all of the selftests within this file. */ -- 1.8.5.3