This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gcjx] Patch: FYI: threading updates


I'm checking this in on the gcjx branch.

This is actually a combination of two patches from my monotone
history, so I rediffed this one.

This patch reworks thread.hh a little, and does some more work on
compiler to get us closer to multi-threading capability.  However,
this also disables the threading code, as there are still more bugs in
this area -- in particular parsing can cause package creation as a
side effect, and this is not guarded against.  Also, at some places we
try to acquire mutexes recursively (all that java programming causing
bad habits :-), which thread.hh did not account for.

Perhaps the threading stuff is a bad idea.  I'm not sure yet.  Luckily
it does not deeply affect the structure of gcjx; we can remove it if
it turns out not to be that useful.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* thread/thread.hh: Disable.

	* main.cc (gcjx_main): Pause workers.
	* compiler.cc (compiler): Initialize pause_count.
	(dispatch_job): Handle PAUSE.
	(pause_workers): New method.
	* compiler.hh (compiler::pause_monitor): New field.
	(compiler::pause_condition): Likewise.
	(compiler::pause_count): Likewise.
	(compiler::pause_waiter): Likewise.
	(PAUSE): New enum constant.
	(compiler::pause_workers): Declare.

	* Makefile.am (gcjx_LDADD): Added -lpthread.
	* directory.cc (add): Updated.
	* classcache.cc (find_class): Updated.
	* classcache.hh (class_cache::mutex): Changed type.
	(class_cache): Updated.
	* compiler.cc (add_unit): Updated.
	(generate_code): Likewise.
	(add_job): Likewise.
	(work): Likewise.
	* thread/thread.hh: Rewrote.
	* main.cc (class argument_parser): Enable -j.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/Makefile.am,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 Makefile.am
--- Makefile.am 30 Jan 2005 02:27:58 -0000 1.1.2.3
+++ Makefile.am 13 Feb 2005 03:30:00 -0000
@@ -8,7 +8,7 @@
 ################################################################
 
 gcjx_SOURCES = main.cc
-gcjx_LDADD = libgcjx.la
+gcjx_LDADD = libgcjx.la -lpthread
 
 libgcjx_la_SOURCES = $(dot_sources) $(model_sources) $(reader_sources) \
 $(source_sources) $(format_sources) $(bytecode_sources)	\
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/Makefile.in,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 Makefile.in
--- Makefile.in 30 Jan 2005 02:27:58 -0000 1.1.2.4
+++ Makefile.in 13 Feb 2005 03:30:01 -0000
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# Makefile.in generated by automake 1.9.2 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -265,7 +265,7 @@
 
 ################################################################
 gcjx_SOURCES = main.cc
-gcjx_LDADD = libgcjx.la
+gcjx_LDADD = libgcjx.la -lpthread
 libgcjx_la_SOURCES = $(dot_sources) $(model_sources) $(reader_sources) \
 $(source_sources) $(format_sources) $(bytecode_sources)	\
 $(header_sources) $(fdlibm_c_sources) $(fdlibm_cc_sources) \
Index: PROJECTS
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/PROJECTS,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 PROJECTS
--- PROJECTS 30 Jan 2005 02:27:58 -0000 1.1.2.3
+++ PROJECTS 13 Feb 2005 03:30:01 -0000
@@ -27,9 +27,8 @@
 - where should model_package call resolve_annotations ?
 
 enums partly work.  They are completely untested but much of the code
-is there.  some code generation work remains (at least switches on
-enum type).  a little semantic analysis work remains, including
-missing error checking
+is there.  some code generation work remains.  a little semantic
+analysis work remains, including missing error checking
 
 Generics partly work.  Generic methods have not been implemented at
 all.
@@ -122,8 +121,6 @@
 here.  (Having a mode for "gcjx --verify-only" would be very useful
 right now!)
 
-The bytecode generator doesn't emit debug information.
-
 JNI header generation is probably ok
 
 CNI stub generation is not implemented
Index: TODO
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/TODO,v
retrieving revision 1.1.2.14
diff -u -r1.1.2.14 TODO
--- TODO 13 Feb 2005 03:22:41 -0000 1.1.2.14
+++ TODO 13 Feb 2005 03:30:02 -0000
@@ -272,8 +272,9 @@
 - must implement gcjh hacks for C++ keywords and method/field name
   clash
 - must implement gcjh hack for field alignment
-- implement the write-to-temp file thing that bytecode uses?
+X implement the write-to-temp file thing that bytecode uses?
   gcjh doesn't, perhaps we don't need this
