[Aptitude-svn-commit] r4072 - in branches/aptitude-0.3/aptitude: .
src/generic/problemresolver
Daniel Burrows
dburrows at costa.debian.org
Sat Sep 10 23:35:12 UTC 2005
Author: dburrows
Date: Sat Sep 10 23:35:09 2005
New Revision: 4072
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/generic/problemresolver/exceptions.h
branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
Log:
Add hooks to manage the resolver in the presence of threads.
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Sat Sep 10 23:35:09 2005
@@ -1,3 +1,13 @@
+2005-09-10 Daniel Burrows <dburrows at debian.org>
+
+ * src/generic/problemresolver/exceptions.h, src/generic/problemresolver/problemresolver.h:
+
+ Add code to manage the resolver in the presence of threads; it
+ ensures that at most one find_next_solution call is running at
+ once, and allows a find_next_solution call to be cleanly
+ cancelled (throwing a special exception); it's guaranteed that
+ you can start the resolver back up after cancelling it.
+
2005-09-10 Jean-Luc Coulon <jean-luc.coulon at wanadoo.fr>
* update French translation
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/exceptions.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/exceptions.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/exceptions.h Sat Sep 10 23:35:09 2005
@@ -44,4 +44,24 @@
}
};
+/** An exception indicating that the resolver was interrupted from
+ * another thread.
+ */
+class InterruptedException : public ProblemResolverError {
+ std::string errmsg() const
+ {
+ return "Dependency solution was interrupted.";
+ }
+};
+
+/** An exception indicating that two threads tried to run the resolver
+ * at once.
+ */
+class DoubleRunException : public ProblemResolverError {
+ std::string errmsg() const
+ {
+ return "Internal error: Multiple threads of execution tried to enter the resolver at once.";
+ }
+};
+
#endif // EXCEPTIONS_H
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h Sat Sep 10 23:35:09 2005
@@ -53,6 +53,7 @@
#include "solution.h"
#include "../dense_setset.h"
+#include "../threads.h"
/** A dummy iterator that's always an "end" iterator. */
template<class V>
@@ -187,64 +188,90 @@
}
};
- typedef ExtractPackageId PackageHash;
+ typedef ExtractPackageId PackageHash;
- /** Compares solutions according to their "goodness". */
- struct solution_goodness_compare
- {
- bool operator()(const solution &s1, const solution &s2) const
- {
- return s1.get_score() < s2.get_score();
- }
- };
+ /** Compares solutions according to their "goodness". */
+ struct solution_goodness_compare
+ {
+ bool operator()(const solution &s1, const solution &s2) const
+ {
+ return s1.get_score() < s2.get_score();
+ }
+ };
- /** Compares solutions according to their contents; used to
- * manage "closed".
- */
- struct solution_contents_compare
- {
- bool operator()(const solution &s1, const solution &s2) const
- {
- // Variation on lexicographical comparison.
- //
- // S1 < S2 if
- // - S1(p)=S2(p) for all p<p' and S1(p')<S2(p'), where
- // p,p' \in \dom(S1) \cup dom(S2)
+ /** Compares solutions according to their contents; used to
+ * manage "closed".
+ */
+ struct solution_contents_compare
+ {
+ bool operator()(const solution &s1, const solution &s2) const
+ {
+ // Variation on lexicographical comparison.
+ //
+ // S1 < S2 if
+ // - S1(p)=S2(p) for all p<p' and S1(p')<S2(p'), where
+ // p,p' \in \dom(S1) \cup dom(S2)
- // NB: the correctness of this code depends implicitly on the
- // invariant that the score is a function of the contents of the
- // solution. Essentially we're using the score as a sort of
- // hash value on solutions!
- if(s1.get_score() < s2.get_score())
- return true;
- else if(s2.get_score() < s1.get_score())
- return false;
- else if(s1.get_action_score() < s2.get_action_score())
- return true;
- else if(s2.get_action_score() < s1.get_action_score())
- return false;
+ // NB: the correctness of this code depends implicitly on the
+ // invariant that the score is a function of the contents of the
+ // solution. Essentially we're using the score as a sort of
+ // hash value on solutions!
+ if(s1.get_score() < s2.get_score())
+ return true;
+ else if(s2.get_score() < s1.get_score())
+ return false;
+ else if(s1.get_action_score() < s2.get_action_score())
+ return true;
+ else if(s2.get_action_score() < s1.get_action_score())
+ return false;
- const imm::map<package,action>
- &a1=s1.get_actions(), &a2=s2.get_actions();
- const imm::set<dep>
- &us1=s1.get_unresolved_soft_deps(), &us2=s2.get_unresolved_soft_deps();
+ const imm::map<package,action>
+ &a1=s1.get_actions(), &a2=s2.get_actions();
+ const imm::set<dep>
+ &us1=s1.get_unresolved_soft_deps(), &us2=s2.get_unresolved_soft_deps();
- // Speed hack: order by size first to avoid traversing the whole
- // tree.
- if(a1.size() < a2.size())
- return true;
- else if(a2.size() < a1.size())
- return false;
- else if(us1.size() < us2.size())
- return true;
- else if(us2.size() < us1.size())
- return false;
- else
- return a1 < a2 || (a2 == a1 && us1 < us2);
- }
- };
+ // Speed hack: order by size first to avoid traversing the whole
+ // tree.
+ if(a1.size() < a2.size())
+ return true;
+ else if(a2.size() < a1.size())
+ return false;
+ else if(us1.size() < us2.size())
+ return true;
+ else if(us2.size() < us1.size())
+ return false;
+ else
+ return a1 < a2 || (a2 == a1 && us1 < us2);
+ }
+ };
+
+ class instance_tracker;
+ friend class instance_tracker;
+ class instance_tracker
+ {
+ generic_problem_resolver &r;
+ public:
+ instance_tracker(generic_problem_resolver &_r)
+ :r(_r)
+ {
+ threads::mutex::lock l(r.execution_mutex);
+ if(r.solver_executing)
+ throw DoubleRunException();
+ else
+ r.solver_executing = true;
+ }
+
+ ~instance_tracker()
+ {
+ threads::mutex::lock l(r.execution_mutex);
+ assert(r.solver_executing);
+
+ r.solver_executing = false;
+ r.solver_cancelled = false;
+ }
+ };
// Information regarding the weight given to various parameters;
// packaged up in a struct so it can be easily used by the solution
@@ -304,6 +331,27 @@
*/
bool remove_stupid:1;
+
+ // Multithreading support variables.
+ //
+ // These variables ensure (as a sanity-check) that only one thread
+ // executes the solver function at once, and allow the executing
+ // instance to be cleanly terminated. They are managed by the
+ // instance_tracker class (see above).
+
+ /** If \b true, a thread is currently executing in the solver. */
+ bool solver_executing : 1;
+
+ /** If \b true, the currently executing thread should stop at the
+ * next opportunity.
+ */
+ bool solver_cancelled : 1;
+
+ /** Mutex guarding the solver_executing and stop_solver. */
+ threads::mutex execution_mutex;
+
+
+
/** The working queue: */
std::priority_queue<solution, std::vector<solution>, solution_goodness_compare> open;
@@ -346,6 +394,7 @@
/** Stores generated solutions: */
std::vector<solution> generated_solutions;
+
typedef std::set<std::pair<version, version> > stupid_table;
std::ostream &dump_conflict(std::ostream &out, const imm::map<package, action> &conflict) const;
@@ -2071,6 +2120,16 @@
unreject_version(*si);
}
+ /** Cancel any find_next_solution call that is executing in the
+ * background.
+ */
+ void cancel_solver()
+ {
+ threads::mutex::lock l(execution_mutex);
+ if(solver_executing)
+ solver_cancelled = true;
+ }
+
/** Try to find the "next" solution: remove partial solutions from
* the open queue and place them in the closed queue until one of
* the following occurs:
@@ -2096,6 +2155,13 @@
*/
solution find_next_solution(int max_steps)
{
+ // This object is responsible for managing the instance variables
+ // that control threaded operation: it sets solver_executing when
+ // it is created and clears both solver_executing and
+ // solver_cancelled when it is destroyed.
+ instance_tracker t(*this);
+
+
// Counter for debugging (see below)
int odometer = 0;
@@ -2118,6 +2184,14 @@
while(max_steps>0 && !open.empty())
{
+ // Threaded operation: check whether we have been cancelled.
+ {
+ threads::mutex::lock l(execution_mutex);
+ if(solver_cancelled)
+ throw InterruptedException();
+ }
+
+
solution s=open.top();
open.pop();
More information about the Aptitude-svn-commit
mailing list