aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-12 23:06:15 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-07-12 23:06:15 +0000
commit66fb6a95c73837a7b5b7981bee9a9fd7a252d311 (patch)
tree8af368f593860eaab9839aa3d0d41448da913098
parent2a9bebd4946971c24e2cd18ab6bcc9901e8897d4 (diff)
downloadpaludis-66fb6a95c73837a7b5b7981bee9a9fd7a252d311.tar.gz
paludis-66fb6a95c73837a7b5b7981bee9a9fd7a252d311.tar.xz
Better idle actions
-rw-r--r--paludis/repositories/e/e_key.cc21
-rw-r--r--paludis/repositories/e/e_key.hh9
-rw-r--r--paludis/repositories/e/ebuild_id.cc19
-rw-r--r--paludis/repositories/e/ebuild_id.hh3
-rw-r--r--paludis/util/action_queue.cc22
-rw-r--r--paludis/util/action_queue.hh3
-rw-r--r--paludis/util/files.m42
-rw-r--r--paludis/util/idle_action_pool-fwd.hh34
-rw-r--r--paludis/util/idle_action_pool.cc87
-rw-r--r--paludis/util/idle_action_pool.hh8
-rw-r--r--paludis/util/idle_action_pool.se20
-rw-r--r--paludis/util/idle_action_pool_TEST.cc3
-rw-r--r--paludis/util/thread.cc27
-rw-r--r--paludis/util/thread.hh2
14 files changed, 228 insertions, 32 deletions
diff --git a/paludis/repositories/e/e_key.cc b/paludis/repositories/e/e_key.cc
index 9a6edcf..923c55a 100644
--- a/paludis/repositories/e/e_key.cc
+++ b/paludis/repositories/e/e_key.cc
@@ -102,7 +102,7 @@ EDependenciesKey::value() const
return _imp->value;
}
-void
+IdleActionResult
EDependenciesKey::idle_load() const
{
TryLock l(_imp->value_mutex);
@@ -110,7 +110,10 @@ EDependenciesKey::idle_load() const
{
Context context("When parsing metadata key '" + raw_name() + "' from '" + stringify(*_imp->id) + "' as idle action:");
_imp->value = PortageDepParser::parse_depend(_imp->string_value, *_imp->id->eapi());
+ return iar_success;
}
+
+ return iar_already_completed;
}
namespace paludis
@@ -155,7 +158,7 @@ ELicenseKey::value() const
return _imp->value;
}
-void
+IdleActionResult
ELicenseKey::idle_load() const
{
TryLock l(_imp->value_mutex);
@@ -163,7 +166,10 @@ ELicenseKey::idle_load() const
{
Context context("When parsing metadata key '" + raw_name() + "' from '" + stringify(*_imp->id) + "' as idle action:");
_imp->value = PortageDepParser::parse_license(_imp->string_value, *_imp->id->eapi());
+ return iar_success;
}
+
+ return iar_already_completed;
}
namespace paludis
@@ -334,7 +340,7 @@ EIUseKey::value() const
return _imp->value;
}
-void
+IdleActionResult
EIUseKey::idle_load() const
{
TryLock l(_imp->value_mutex);
@@ -347,7 +353,11 @@ EIUseKey::idle_load() const
for (std::list<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()) ;
t != t_end ; ++t)
_imp->value->insert(IUseFlag(*t, _imp->id->eapi()->supported->iuse_flag_parse_mode));
+
+ return iar_success;
}
+
+ return iar_already_completed;
}
namespace paludis
@@ -393,7 +403,7 @@ EKeywordsKey::value() const
return _imp->value;
}
-void
+IdleActionResult
EKeywordsKey::idle_load() const
{
TryLock l(_imp->value_mutex);
@@ -402,7 +412,10 @@ EKeywordsKey::idle_load() const
_imp->value.reset(new KeywordNameSet);
Context context("When parsing metadata key '" + raw_name() + "' from '" + stringify(*_imp->id) + "' as idle action:");
WhitespaceTokeniser::get_instance()->tokenise(_imp->string_value, create_inserter<KeywordName>(_imp->value->inserter()));
+ return iar_success;
}
+
+ return iar_already_completed;
}
namespace paludis
diff --git a/paludis/repositories/e/e_key.hh b/paludis/repositories/e/e_key.hh
index c3b9fa2..326fa6f 100644
--- a/paludis/repositories/e/e_key.hh
+++ b/paludis/repositories/e/e_key.hh
@@ -22,6 +22,7 @@
#include <paludis/metadata_key.hh>
#include <paludis/util/fs_entry-fwd.hh>
+#include <paludis/util/idle_action_pool-fwd.hh>
namespace paludis
{
@@ -59,7 +60,7 @@ namespace paludis
virtual const tr1::shared_ptr<const DependencySpecTree::ConstItem> value() const
PALUDIS_ATTRIBUTE((warn_unused_result));
- void idle_load() const;
+ IdleActionResult idle_load() const;
};
class EURIKey :
@@ -125,7 +126,7 @@ namespace paludis
virtual const tr1::shared_ptr<const LicenseSpecTree::ConstItem> value() const
PALUDIS_ATTRIBUTE((warn_unused_result));
- void idle_load() const;
+ IdleActionResult idle_load() const;
};
class EIUseKey :
@@ -143,7 +144,7 @@ namespace paludis
const tr1::shared_ptr<const IUseFlagSet> value() const
PALUDIS_ATTRIBUTE((warn_unused_result));
- void idle_load() const;
+ IdleActionResult idle_load() const;
};
class EKeywordsKey :
@@ -161,7 +162,7 @@ namespace paludis
const tr1::shared_ptr<const KeywordNameSet> value() const
PALUDIS_ATTRIBUTE((warn_unused_result));
- void idle_load() const;
+ IdleActionResult idle_load() const;
};
class EUseKey :
diff --git a/paludis/repositories/e/ebuild_id.cc b/paludis/repositories/e/ebuild_id.cc
index fd1c05c..cef5c79 100644
--- a/paludis/repositories/e/ebuild_id.cc
+++ b/paludis/repositories/e/ebuild_id.cc
@@ -562,28 +562,33 @@ EbuildID::load_inherited(const std::string & r, const std::string & h, const std
add_metadata_key(_imp->inherited);
}
-void
+IdleActionResult
EbuildID::_idle_load() const throw ()
{
+ IdleActionResult result(iar_success);
+
try
{
if (_imp->build_dependencies)
- _imp->build_dependencies->idle_load();
+ result = std::max(result, _imp->build_dependencies->idle_load());
if (_imp->run_dependencies)
- _imp->run_dependencies->idle_load();
+ result = std::max(result, _imp->run_dependencies->idle_load());
if (_imp->post_dependencies)
- _imp->post_dependencies->idle_load();
+ result = std::max(result, _imp->post_dependencies->idle_load());
if (_imp->license)
- _imp->license->idle_load();
+ result = std::max(result, _imp->license->idle_load());
if (_imp->keywords)
- _imp->keywords->idle_load();
+ result = std::max(result, _imp->keywords->idle_load());
if (_imp->iuse)
- _imp->iuse->idle_load();
+ result = std::max(result, _imp->iuse->idle_load());
}
catch (...)
{
// exception will be regenerated outside of the idle task.
+ result = iar_failure;
}
+
+ return result;
}
namespace
diff --git a/paludis/repositories/e/ebuild_id.hh b/paludis/repositories/e/ebuild_id.hh
index 990054e..3406286 100644
--- a/paludis/repositories/e/ebuild_id.hh
+++ b/paludis/repositories/e/ebuild_id.hh
@@ -23,6 +23,7 @@
#include <paludis/package_id.hh>
#include <paludis/metadata_key.hh>
#include <paludis/util/fs_entry-fwd.hh>
+#include <paludis/util/idle_action_pool-fwd.hh>
namespace paludis
{
@@ -39,7 +40,7 @@ namespace paludis
private:
Implementation<EbuildID> * const _imp;
- void _idle_load() const throw ();
+ IdleActionResult _idle_load() const throw ();
protected:
virtual void need_keys_added() const;
diff --git a/paludis/util/action_queue.cc b/paludis/util/action_queue.cc
index fe85a70..d455acc 100644
--- a/paludis/util/action_queue.cc
+++ b/paludis/util/action_queue.cc
@@ -24,6 +24,7 @@
# include <paludis/util/mutex.hh>
# include <paludis/util/condition_variable.hh>
# include <paludis/util/thread_pool.hh>
+# include <paludis/util/thread.hh>
# include <list>
#endif
@@ -74,19 +75,23 @@ namespace paludis
}
}
- Implementation(const unsigned n_threads) :
+ Implementation(const unsigned n_threads, const bool nice) :
should_finish(false)
{
for (unsigned x(0) ; x < n_threads ; ++x)
- threads.create_thread(tr1::bind(tr1::mem_fn(&Implementation::thread_func), this));
+ if (nice)
+ threads.create_thread(tr1::bind(&Thread::idle_adapter,
+ tr1::function<void () throw ()>(tr1::bind(tr1::mem_fn(&Implementation::thread_func), this))));
+ else
+ threads.create_thread(tr1::bind(tr1::mem_fn(&Implementation::thread_func), this));
}
#endif
};
}
-ActionQueue::ActionQueue(const unsigned n_threads) :
+ActionQueue::ActionQueue(const unsigned n_threads, const bool nice) :
#ifdef PALUDIS_ENABLE_THREADS
- PrivateImplementationPattern<ActionQueue>(new Implementation<ActionQueue>(n_threads))
+ PrivateImplementationPattern<ActionQueue>(new Implementation<ActionQueue>(n_threads, nice))
#else
PrivateImplementationPattern<ActionQueue>(new Implementation<ActionQueue>())
#endif
@@ -125,3 +130,12 @@ ActionQueue::complete_pending()
#endif
}
+void
+ActionQueue::forget_pending()
+{
+#ifdef PALUDIS_ENABLE_THREADS
+ Lock l(_imp->mutex);
+ _imp->queue.clear();
+#endif
+}
+
diff --git a/paludis/util/action_queue.hh b/paludis/util/action_queue.hh
index 5cdceb2..7b7684b 100644
--- a/paludis/util/action_queue.hh
+++ b/paludis/util/action_queue.hh
@@ -29,11 +29,12 @@ namespace paludis
private PrivateImplementationPattern<ActionQueue>
{
public:
- ActionQueue(const unsigned n_threads = 1);
+ ActionQueue(const unsigned n_threads = 1, const bool nice = false);
~ActionQueue();
void enqueue(const tr1::function<void () throw ()> &);
void complete_pending();
+ void forget_pending();
};
}
diff --git a/paludis/util/files.m4 b/paludis/util/files.m4
index 7aebcd9..6e3562a 100644
--- a/paludis/util/files.m4
+++ b/paludis/util/files.m4
@@ -20,7 +20,7 @@ add(`fd_output_stream', `hh')
add(`fs_entry', `hh', `cc', `fwd', `test', `testscript')
add(`fd_holder', `hh')
add(`graph', `hh', `cc', `impl', `test')
-add(`idle_action_pool', `hh', `cc', `test')
+add(`idle_action_pool', `hh', `cc', `se', `test')
add(`iterator', `hh', `test')
add(`instantiation_policy', `hh', `impl', `test')
add(`is_file_with_extension', `hh', `cc', `se', `test', `testscript')
diff --git a/paludis/util/idle_action_pool-fwd.hh b/paludis/util/idle_action_pool-fwd.hh
new file mode 100644
index 0000000..697bd70
--- /dev/null
+++ b/paludis/util/idle_action_pool-fwd.hh
@@ -0,0 +1,34 @@
+/* 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_IDLE_ACTION_POOL_FWD_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_IDLE_ACTION_POOL_FWD_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <iosfwd>
+
+namespace paludis
+{
+
+#include <paludis/util/idle_action_pool-se.hh>
+
+ class IdleActionPool;
+}
+
+#endif
diff --git a/paludis/util/idle_action_pool.cc b/paludis/util/idle_action_pool.cc
index d745964..b1e70ce 100644
--- a/paludis/util/idle_action_pool.cc
+++ b/paludis/util/idle_action_pool.cc
@@ -21,22 +21,63 @@
#include <paludis/util/private_implementation_pattern-impl.hh>
#include <paludis/util/instantiation_policy-impl.hh>
#include <paludis/util/action_queue.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/mutex.hh>
+#include <paludis/util/destringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/exception.hh>
+#include <ostream>
using namespace paludis;
+#include <paludis/util/idle_action_pool-se.cc>
+
template class InstantiationPolicy<IdleActionPool, instantiation_method::SingletonTag>;
+namespace
+{
+#ifdef PALUDIS_ENABLE_THREADS
+ struct Stats
+ {
+ Mutex mutex;
+ unsigned success, failure, already_completed, enqueued;
+
+ Stats() :
+ success(0),
+ failure(0),
+ already_completed(0),
+ enqueued(0)
+ {
+ }
+
+ ~Stats()
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context) << "Idle action pool stats: success "
+ << success << " failure " << failure << " already completed " << already_completed
+ << " forgotten " << (enqueued - success - failure - already_completed);
+ }
+ };
+#endif
+}
+
namespace paludis
{
template <>
struct Implementation<IdleActionPool>
{
#ifdef PALUDIS_ENABLE_THREADS
+ Stats stats;
ActionQueue pool;
Implementation() :
- pool(5)
+ pool(destringify<int>(getenv_with_default("PALUDIS_IDLE_THREAD_COUNT", "5")), true)
+ {
+ }
+
+ ~Implementation()
{
+ pool.forget_pending();
}
#endif
};
@@ -53,10 +94,10 @@ IdleActionPool::~IdleActionPool()
}
void
-IdleActionPool::required_idle_action(const tr1::function<void () throw ()> & f)
+IdleActionPool::required_idle_action(const tr1::function<IdleActionResult () throw ()> & f)
{
#ifdef PALUDIS_ENABLE_THREADS
- _imp->pool.enqueue(f);
+ _imp->pool.enqueue(tr1::bind(tr1::mem_fn(&IdleActionPool::_count_result), this, f));
#else
f();
#endif
@@ -65,14 +106,48 @@ IdleActionPool::required_idle_action(const tr1::function<void () throw ()> & f)
void
IdleActionPool::optional_idle_action(
#ifdef PALUDIS_ENABLE_THREADS
- const tr1::function<void () throw ()> & f
+ const tr1::function<IdleActionResult () throw ()> & f
#else
- const tr1::function<void () throw ()> &
+ const tr1::function<IdleActionResult () throw ()> &
#endif
)
{
#ifdef PALUDIS_ENABLE_THREADS
- _imp->pool.enqueue(f);
+ _imp->pool.enqueue(tr1::bind(tr1::mem_fn(&IdleActionPool::_count_result), this, f));
+#endif
+}
+
+void
+IdleActionPool::_count_result(const tr1::function<IdleActionResult () throw ()> & f)
+{
+#ifdef PALUDIS_ENABLE_THREADS
+ {
+ Lock l(_imp->stats.mutex);
+ ++_imp->stats.enqueued;
+ }
+
+ IdleActionResult r(f());
+
+ {
+ Lock l(_imp->stats.mutex);
+ switch (r)
+ {
+ case iar_success:
+ ++_imp->stats.success;
+ break;
+
+ case iar_failure:
+ ++_imp->stats.failure;
+ break;
+
+ case iar_already_completed:
+ ++_imp->stats.already_completed;
+ break;
+
+ case last_iar:
+ break;
+ }
+ }
#endif
}
diff --git a/paludis/util/idle_action_pool.hh b/paludis/util/idle_action_pool.hh
index c94d92d..0a37717 100644
--- a/paludis/util/idle_action_pool.hh
+++ b/paludis/util/idle_action_pool.hh
@@ -20,7 +20,7 @@
#ifndef PALUDIS_GUARD_PALUDIS_UTIL_IDLE_ACTION_POOL_HH
#define PALUDIS_GUARD_PALUDIS_UTIL_IDLE_ACTION_POOL_HH 1
-#include <paludis/util/attributes.hh>
+#include <paludis/util/idle_action_pool-fwd.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/instantiation_policy.hh>
#include <paludis/util/tr1_functional.hh>
@@ -37,9 +37,11 @@ namespace paludis
IdleActionPool();
~IdleActionPool();
+ void _count_result(const tr1::function<IdleActionResult () throw ()> &);
+
public:
- void required_idle_action(const tr1::function<void () throw ()> &);
- void optional_idle_action(const tr1::function<void () throw ()> &);
+ void required_idle_action(const tr1::function<IdleActionResult () throw ()> &);
+ void optional_idle_action(const tr1::function<IdleActionResult () throw ()> &);
};
}
diff --git a/paludis/util/idle_action_pool.se b/paludis/util/idle_action_pool.se
new file mode 100644
index 0000000..2a4490f
--- /dev/null
+++ b/paludis/util/idle_action_pool.se
@@ -0,0 +1,20 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et ft=sh :
+
+make_enum_IdleActionResult()
+{
+ prefix iar
+
+ key iar_success "Success"
+ key iar_already_completed "Already completed"
+ key iar_failure "Failure"
+
+ doxygen_comment << "END"
+ /**
+ * The result of an idle action.
+ *
+ * \see IdleActionPool
+ */
+END
+}
+
diff --git a/paludis/util/idle_action_pool_TEST.cc b/paludis/util/idle_action_pool_TEST.cc
index eefdf13..e480778 100644
--- a/paludis/util/idle_action_pool_TEST.cc
+++ b/paludis/util/idle_action_pool_TEST.cc
@@ -27,9 +27,10 @@ using namespace paludis;
namespace
{
- void make_true(bool & b) throw ()
+ IdleActionResult make_true(bool & b) throw ()
{
b = true;
+ return iar_success;
}
}
diff --git a/paludis/util/thread.cc b/paludis/util/thread.cc
index ecb430e..84937ce 100644
--- a/paludis/util/thread.cc
+++ b/paludis/util/thread.cc
@@ -20,12 +20,22 @@
#include <paludis/util/thread.hh>
#include <paludis/util/exception.hh>
#include <paludis/util/stringify.hh>
+#include <paludis/util/log.hh>
#include <string.h>
+#include <errno.h>
+
+#ifdef __linux__
+# include <sys/time.h>
+# include <sys/resource.h>
+# include <unistd.h>
+# include <sys/syscall.h>
+#endif
using namespace paludis;
#ifdef PALUDIS_ENABLE_THREADS
+
Thread::Thread(const tr1::function<void () throw ()> & f) :
_thread(new pthread_t),
_func(f)
@@ -49,6 +59,17 @@ Thread::~Thread()
delete _thread;
}
+void
+Thread::idle_adapter(const tr1::function<void () throw ()> & f)
+{
+#ifdef __linux__
+ setpriority(PRIO_PROCESS, syscall(SYS_gettid), 10);
+#else
+# warning "Don't know how to set thread priorities on your platform"
+#endif
+ f();
+}
+
#else
Thread::Thread(const tr1::function<void () throw ()> & f)
@@ -60,5 +81,11 @@ Thread::~Thread()
{
}
+void
+Thread::idle_adapter(const tr1::function<void () throw ()> & f)
+{
+ f();
+}
+
#endif
diff --git a/paludis/util/thread.hh b/paludis/util/thread.hh
index 5729d88..efc9df4 100644
--- a/paludis/util/thread.hh
+++ b/paludis/util/thread.hh
@@ -42,6 +42,8 @@ namespace paludis
public:
Thread(const tr1::function<void () throw ()> &);
~Thread();
+
+ static void idle_adapter(const tr1::function<void () throw ()> &);
};
}