aboutsummaryrefslogtreecommitdiff
path: root/libbuild2
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2')
-rw-r--r--libbuild2/scheduler.cxx34
-rw-r--r--libbuild2/scheduler.hxx71
2 files changed, 102 insertions, 3 deletions
diff --git a/libbuild2/scheduler.cxx b/libbuild2/scheduler.cxx
index c660bba..03842ec 100644
--- a/libbuild2/scheduler.cxx
+++ b/libbuild2/scheduler.cxx
@@ -144,8 +144,8 @@ namespace build2
if (collision)
stat_wait_collisions_++;
- // If we have spare active threads, then become active. Otherwise it
- // enters the ready queue.
+ // If we have spare active threads, then become active. Otherwise we enter
+ // the ready queue.
//
if (external)
external_--;
@@ -186,6 +186,36 @@ namespace build2
}
size_t scheduler::
+ allocate (size_t n)
+ {
+ if (max_active_ == 1) // Serial execution.
+ return 0;
+
+ lock l (mutex_);
+
+ if (active_ < max_active_)
+ {
+ size_t d (max_active_ - active_);
+ if (n == 0 || d < n)
+ n = d;
+ active_ -= n;
+ return n;
+ }
+ else
+ return 0;
+ }
+
+ void scheduler::
+ deallocate (size_t n)
+ {
+ if (max_active_ == 1) // Serial execution.
+ return;
+
+ lock l (mutex_);
+ active_ += n;
+ }
+
+ size_t scheduler::
suspend (size_t start_count, const atomic_count& task_count)
{
wait_slot& s (
diff --git a/libbuild2/scheduler.hxx b/libbuild2/scheduler.hxx
index b7bc3c5..7e052cd 100644
--- a/libbuild2/scheduler.hxx
+++ b/libbuild2/scheduler.hxx
@@ -159,6 +159,72 @@ namespace build2
static void
active_sleep (const duration&);
+ // Allocate additional active thread count to the current active thread,
+ // for example, to be "passed" to an external program:
+ //
+ // scheduler::alloc_guard ag (ctx.sched, ctx.sched.max_active () / 2);
+ // args.push_back ("-flto=" + to_string (1 + ag.n));
+ // run (args);
+ // ag.deallocate ();
+ //
+ // The allocate() function reserves up to the specified number of
+ // additional threads returning the number actually allocated (which can
+ // be less than requested, including 0). If 0 is specified, then it
+ // allocates all the currently available threads.
+ //
+ // The deallocate() function returns the specified number of previously
+ // allocated threads back to the active thread pool.
+ //
+ // Note that when the thread is deactivated (directly or indirectly via
+ // wait, phase switching, etc), the additionally allocated threads are
+ // considered to be still active (this semantics could be changed if we
+ // have a plausible scenario for where waiting, etc., with allocated
+ // threads is useful).
+ //
+ size_t
+ allocate (size_t);
+
+ void
+ deallocate (size_t);
+
+ struct alloc_guard
+ {
+ size_t n;
+
+ alloc_guard (): n (0), s_ (nullptr) {}
+ alloc_guard (scheduler& s, size_t m): n (s.allocate (m)), s_ (&s) {}
+ alloc_guard (alloc_guard&& x): n (x.n), s_ (x.s_) {x.s_ = nullptr;}
+ alloc_guard& operator= (alloc_guard&& x)
+ {
+ if (&x != this)
+ {
+ n = x.n;
+ s_ = x.s_;
+ x.s_ = nullptr;
+ }
+ return *this;
+ }
+
+ ~alloc_guard ()
+ {
+ if (s_ != nullptr && n != 0)
+ s_->deallocate (n);
+ }
+
+ void
+ deallocate ()
+ {
+ if (n != 0)
+ {
+ s_->deallocate (n);
+ n = 0;
+ }
+ }
+
+ private:
+ scheduler* s_;
+ };
+
// Startup and shutdown.
//
public:
@@ -248,13 +314,16 @@ namespace build2
size_t o_;
};
- // Return true if the scheduler is configured to run tasks serially.
+ // Return scheduler configuration.
//
// Note: can only be called from threads that have observed startup.
//
bool
serial () const {return max_active_ == 1;}
+ size_t
+ max_active () const {return max_active_;}
+
// Wait for all the helper threads to terminate. Throw system_error on
// failure. Note that the initially active threads are not waited for.
// Return scheduling statistics.