aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/b-options.cxx20
-rw-r--r--build2/b-options.hxx8
-rw-r--r--build2/b-options.ixx12
-rw-r--r--build2/b.cli15
-rw-r--r--build2/b.cxx8
-rw-r--r--build2/scheduler.cxx42
-rw-r--r--build2/scheduler.hxx10
7 files changed, 102 insertions, 13 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
index f3a15c3..9b4823f 100644
--- a/build2/b-options.cxx
+++ b/build2/b-options.cxx
@@ -582,6 +582,8 @@ namespace build2
max_jobs_specified_ (false),
queue_depth_ (4),
queue_depth_specified_ (false),
+ max_stack_ (),
+ max_stack_specified_ (false),
serial_stop_ (),
structured_result_ (),
match_only_ (),
@@ -727,6 +729,21 @@ namespace build2
<< " the build system scheduler implementation for details." << ::std::endl;
os << std::endl
+ << "\033[1m--max-stack\033[0m \033[4mnum\033[0m The maximum stack size in KBytes to allow for newly" << ::std::endl
+ << " created threads. For \033[4mpthreads\033[0m-based systems the driver" << ::std::endl
+ << " queries the stack size of the main thread and uses the" << ::std::endl
+ << " same size for creating additional threads. This allows" << ::std::endl
+ << " adjusting the stack size using familiar mechanisms, such" << ::std::endl
+ << " as \033[1mulimit\033[0m. Sometimes, however, the stack size of the main" << ::std::endl
+ << " thread is excessively large. As a result, the driver" << ::std::endl
+ << " checks if it is greater than a predefined limit (64MB on" << ::std::endl
+ << " 64-bit systems and 32MB on 32-bit ones) and caps it to a" << ::std::endl
+ << " more sensible value (8MB) if that's the case. This option" << ::std::endl
+ << " allows you to override this check with the special zero" << ::std::endl
+ << " value indicating that the main thread stack size should be" << ::std::endl
+ << " used as is." << ::std::endl;
+
+ os << std::endl
<< "\033[1m--serial-stop\033[0m|\033[1m-s\033[0m Run serially and stop at the first error. This mode is" << ::std::endl
<< " useful to investigate build failures that are caused by" << ::std::endl
<< " build system errors rather than compilation errors. Note" << ::std::endl
@@ -858,6 +875,9 @@ namespace build2
_cli_options_map_["-Q"] =
&::build2::cl::thunk< options, size_t, &options::queue_depth_,
&options::queue_depth_specified_ >;
+ _cli_options_map_["--max-stack"] =
+ &::build2::cl::thunk< options, size_t, &options::max_stack_,
+ &options::max_stack_specified_ >;
_cli_options_map_["--serial-stop"] =
&::build2::cl::thunk< options, bool, &options::serial_stop_ >;
_cli_options_map_["-s"] =
diff --git a/build2/b-options.hxx b/build2/b-options.hxx
index b6edae8..12a029c 100644
--- a/build2/b-options.hxx
+++ b/build2/b-options.hxx
@@ -434,6 +434,12 @@ namespace build2
bool
queue_depth_specified () const;
+ const size_t&
+ max_stack () const;
+
+ bool
+ max_stack_specified () const;
+
const bool&
serial_stop () const;
@@ -517,6 +523,8 @@ namespace build2
bool max_jobs_specified_;
size_t queue_depth_;
bool queue_depth_specified_;
+ size_t max_stack_;
+ bool max_stack_specified_;
bool serial_stop_;
bool structured_result_;
bool match_only_;
diff --git a/build2/b-options.ixx b/build2/b-options.ixx
index ef304d3..7a6f33e 100644
--- a/build2/b-options.ixx
+++ b/build2/b-options.ixx
@@ -294,6 +294,18 @@ namespace build2
return this->queue_depth_specified_;
}
+ inline const size_t& options::
+ max_stack () const
+ {
+ return this->max_stack_;
+ }
+
+ inline bool options::
+ max_stack_specified () const
+ {
+ return this->max_stack_specified_;
+ }
+
inline const bool& options::
serial_stop () const
{
diff --git a/build2/b.cli b/build2/b.cli
index e7f06cb..6114763 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -435,6 +435,21 @@ namespace build2
details."
}
+ size_t --max-stack
+ {
+ "<num>",
+ "The maximum stack size in KBytes to allow for newly created threads.
+ For \i{pthreads}-based systems the driver queries the stack size of
+ the main thread and uses the same size for creating additional threads.
+ This allows adjusting the stack size using familiar mechanisms, such
+ as \cb{ulimit}. Sometimes, however, the stack size of the main thread
+ is excessively large. As a result, the driver checks if it is greater
+ than a predefined limit (64MB on 64-bit systems and 32MB on 32-bit
+ ones) and caps it to a more sensible value (8MB) if that's the case.
+ This option allows you to override this check with the special zero
+ value indicating that the main thread stack size should be used as is."
+ }
+
bool --serial-stop|-s
{
"Run serially and stop at the first error. This mode is useful to
diff --git a/build2/b.cxx b/build2/b.cxx
index b0a9abf..945d375 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -451,7 +451,13 @@ main (int argc, char* argv[])
fail << "invalid --max-jobs|-J value";
}
- sched.startup (jobs, 1, max_jobs, jobs * ops.queue_depth ());
+ sched.startup (jobs,
+ 1,
+ max_jobs,
+ jobs * ops.queue_depth (),
+ (ops.max_stack_specified ()
+ ? optional<size_t> (ops.max_stack () * 1024)
+ : nullopt));
variable_cache_mutex_shard_size = sched.shard_size ();
variable_cache_mutex_shard.reset (
diff --git a/build2/scheduler.cxx b/build2/scheduler.cxx
index e6a0bc6..79951b6 100644
--- a/build2/scheduler.cxx
+++ b/build2/scheduler.cxx
@@ -13,6 +13,8 @@
#include <cerrno>
+#include <iostream>
+
using namespace std;
namespace build2
@@ -257,13 +259,16 @@ namespace build2
startup (size_t max_active,
size_t init_active,
size_t max_threads,
- size_t queue_depth)
+ size_t queue_depth,
+ optional<size_t> max_stack)
{
// Lock the mutex to make sure our changes are visible in (other) active
// threads.
//
lock l (mutex_);
+ max_stack_ = max_stack;
+
// Use 8x max_active on 32-bit and 32x max_active on 64-bit. Unless we
// were asked to run serially.
//
@@ -475,11 +480,16 @@ namespace build2
// MinGW : 2048 / 2048
// VC : 1024 / 1024
//
- // We will make sure that the new thread stack size is the same as for the
- // main thread. For FreeBSD we will also cap it at 8MB.
+ // Provided the main thread size is less-equal than BUILD2_SANE_STACK_SIZE
+ // (default: sizeof(void*) * BUILD2_DEFAULT_STACK_SIZE), we make sure that
+ // the new thread stack is the same as for the main thread. Otherwise, we
+ // cap it at BUILD2_DEFAULT_STACK_SIZE (default: 8MB). This can also be
+ // overridden at runtime with the --max-stack option (remember to update
+ // its documentation of changing anything here).
//
// On Windows the stack size is the same for all threads and is customized
- // at the linking stage (see build2/buildfile).
+ // at the linking stage (see build2/buildfile). Thus neither *_STACK_SIZE
+ // nor --max-stack have any effect here.
//
// On Linux, FreeBSD and MacOS there is no way to change it once and for
// all newly created threads. Thus we will use pthreads, creating threads
@@ -488,6 +498,15 @@ namespace build2
// created by the main thread).
//
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+
+#ifndef BUILD2_DEFAULT_STACK_SIZE
+# define BUILD2_DEFAULT_STACK_SIZE 8388608 // 8MB
+#endif
+
+#ifndef BUILD2_SANE_STACK_SIZE
+# define BUILD2_SANE_STACK_SIZE (sizeof(void*) * BUILD2_DEFAULT_STACK_SIZE)
+#endif
+
// Auto-deleter.
//
struct attr_deleter
@@ -543,16 +562,21 @@ namespace build2
if (r != 0)
throw_system_error (r);
- // Cap at 8MB.
- //
- if (stack_size > 8388608)
- stack_size = 8388608;
-
#else // defined(__APPLE__)
stack_size = pthread_get_stacksize_np (pthread_self ());
#endif
}
+ // Cap the size if necessary.
+ //
+ if (max_stack_)
+ {
+ if (*max_stack_ != 0 && stack_size > *max_stack_)
+ stack_size = *max_stack_;
+ }
+ else if (stack_size > BUILD2_SANE_STACK_SIZE)
+ stack_size = BUILD2_DEFAULT_STACK_SIZE;
+
pthread_attr_t attr;
int r (pthread_attr_init (&attr));
diff --git a/build2/scheduler.hxx b/build2/scheduler.hxx
index 4880392..d90a26f 100644
--- a/build2/scheduler.hxx
+++ b/build2/scheduler.hxx
@@ -164,9 +164,10 @@ namespace build2
scheduler (size_t max_active,
size_t init_active = 1,
size_t max_threads = 0,
- size_t queue_depth = 0)
+ size_t queue_depth = 0,
+ optional<size_t> max_stack = nullopt)
{
- startup (max_active, init_active, max_threads, queue_depth);
+ startup (max_active, init_active, max_threads, queue_depth, max_stack);
}
// Start the scheduler.
@@ -175,7 +176,8 @@ namespace build2
startup (size_t max_active,
size_t init_active = 1,
size_t max_threads = 0,
- size_t queue_depth = 0);
+ size_t queue_depth = 0,
+ optional<size_t> max_stack = nullopt);
// Return true if the scheduler was started up.
//
@@ -386,6 +388,8 @@ namespace build2
std::mutex mutex_;
bool shutdown_ = true; // Shutdown flag.
+ optional<size_t> max_stack_;
+
// The constraints that we must maintain:
//
// active <= max_active