aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-08-06 23:54:48 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-08-06 23:54:48 +0000
commitdf86259eedbe962f522a4a3fd5b60c91d52db170 (patch)
treef44514c3082da9e70466649c49da019e55566509
parentb1303fc4c597273b05a723f1eeb329b4d66b080e (diff)
downloadpaludis-df86259eedbe962f522a4a3fd5b60c91d52db170.tar.gz
paludis-df86259eedbe962f522a4a3fd5b60c91d52db170.tar.xz
More thread work
-rw-r--r--paludis/repositories/e/qa/qa_controller.cc93
-rw-r--r--paludis/repositories/e/qa/qa_controller.hh7
-rw-r--r--paludis/util/files.m41
-rw-r--r--paludis/util/future.cc64
-rw-r--r--paludis/util/future.hh14
-rw-r--r--paludis/util/future_TEST.cc21
-rw-r--r--paludis/util/parallel_for_each.cc28
-rw-r--r--paludis/util/parallel_for_each.hh39
-rw-r--r--paludis/util/parallel_for_each_TEST.cc64
9 files changed, 300 insertions, 31 deletions
diff --git a/paludis/repositories/e/qa/qa_controller.cc b/paludis/repositories/e/qa/qa_controller.cc
index 743f7ef..0912b9b 100644
--- a/paludis/repositories/e/qa/qa_controller.cc
+++ b/paludis/repositories/e/qa/qa_controller.cc
@@ -24,14 +24,39 @@
#include <paludis/util/tr1_functional.hh>
#include <paludis/util/set.hh>
#include <paludis/util/sequence.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/parallel_for_each.hh>
+#include <paludis/qa.hh>
#include <libwrapiter/libwrapiter_forward_iterator.hh>
#include <algorithm>
+#include <list>
using namespace paludis;
using namespace paludis::erepository;
+namespace
+{
+ struct ThreadSafeQAReporter :
+ QAReporter
+ {
+ QAReporter & base;
+ Mutex mutex;
+
+ ThreadSafeQAReporter(QAReporter & b) :
+ base(b)
+ {
+ }
+
+ void message(QAMessageLevel l, const std::string & s, const std::string & t)
+ {
+ Lock lock(mutex);
+ base.message(l, s, t);
+ }
+ };
+}
+
namespace paludis
{
template <>
@@ -42,7 +67,7 @@ namespace paludis
const QACheckProperties & ignore_if;
const QACheckProperties & ignore_unless;
const QAMessageLevel minimum_level;
- QAReporter & reporter;
+ ThreadSafeQAReporter reporter;
Implementation(
const Environment * const e,
@@ -81,6 +106,42 @@ QAController::~QAController()
}
void
+QAController::_run_category(const CategoryNamePart & c)
+{
+ using namespace tr1::placeholders;
+
+ std::find_if(
+ QAChecks::get_instance()->category_dir_checks_group()->begin(),
+ QAChecks::get_instance()->category_dir_checks_group()->end(),
+ tr1::bind(std::equal_to<bool>(), false,
+ tr1::bind<bool>(tr1::mem_fn(&CategoryDirCheckFunction::operator() ),
+ _1, tr1::ref(_imp->reporter), _imp->env, _imp->repo, _imp->repo->layout()->category_directory(c))));
+
+ tr1::shared_ptr<const QualifiedPackageNameSet> packages(_imp->repo->package_names(c));
+ parallel_for_each(packages->begin(), packages->end(), tr1::bind(&QAController::_run_package, this, _1));
+}
+
+void
+QAController::_run_package(const QualifiedPackageName & p)
+{
+ using namespace tr1::placeholders;
+ tr1::shared_ptr<const PackageIDSequence> ids(_imp->repo->package_ids(p));
+ parallel_for_each(ids->begin(), ids->end(), tr1::bind(&QAController::_run_id, this, _1));
+}
+
+void
+QAController::_run_id(const tr1::shared_ptr<const PackageID> & i)
+{
+ using namespace tr1::placeholders;
+ std::find_if(
+ QAChecks::get_instance()->package_id_checks_group()->begin(),
+ QAChecks::get_instance()->package_id_checks_group()->end(),
+ tr1::bind(std::equal_to<bool>(), false,
+ tr1::bind<bool>(tr1::mem_fn(&PackageIDCheckFunction::operator() ),
+ _1, tr1::ref(_imp->reporter), _imp->env, _imp->repo, tr1::static_pointer_cast<const ERepositoryID>(i))));
+}
+
+void
QAController::run()
{
using namespace tr1::placeholders;
@@ -93,34 +154,6 @@ QAController::run()
_1, tr1::ref(_imp->reporter), _imp->env, _imp->repo, _imp->repo->params().location)));
tr1::shared_ptr<const CategoryNamePartSet> categories(_imp->repo->category_names());
- for (CategoryNamePartSet::Iterator c(categories->begin()), c_end(categories->end()) ;
- c != c_end ; ++c)
- {
- std::find_if(
- QAChecks::get_instance()->category_dir_checks_group()->begin(),
- QAChecks::get_instance()->category_dir_checks_group()->end(),
- tr1::bind(std::equal_to<bool>(), false,
- tr1::bind<bool>(tr1::mem_fn(&CategoryDirCheckFunction::operator() ),
- _1, tr1::ref(_imp->reporter), _imp->env, _imp->repo, _imp->repo->layout()->category_directory(*c))));
-
- tr1::shared_ptr<const QualifiedPackageNameSet> packages(_imp->repo->package_names(*c));
- for (QualifiedPackageNameSet::Iterator p(packages->begin()), p_end(packages->end()) ;
- p != p_end ; ++p)
- {
-
- tr1::shared_ptr<const PackageIDSequence> ids(_imp->repo->package_ids(*p));
- for (PackageIDSequence::Iterator i(ids->begin()), i_end(ids->end()) ;
- i != i_end ; ++i)
- {
- std::find_if(
- QAChecks::get_instance()->package_id_checks_group()->begin(),
- QAChecks::get_instance()->package_id_checks_group()->end(),
- tr1::bind(std::equal_to<bool>(), false,
- tr1::bind<bool>(tr1::mem_fn(&PackageIDCheckFunction::operator() ),
- _1, tr1::ref(_imp->reporter), _imp->env, _imp->repo, tr1::static_pointer_cast<const ERepositoryID>(*i))));
- }
- }
- }
-
+ parallel_for_each(categories->begin(), categories->end(), tr1::bind(&QAController::_run_category, this, _1));
}
diff --git a/paludis/repositories/e/qa/qa_controller.hh b/paludis/repositories/e/qa/qa_controller.hh
index 3a2c554..d47483d 100644
--- a/paludis/repositories/e/qa/qa_controller.hh
+++ b/paludis/repositories/e/qa/qa_controller.hh
@@ -27,6 +27,8 @@
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/qa-fwd.hh>
#include <paludis/environment-fwd.hh>
+#include <paludis/name-fwd.hh>
+#include <paludis/package_id-fwd.hh>
#include <libwrapiter/libwrapiter_forward_iterator-fwd.hh>
@@ -39,6 +41,11 @@ namespace paludis
class QAController :
private PrivateImplementationPattern<QAController>
{
+ private:
+ void _run_category(const CategoryNamePart &);
+ void _run_package(const QualifiedPackageName &);
+ void _run_id(const tr1::shared_ptr<const PackageID> &);
+
public:
QAController(
const Environment * const,
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index f6466de..ad008d5 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -33,6 +33,7 @@ add(`mutex', `hh', `cc', `test')
add(`operators', `hh')
add(`options', `hh', `fwd', `cc', `test')
add(`output_wrapper', `test', `testscript')
+add(`parallel_for_each', `hh', `cc', `test')
add(`pipe', `hh', `cc')
add(`private_implementation_pattern', `hh', `impl')
add(`pstream', `hh', `cc', `test')
diff --git a/paludis/util/future.cc b/paludis/util/future.cc
index 4f21547..02ab7a9 100644
--- a/paludis/util/future.cc
+++ b/paludis/util/future.cc
@@ -27,7 +27,7 @@ using namespace paludis;
template class InstantiationPolicy<FutureActionQueue, instantiation_method::SingletonTag>;
FutureActionQueue::FutureActionQueue() :
- ActionQueue(destringify<int>(getenv_with_default("PALUDIS_FUTURE_THREAD_COUNT", "2")), true)
+ ActionQueue(destringify<int>(getenv_with_default("PALUDIS_FUTURE_THREAD_COUNT", "5")), true)
{
}
@@ -35,3 +35,65 @@ FutureActionQueue::~FutureActionQueue()
{
}
+namespace
+{
+ unsigned make_non_void(const tr1::function<void () throw ()> & f)
+ {
+ f();
+ return 0;
+ }
+}
+
+namespace paludis
+{
+ template <>
+ template <>
+ struct Implementation<Future<void> >
+ {
+ const tr1::function<void () throw ()> f;
+ const tr1::function<unsigned () throw ()> adapted_f;
+ mutable tr1::shared_ptr<tr1::shared_ptr<unsigned > > result;
+ mutable tr1::shared_ptr<Mutex> mutex;
+ mutable tr1::shared_ptr<ConditionVariable> condition;
+
+ Implementation(const tr1::function<void () throw ()> & fn) :
+ f(fn),
+ adapted_f(tr1::bind(&make_non_void, fn)),
+ result(new tr1::shared_ptr<unsigned >),
+ mutex(new Mutex),
+ condition(new ConditionVariable)
+ {
+ FutureActionQueue::get_instance()->enqueue(
+ tr1::bind(&adapt_for_future<unsigned>, adapted_f, result, mutex, condition));
+ }
+ };
+}
+
+Future<void>::Future(const tr1::function<void () throw ()> & f) :
+ PrivateImplementationPattern<Future<void> >(new Implementation<Future<void> >(f))
+{
+}
+
+Future<void>::~Future()
+{
+ Lock l(*_imp->mutex);
+ if (! *_imp->result)
+ {
+ _imp->f();
+ _imp->result->reset(new unsigned(0));
+ _imp->condition->broadcast();
+ }
+}
+
+void
+Future<void>::operator() () const
+{
+ Lock l(*_imp->mutex);
+ if (! *_imp->result)
+ {
+ _imp->f();
+ _imp->result->reset(new unsigned(0));
+ _imp->condition->broadcast();
+ }
+}
+
diff --git a/paludis/util/future.hh b/paludis/util/future.hh
index 64734be..d6887f9 100644
--- a/paludis/util/future.hh
+++ b/paludis/util/future.hh
@@ -52,6 +52,20 @@ namespace paludis
T_ operator() () const PALUDIS_ATTRIBUTE((warn_unused_result));
};
+
+ template <>
+ class PALUDIS_VISIBLE Future<void> :
+ private PrivateImplementationPattern<Future<void> >
+ {
+ private:
+ using PrivateImplementationPattern<Future<void> >::_imp;
+
+ public:
+ Future(const tr1::function<void () throw ()> &);
+ ~Future();
+
+ void operator() () const;
+ };
}
#endif
diff --git a/paludis/util/future_TEST.cc b/paludis/util/future_TEST.cc
index 6353b02..4a157ea 100644
--- a/paludis/util/future_TEST.cc
+++ b/paludis/util/future_TEST.cc
@@ -36,6 +36,11 @@ namespace
Future<int> r1(&f), r2(&f), r3(&f), r4(&f);
return r1() + r2() + r3() - r4();
}
+
+ void h(int & i)
+ {
+ i = 42;
+ }
}
namespace test_cases
@@ -63,6 +68,22 @@ namespace test_cases
TEST_CHECK_EQUAL(f2(), 84);
}
} test_future_future;
+
+ struct VoidFutureTest : TestCase
+ {
+ VoidFutureTest() : TestCase("void future") { }
+
+ void run()
+ {
+ int x(17), y(23);
+ {
+ Future<void> f1(tr1::bind(&h, tr1::ref(x))), f2(tr1::bind(&h, tr1::ref(y)));
+ f1();
+ TEST_CHECK_EQUAL(x, 42);
+ }
+ TEST_CHECK_EQUAL(y, 42);
+ }
+ } test_void_future;
}
diff --git a/paludis/util/parallel_for_each.cc b/paludis/util/parallel_for_each.cc
new file mode 100644
index 0000000..71e3998
--- /dev/null
+++ b/paludis/util/parallel_for_each.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/parallel_for_each.hh>
+#include <paludis/util/sequence-impl.hh>
+#include <paludis/util/future-impl.hh>
+
+using namespace paludis;
+
+template class Sequence<tr1::shared_ptr<Future<void> > >;
+template class Future<void>;
+
diff --git a/paludis/util/parallel_for_each.hh b/paludis/util/parallel_for_each.hh
new file mode 100644
index 0000000..4bc5416
--- /dev/null
+++ b/paludis/util/parallel_for_each.hh
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_PARALLEL_FOR_EACH_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_PARALLEL_FOR_EACH_HH 1
+
+#include <paludis/util/future.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/tr1_memory.hh>
+
+namespace paludis
+{
+ template <typename I_, typename P_>
+ void parallel_for_each(I_ cur, const I_ & end, const P_ & op)
+ {
+ Sequence<tr1::shared_ptr<Future<void> > > futures;
+ for ( ; cur != end ; ++cur)
+ futures.push_back(make_shared_ptr(new Future<void>(tr1::bind(op, tr1::ref(*cur)))));
+ }
+}
+
+#endif
diff --git a/paludis/util/parallel_for_each_TEST.cc b/paludis/util/parallel_for_each_TEST.cc
new file mode 100644
index 0000000..3278d38
--- /dev/null
+++ b/paludis/util/parallel_for_each_TEST.cc
@@ -0,0 +1,64 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/join.hh>
+#include <paludis/util/parallel_for_each.hh>
+#include <test/test_runner.hh>
+#include <test/test_framework.hh>
+#include <vector>
+
+using namespace paludis;
+using namespace test;
+
+namespace
+{
+ int factorial(const int i)
+ {
+ if (i < 2)
+ return 1;
+ else
+ return i * factorial(i - 1);
+ }
+
+ void factorialify(int & i)
+ {
+ i = factorial(i);
+ }
+}
+
+namespace test_cases
+{
+ struct ParallelForEachTest : TestCase
+ {
+ ParallelForEachTest() : TestCase("parallel_for_each") { }
+
+ void run()
+ {
+ std::vector<int> v;
+ v.push_back(2);
+ v.push_back(4);
+ v.push_back(6);
+
+ parallel_for_each(v.begin(), v.end(), &factorialify);
+
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), " "), "2 24 720");
+ }
+ } test_parallel_for_each;
+}
+