+  [ we don't because we build all the headers before any .cc files ]
 
 ================================================================
 
@@ -281,6 +282,7 @@
 
 we should factor out things like object layout, etc, so that
 we can reuse the bulk of this code with LLVM
+  [ done ]
 
 build_address_of() the functions we call
 document this in tree.def:call_expr ?
Index: aclocal.m4
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/aclocal.m4,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 aclocal.m4
--- aclocal.m4 13 Jan 2005 03:18:33 -0000 1.1.2.1
+++ aclocal.m4 13 Feb 2005 03:30:02 -0000
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.9.3 -*- Autoconf -*-
+# generated automatically by aclocal 1.9.2 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
 # Free Software Foundation, Inc.
@@ -40,7 +40,7 @@
 # Call AM_AUTOMAKE_VERSION so it can be traced.
 # This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-	 [AM_AUTOMAKE_VERSION([1.9.3])])
+	 [AM_AUTOMAKE_VERSION([1.9.2])])
 
 # AM_AUX_DIR_EXPAND
 
Index: classcache.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/classcache.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 classcache.cc
--- classcache.cc 13 Jan 2005 03:18:33 -0000 1.1.2.1
+++ classcache.cc 13 Feb 2005 03:30:02 -0000
@@ -1,6 +1,6 @@
 // Class cache implementation.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -24,7 +24,7 @@
 void
 class_cache::find_class ()
 {
-  concurrence::sync::lock_sentinel sync (mutex);
+  concurrence::exclusive_mutex::lock_sentinel sync (mutex);
   // We could require the compiler as an argument to the constructor.
   cache = global->get_compiler ()->find_class (name);
   if (! cache)
Index: classcache.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/classcache.hh,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 classcache.hh
--- classcache.hh 13 Jan 2005 03:18:33 -0000 1.1.2.1
+++ classcache.hh 13 Feb 2005 03:30:02 -0000
@@ -1,6 +1,6 @@
 // Look up and cache classes.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -31,7 +31,7 @@
   model_class *cache;
 
   /// The mutex on which to synchronize.
-  concurrence::sync &mutex;
+  concurrence::exclusive_mutex &mutex;
 
   // This is here to make it impossible for user code to try to use
   // this class as anything other than a cache.
@@ -44,7 +44,7 @@
 
 public:
 
-  class_cache (concurrence::sync &m, const char *n)
+  class_cache (concurrence::exclusive_mutex &m, const char *n)
     : name (n),
       cache (NULL),
       mutex (m)
Index: compiler.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/compiler.cc,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 compiler.cc
--- compiler.cc 23 Jan 2005 00:36:54 -0000 1.1.2.2
+++ compiler.cc 13 Feb 2005 03:30:02 -0000
@@ -29,6 +29,8 @@
     multi_threaded (0),
     mt_monitor (),
     mt_condition (mt_monitor),
+    pause_monitor (),
+    pause_condition (pause_monitor),
     factory (NULL),
     primordial_package (new model_primordial_package ()),
     unnamed_package (new model_unnamed_package ()),
@@ -158,7 +160,7 @@
 void
 compiler::add_unit (const ref_unit &unit, bool emit_code)
 {
-  concurrence::sync::lock_sentinel sync (mt_monitor);
+  concurrence::exclusive_mutex::lock_sentinel sync (mt_monitor);
   units.push_back (unit);
   if (emit_code && (pre_semantic_analysis || generating_bytecode))
     code_generation_units.push_back (unit);
@@ -227,15 +229,13 @@
 {
   pre_semantic_analysis = false;
 
-  // FIXME: here we need a way to wait until all the worker threads
-  // have parsed the input files.
-
   for (std::list<ref_unit>::const_iterator i = code_generation_units.begin ();
        ok && i != code_generation_units.end ();
        ++i)
-    {
-      do_analyze_unit ((*i).get ());
-    }
+    // Note that we do this single-threaded, as we don't have support
+    // for MT semantic analysis.
+    do_analyze_unit ((*i).get ());
+
   return ok;
 }
 
@@ -266,7 +266,7 @@
   // FIXME: it would make more sense, perhaps, to turn this thread
   // into a worker as well...?
   {
-    concurrence::sync::lock_sentinel sync (mt_monitor);
+    concurrence::exclusive_mutex::lock_sentinel sync (mt_monitor);
     while (multi_threaded)
       mt_condition.wait ();
   }
@@ -386,7 +386,7 @@
 {
   if (multi_threaded)
     {
-      concurrence::sync::lock_sentinel sync (work_monitor);
+      concurrence::exclusive_mutex::lock_sentinel sync (work_monitor);
       work_list.push_back (job);
       work_condition.signal ();
     }
@@ -409,6 +409,17 @@
     case GENERATE_CODE:
       do_generate_code (job.unit);
       break;
+    case PAUSE:
+      {
+	{
+	  concurrence::exclusive_mutex::lock_sentinel hold (pause_monitor);
+	  pause_condition.signal ();
+	}
+	// Now wait on the pause mutex.  Since we release it as soon
+	// as we acquire it, this lets all the workers proceed.
+	concurrence::exclusive_mutex::lock_sentinel hold (pause_waiter);
+      }
+      break;
     case DIE:
       // We're done.
       result = true;
@@ -420,10 +431,8 @@
 void
 compiler::work ()
 {
-  assert (0 && "thread code stubbed out for the time being");
-
   {
-    concurrence::sync::lock_sentinel sync (mt_monitor);
+    concurrence::exclusive_mutex::lock_sentinel sync (mt_monitor);
     ++multi_threaded;
   }
 
@@ -435,7 +444,7 @@
 	  work_item job;
 
 	  {
-	    concurrence::sync::lock_sentinel sync (work_monitor);
+	    concurrence::exclusive_mutex::lock_sentinel sync (work_monitor);
 	    while (work_list.empty ())
 	      work_condition.wait ();
 	    // Pop the work item while we still hold the mutex.
@@ -449,19 +458,43 @@
     }
   catch (...)
     {
-      concurrence::sync::lock_sentinel sync (mt_monitor);
+      concurrence::exclusive_mutex::lock_sentinel sync (mt_monitor);
       --multi_threaded;
       mt_condition.signal ();
 
       throw;
     }
 
-  concurrence::sync::lock_sentinel sync (mt_monitor);
+  concurrence::exclusive_mutex::lock_sentinel sync (mt_monitor);
   --multi_threaded;
   mt_condition.signal ();
 }
 
 void
+compiler::pause_workers ()
+{
+  if (! multi_threaded)
+    return;
+
+  // Acquire the lock used for pausing.
+  concurrence::exclusive_mutex::lock_sentinel outer (pause_waiter);
+
+  // Acquire the lock that controls the counter.
+  concurrence::exclusive_mutex::lock_sentinel inner (pause_monitor);
+
+  // Tell each thread to pause.
+  for (int i = 0; i < multi_threaded; ++i)
+    {
+      work_item job (PAUSE);
+      add_job (job);
+    }
+
+  // Wait for each thread to report back.
+  for (int i = 0; i < multi_threaded; ++i)
+    pause_condition.wait ();
+}
+
+void
 compiler::do_load_source_file (const std::string &filename)
 {
   if (! factory->load_source_file (filename))
Index: compiler.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/compiler.hh,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 compiler.hh
--- compiler.hh 23 Jan 2005 00:36:54 -0000 1.1.2.2
+++ compiler.hh 13 Feb 2005 03:30:02 -0000
@@ -70,6 +70,7 @@
     PARSE,
     ANALYZE,
     GENERATE_CODE,
+    PAUSE,
     DIE
   } job_type;
 
@@ -136,6 +137,14 @@
   // Work items.
   std::deque<work_item> work_list;
 
+  // This monitor and condition are acquired when waiting for worker
+  // threads to pause.
+  concurrence::exclusive_mutex pause_monitor;
+  concurrence::exclusive_condition pause_condition;
+
+  // This is held when waiting for worker threads to pause.
+  concurrence::exclusive_mutex pause_waiter;
+
   // The class path we search.
   classpath_class_factory *factory;
 
@@ -422,6 +431,9 @@
 
   /// Register the current thread as a worker thread for the compiler.
   void work ();
+
+  /// FIXME: this probably shouldn't be public...
+  void pause_workers ();
 };
 
 #endif // GCJX_COMPILER_HH
Index: directory.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/directory.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 directory.cc
--- directory.cc 13 Jan 2005 03:18:33 -0000 1.1.2.1
+++ directory.cc 13 Feb 2005 03:30:02 -0000
@@ -1,6 +1,6 @@
 // Directory cache.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -44,7 +44,7 @@
 std::string
 directory_cache::add (model_class *klass, const std::string &suffix)
 {
-  concurrence::sync::lock_sentinel sync (monitor);
+  concurrence::exclusive_mutex::lock_sentinel sync (monitor);
   std::list<std::string> qualname = split (klass->get_fully_qualified_name (),
 					   '.');
   std::string partial = base;
Index: main.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/Attic/main.cc,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 main.cc
--- main.cc 23 Jan 2005 00:36:54 -0000 1.1.2.2
+++ main.cc 13 Feb 2005 03:30:02 -0000
@@ -453,13 +453,8 @@
 	  dash_i_args.push_back (get_arg_for (it, "-I", false));
         else if (arg == "-j")
 	  {
-#if 1
-	    throw make_error ("thread support is stubbed out until "
-		              "libthread++ is released");
-#else
 	    std::string threads (get_next_arg (it, arg));
-	    n_threads = atoi (arg);
-#endif
+	    n_threads = atoi (threads.c_str ());
 	  }
 	else if (is_form_of (it, "-source"))
 	  set_source (get_arg_for (it, "-source"));
@@ -526,7 +521,7 @@
 
     // Start the worker threads.
     for (int i = 0; i < n_threads; ++i)
-      concurrence::make_thread (*comp, &compiler::work).start ();
+      concurrence::make_thread (comp, &compiler::work).start ();
 
     return source_files;
   }
@@ -555,6 +550,8 @@
   std::deque<std::string>::const_iterator it = source_files.begin ();
   for (; it != source_files.end (); ++it)
     global->get_compiler ()->load_source_file (*it);
+  // Make sure we don't do any analysis before the parsing is done.
+  global->get_compiler ()->pause_workers ();
 
   if (! global->get_compiler ()->semantic_analysis ())
     return 1;
Index: thread/thread.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/thread/Attic/thread.hh,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 thread.hh
--- thread/thread.hh 13 Jan 2005 03:18:37 -0000 1.1.2.1
+++ thread/thread.hh 13 Feb 2005 03:30:02 -0000
@@ -1,6 +1,6 @@
 // Thread definitions.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -22,46 +22,85 @@
 #ifndef GCJX_THREAD_THREAD_HH
 #define GCJX_THREAD_THREAD_HH
 
+// #include <pthread.h>
+
 /// Note that this is just stubs.  The names come from Benjamin
 /// Kosnik's libthread++, which isn't checked in anywhere yet.
 /// Meanwhile this implements exactly the subset used by gcjx.
 namespace concurrence
 {
-  // Mutex base class.
-  class sync
+  class exclusive_condition;
+
+  class exclusive_mutex
   {
+//     pthread_mutex_t lock;
+
+    friend class exclusive_condition;
+
   public:
 
+    exclusive_mutex ()
+    {
+      // FIXME: we must use a recursive mutex here due to uses in
+      // compiler, but last time I looked (quite a long time ago),
+      // recursive mutexes did not work properly with condition
+      // variables.
+//       pthread_mutex_init (&lock, NULL);
+    }
+
+    ~exclusive_mutex ()
+    {
+//       pthread_mutex_destroy (&lock);
+    }
+
     // Acquire and release a mutex using RAII.
     class lock_sentinel
     {
+      exclusive_mutex &m;
+
     public:
 
-      lock_sentinel (const sync &)
+      lock_sentinel (exclusive_mutex &mu)
+	: m (mu)
       {
+// 	pthread_mutex_lock (&m.lock);
       }
-    };
-  };
 
-  class exclusive_mutex : public sync
-  {
+      ~lock_sentinel ()
+      {
+// 	pthread_mutex_unlock (&m.lock);
+      }
+    };
   };
 
   // Condition variable.
   class exclusive_condition
   {
+    exclusive_mutex &m;
+
+//     pthread_cond_t cond;
+
   public:
 
-    exclusive_condition (const exclusive_mutex &)
+    exclusive_condition (exclusive_mutex &mu)
+      : m (mu)
+    {
+//       pthread_cond_init (&cond, NULL);
+    }
+
+    ~exclusive_condition ()
     {
+//       pthread_cond_destroy (&cond);
     }
 
     void wait ()
     {
+//       pthread_cond_wait (&cond, &m.lock);
     }
 
     void signal ()
     {
+//       pthread_cond_signal (&cond);
     }
   };
 
@@ -86,19 +125,41 @@
     }
   };
 
+  template<typename T>
   class thread
   {
+    T *obj;
+
+    void (T::*fn) ();
+
+    pthread_t thr;
+
+    static void *do_start (void *val)
+    {
+      thread *self = reinterpret_cast<thread *> (val);
+      ((self->obj)->*(self->fn)) ();
+      return NULL;
+    }
+
   public:
 
+    thread (T *o, void (T::*f) ())
+      : obj (o),
+	fn (f)
+    {
+    }
+
     void start ()
     {
+      abort ();
+//       pthread_create (&thr, NULL, do_start, this);
     }
   };
 
   template<typename T>
-  thread make_thread (const T &obj, void (T::*fn) ())
+  thread<T> make_thread (T *obj, void (T::*fn) ())
   {
-    abort ();
+    return thread<T> (obj, fn);
   }
 };
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]