This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: threading updates
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 12 Feb 2005 20:30:47 -0700
- Subject: [gcjx] Patch: FYI: threading updates
- Reply-to: tromey at redhat dot com
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);
}
};