From c8b200965f0f8c500a9d12b1570e41869d88f1c8 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 25 May 2017 19:20:04 -0400
Subject: [PATCH 23/38] FIXME: start the checker threads before the main
 compile

---
 gcc/checkers.c | 72 +++++++++++++++++++++++++++++++++++++++++++++-------------
 gcc/toplev.c   | 16 ++++++++-----
 2 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/gcc/checkers.c b/gcc/checkers.c
index 9487c5d..83b27fe 100644
--- a/gcc/checkers.c
+++ b/gcc/checkers.c
@@ -149,7 +149,10 @@ handle_failure (const firehose::analysis &analysis,
 
 /* Given UTF8_BUFFER, a non-NULL UTF-8-encoded buffer of JSON output
    from a tool, in Firehose JSON format, emit the results through GCC's
-   diagnostic subsystem.  */
+   diagnostic subsystem.
+   This must be run on the main thread (firehose::analysis::from_json can
+   touch the global line_table, and error_at and the other diagnostic
+   emission requires the main thread).   */
 
 static void
 handle_json (const char *utf8_buffer)
@@ -317,6 +320,9 @@ checker::from_json (const json::value *jv, char *&out_err)
   return ch;
 }
 
+/* FIXME.  */
+// This is run within the per-checker thread
+
 void *
 checker::run_checker_thread (void *ptr)
 {
@@ -326,6 +332,8 @@ checker::run_checker_thread (void *ptr)
 
 /* FIXME.  */
 
+// This is run on the main thread
+
 void
 checker::start ()
 {
@@ -396,12 +404,12 @@ checker::run_single_threaded ()
 /* Run the checker, capturing its stdout.
 
    Return a buffer containing the captured stdout, which must be freed
-   by the caller.  */
+   by the caller.
 
-// FIXME: not thread-safe: error-handling can call error_at
-// maybe make error-handling work by writing to an out_err
+   This can be run either on the main thread, or within the
+   per-checker thread.  */
 
-// FIXME: this assumes that pex is thread-safe
+// FIXME: this assumes that pex is thread-safe; is it?
 
 char *
 checker::capture_stdout (char *&out_err)
@@ -468,7 +476,8 @@ checker::capture_stdout (char *&out_err)
   return utf8_buffer;
 }
 
-/* FIXME.  */
+/* FIXME.
+   This can be run within the per-checker thread.  */
 
 void
 checker::make_args (auto_argvec &out) const
@@ -535,18 +544,19 @@ policy::read_from_file (const char *path, char *&out_err)
   return true;
 }
 
+static bool use_threads = true; // FIXME; move to class policy?
+static policy *the_policy = NULL;
+
 /* FIXME.  */
 
 void
-run_analyzers (const char *path)
+checkers_start (const char *path)
 {
-  if (0)
-    inform (UNKNOWN_LOCATION, "run_analyzers (%qs)", path);
+  the_policy = new policy ();
 
   /* Try to load a policy file.  */
-  policy p;
   char *err = NULL;
-  if (!p.policy::read_from_file (path, err))
+  if (!the_policy->read_from_file (path, err))
     {
       error_at (UNKNOWN_LOCATION,
 		"unable to load checker policy %qs: %qs",
@@ -555,15 +565,45 @@ run_analyzers (const char *path)
       return;
     }
 
-  /* Run the checkers specified by the policy.  */
+  /* If using threads, start the checkers specified by the policy now,
+     each on their own thread.  */
+
+  int i;
+  checker *ch;
+  if (use_threads)
+    {
+      FOR_EACH_VEC_ELT (the_policy->m_checkers, i, ch)
+	ch->start ();
+    }
+}
+
+/* FIXME.  */
+/* If using threads, wait for each checker thread to finish, and flush
+   the results.
+   Otherwise, run each checker now in the main thread, sequentially.  */
+
+void
+checkers_finish ()
+{
   int i;
   checker *ch;
-  FOR_EACH_VEC_ELT (p.m_checkers, i, ch)
-    ch->start ();
 
-  FOR_EACH_VEC_ELT (p.m_checkers, i, ch)
-    ch->finish ();
+  /* This should have been created in checkers_start.  */
+  gcc_assert (the_policy);
+
+  if (use_threads)
+    {
+      FOR_EACH_VEC_ELT (the_policy->m_checkers, i, ch)
+	ch->finish ();
+    }
+  else
+    {
+      FOR_EACH_VEC_ELT (the_policy->m_checkers, i, ch)
+	ch->run_single_threaded ();
+    }
 
+  delete the_policy;
+  the_policy = NULL;
 }
 
 #if CHECKING_P
diff --git a/gcc/toplev.c b/gcc/toplev.c
index e0df0b6..0bda9c8 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1960,6 +1960,9 @@ standard_type_bitsize (int bitsize)
   return false;
 }
 
+extern void checkers_start (const char *path);
+extern void checkers_finish ();
+
 /* Initialize the compiler, and compile the input file.  */
 static void
 do_compile ()
@@ -1971,6 +1974,9 @@ do_compile ()
     {
       int i;
 
+      if (flag_run_analyzers)
+	checkers_start (flag_run_analyzers);
+
       timevar_start (TV_PHASE_SETUP);
 
       /* This must be run always, because it is needed to compute the FP
@@ -2020,6 +2026,10 @@ do_compile ()
       finalize (no_backend);
 
       timevar_stop (TV_PHASE_FINALIZE);
+
+      /* FIXME.  */
+      if (flag_run_analyzers)
+	checkers_finish ();
     }
 }
 
@@ -2081,8 +2091,6 @@ toplev::run_self_tests ()
 #endif /* #if CHECKING_P */
 }
 
-extern void run_analyzers (const char *path);
-
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
    Exit code is FATAL_EXIT_CODE if can't open files or if there were
    any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
@@ -2167,10 +2175,6 @@ toplev::main (int argc, char **argv)
       pp_flush (&pp);
     }
 
-  /* FIXME.  */
-  if (flag_run_analyzers)
-    run_analyzers (flag_run_analyzers);
-
   diagnostic_finish (global_dc);
 
   finalize_plugins ();
-- 
1.8.5.3

