mirror of
https://github.com/boostorg/build.git
synced 2026-02-17 13:42:14 +00:00
Merge branch 'develop' of https://github.com/boostorg/build into develop
This commit is contained in:
@@ -780,31 +780,161 @@ static void read_output()
|
||||
* cmdtab array, or -1.
|
||||
*/
|
||||
|
||||
typedef struct _twh_params
|
||||
{
|
||||
int * active_procs;
|
||||
HANDLE * active_handles;
|
||||
DWORD num_active;
|
||||
DWORD timeoutMillis;
|
||||
} twh_params;
|
||||
|
||||
static int try_wait_helper( twh_params * );
|
||||
|
||||
static int try_wait( int const timeoutMillis )
|
||||
{
|
||||
#define MAX_THREADS MAXJOBS/(MAXIMUM_WAIT_OBJECTS - 1) + 1
|
||||
int i;
|
||||
int num_active;
|
||||
int wait_api_result;
|
||||
HANDLE active_handles[ MAXJOBS ];
|
||||
int active_procs[ MAXJOBS ];
|
||||
HANDLE active_handles[ MAXJOBS + MAX_THREADS ];
|
||||
int active_procs[ MAXJOBS + MAX_THREADS ];
|
||||
unsigned int num_threads;
|
||||
unsigned int num_handles;
|
||||
unsigned int last_chunk_size;
|
||||
unsigned int last_chunk_offset;
|
||||
HANDLE completed_event = INVALID_HANDLE_VALUE;
|
||||
HANDLE thread_handles[MAXIMUM_WAIT_OBJECTS];
|
||||
twh_params thread_params[MAX_THREADS];
|
||||
int result = -1;
|
||||
BOOL success;
|
||||
|
||||
/* Prepare a list of all active processes to wait for. */
|
||||
for ( num_active = 0, i = 0; i < globs.jobs; ++i )
|
||||
if ( cmdtab[ i ].pi.hProcess )
|
||||
{
|
||||
if ( num_active == MAXIMUM_WAIT_OBJECTS )
|
||||
{
|
||||
/*
|
||||
* We surpassed MAXIMUM_WAIT_OBJECTS, so we need to use threads
|
||||
* to wait for this set. Create an event object which will
|
||||
* notify threads to stop waiting. Every handle set chunk should
|
||||
* have this event as its last element.
|
||||
*/
|
||||
assert( completed_event == INVALID_HANDLE_VALUE );
|
||||
completed_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
active_handles[ num_active ] = active_handles[ num_active - 1 ];
|
||||
active_procs[ num_active ] = active_procs[ num_active - 1 ];
|
||||
active_handles[ num_active - 1 ] = completed_event;
|
||||
active_procs[ num_active - 1 ] = -1;
|
||||
++num_active;
|
||||
}
|
||||
else if ( ( completed_event != INVALID_HANDLE_VALUE ) &&
|
||||
!((num_active + 1) % MAXIMUM_WAIT_OBJECTS) )
|
||||
{
|
||||
active_handles[ num_active ] = completed_event;
|
||||
active_procs[ num_active ] = -1;
|
||||
++num_active;
|
||||
}
|
||||
active_handles[ num_active ] = cmdtab[ i ].pi.hProcess;
|
||||
active_procs[ num_active ] = i;
|
||||
++num_active;
|
||||
}
|
||||
|
||||
/* Wait for a child to complete, or for our timeout window to expire. */
|
||||
wait_api_result = WaitForMultipleObjects( num_active, active_handles,
|
||||
FALSE, timeoutMillis );
|
||||
assert( (num_active <= MAXIMUM_WAIT_OBJECTS) ==
|
||||
(completed_event == INVALID_HANDLE_VALUE) );
|
||||
if ( num_active <= MAXIMUM_WAIT_OBJECTS )
|
||||
{
|
||||
twh_params twh;
|
||||
twh.active_procs = active_procs;
|
||||
twh.active_handles = active_handles;
|
||||
twh.num_active = num_active;
|
||||
twh.timeoutMillis = timeoutMillis;
|
||||
return try_wait_helper( &twh );
|
||||
}
|
||||
|
||||
num_threads = num_active / MAXIMUM_WAIT_OBJECTS;
|
||||
last_chunk_size = num_active % MAXIMUM_WAIT_OBJECTS;
|
||||
num_handles = num_threads;
|
||||
if ( last_chunk_size )
|
||||
{
|
||||
/* Can we fit the last chunk in the outer WFMO call? */
|
||||
if ( last_chunk_size <= MAXIMUM_WAIT_OBJECTS - num_threads )
|
||||
{
|
||||
last_chunk_offset = num_threads * MAXIMUM_WAIT_OBJECTS;
|
||||
for ( i = 0; i < last_chunk_size; ++i )
|
||||
thread_handles[ i + num_threads ] =
|
||||
active_handles[ i + last_chunk_offset ];
|
||||
num_handles = num_threads + last_chunk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We need another thread for the remainder. */
|
||||
/* Add completed_event handle to the last chunk. */
|
||||
active_handles[ num_active ] = completed_event;
|
||||
active_procs[ num_active ] = -1;
|
||||
++last_chunk_size;
|
||||
++num_active;
|
||||
++num_threads;
|
||||
num_handles = num_threads;
|
||||
}
|
||||
}
|
||||
|
||||
assert( num_threads <= MAX_THREADS );
|
||||
|
||||
for ( i = 0; i < num_threads; ++i )
|
||||
{
|
||||
thread_params[i].active_procs = active_procs +
|
||||
i * MAXIMUM_WAIT_OBJECTS;
|
||||
thread_params[i].active_handles = active_handles +
|
||||
i * MAXIMUM_WAIT_OBJECTS;
|
||||
thread_params[i].timeoutMillis = INFINITE;
|
||||
thread_params[i].num_active = MAXIMUM_WAIT_OBJECTS;
|
||||
if ( ( i == num_threads - 1 ) && last_chunk_size &&
|
||||
( num_handles == num_threads ) )
|
||||
thread_params[i].num_active = last_chunk_size;
|
||||
thread_handles[i] = CreateThread(NULL, 4 * 1024,
|
||||
(LPTHREAD_START_ROUTINE)&try_wait_helper, &thread_params[i],
|
||||
0, NULL);
|
||||
}
|
||||
wait_api_result = WaitForMultipleObjects(num_handles, thread_handles,
|
||||
FALSE, timeoutMillis);
|
||||
if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
|
||||
( wait_api_result < WAIT_OBJECT_0 + num_active ) )
|
||||
( wait_api_result < WAIT_OBJECT_0 + num_threads ) )
|
||||
{
|
||||
HANDLE thread_handle = thread_handles[wait_api_result - WAIT_OBJECT_0];
|
||||
success = GetExitCodeThread(thread_handle, (DWORD *)&result);
|
||||
assert( success );
|
||||
}
|
||||
else if ( ( WAIT_OBJECT_0 + num_threads <= wait_api_result ) &&
|
||||
( wait_api_result < WAIT_OBJECT_0 + num_handles ) )
|
||||
{
|
||||
unsigned int offset = wait_api_result - num_threads - WAIT_OBJECT_0;
|
||||
result = active_procs[ last_chunk_offset + offset ];
|
||||
}
|
||||
SetEvent(completed_event);
|
||||
/* Should complete instantly. */
|
||||
WaitForMultipleObjects(num_threads, thread_handles, TRUE, INFINITE);
|
||||
CloseHandle(completed_event);
|
||||
for ( i = 0; i < num_threads; ++i )
|
||||
CloseHandle(thread_handles[i]);
|
||||
return result;
|
||||
#undef MAX_THREADS
|
||||
}
|
||||
|
||||
static int try_wait_helper( twh_params * params )
|
||||
{
|
||||
int wait_api_result;
|
||||
|
||||
assert( params->num_active <= MAXIMUM_WAIT_OBJECTS );
|
||||
|
||||
/* Wait for a child to complete, or for our timeout window to expire. */
|
||||
wait_api_result = WaitForMultipleObjects( params->num_active,
|
||||
params->active_handles, FALSE, params->timeoutMillis );
|
||||
if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
|
||||
( wait_api_result < WAIT_OBJECT_0 + params->num_active ) )
|
||||
{
|
||||
/* Terminated process detected - return its index. */
|
||||
return active_procs[ wait_api_result - WAIT_OBJECT_0 ];
|
||||
return params->active_procs[ wait_api_result - WAIT_OBJECT_0 ];
|
||||
}
|
||||
|
||||
/* Timeout. */
|
||||
|
||||
@@ -32,6 +32,7 @@ import path ;
|
||||
import pch ;
|
||||
import property ;
|
||||
import rc ;
|
||||
import set ;
|
||||
import toolset ;
|
||||
import type ;
|
||||
|
||||
@@ -130,6 +131,14 @@ rule init (
|
||||
# Platform specific setup command to invoke before running any of the
|
||||
# msvc tools used when builing a target for a specific platform, e.g.
|
||||
# when building a 32 or 64 bit executable.
|
||||
#
|
||||
# <rewrite-setup-scripts>
|
||||
# Whether to rewrite setup scripts. New scripts will be output in
|
||||
# TEMP directory and will be used instead of originals in build actions.
|
||||
# Possible values:
|
||||
# * on - rewrite scripts, if they do not already exist (default)
|
||||
# * always - always rewrite scripts, even if they already exist
|
||||
# * off - use original setup scripts
|
||||
: options *
|
||||
)
|
||||
{
|
||||
@@ -676,6 +685,58 @@ local rule auto-detect-toolset-versions ( )
|
||||
}
|
||||
}
|
||||
|
||||
# Helper rule to generate a faster alternative to MSVC setup scripts.
|
||||
# We used to call MSVC setup scripts directly in every action, however in
|
||||
# newer MSVC versions (10.0+) they make long-lasting registry queries
|
||||
# which have a significant impact on build time.
|
||||
local rule maybe-rewrite-setup ( setup-script : setup-options : version : rewrite-setup ? )
|
||||
{
|
||||
local result = $(setup-script)" "$(setup-options) ;
|
||||
# At the moment we only know how to rewrite scripts with cmd shell.
|
||||
if ( [ os.name ] in NT ) && ( $(rewrite-setup) != off )
|
||||
{
|
||||
setup-script-id = b2_msvc_$(version)_$(setup-script:B) ;
|
||||
if $(setup-options)-is-not-empty
|
||||
{
|
||||
setup-script-id = $(setup-script-id)_$(setup-options) ;
|
||||
}
|
||||
|
||||
if $(.$(setup-script-id))
|
||||
{
|
||||
errors.error rewriting setup script for the second time ;
|
||||
}
|
||||
|
||||
local tmpdir = [ os.environ TEMP ] ;
|
||||
local replacement = [ path.native $(tmpdir)/$(setup-script-id).cmd ] ;
|
||||
if ( $(rewrite-setup) = always ) || ( ! [ path.exists $(replacement) ] )
|
||||
{
|
||||
local original-vars = [ SPLIT_BY_CHARACTERS [ SHELL set ] : "\n" ] ;
|
||||
local new-vars = [ SPLIT_BY_CHARACTERS [ SHELL "$(setup-script) $(setup-options)>nul && set" ] : "\n" ] ;
|
||||
local diff-vars = [ set.difference $(new-vars) : $(original-vars) ] ;
|
||||
if $(diff-vars)
|
||||
{
|
||||
local target = <new-setup-script>$(replacement) ;
|
||||
FILE_CONTENTS on $(target) = "SET "$(diff-vars) ;
|
||||
ALWAYS $(target) ;
|
||||
msvc.write-setup-script $(target) ;
|
||||
UPDATE_NOW $(target) : : ignore-minus-n ;
|
||||
.$(setup-script-id) = $(replacement) ;
|
||||
result = $(replacement) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = $(replacement) ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
actions write-setup-script
|
||||
{
|
||||
@($(STDOUT):E=$(FILE_CONTENTS:J=$(.nl))) > "$(<)"
|
||||
}
|
||||
|
||||
|
||||
# Worker rule for toolset version configuration. Takes an explicit version id or
|
||||
# nothing in case it should configure the default toolset version (the first
|
||||
@@ -931,7 +992,9 @@ local rule configure-really ( version ? : options * )
|
||||
# Append setup options to the setup name and add the final setup
|
||||
# prefix & suffix.
|
||||
setup-options ?= "" ;
|
||||
setup-$(c) = $(setup-prefix)$(setup-$(c):J=" ")" "$(setup-options:J=" ")$(setup-suffix) ;
|
||||
local rewrite = [ feature.get-values <rewrite-setup-scripts> : $(options) ] ;
|
||||
setup-$(c) = [ maybe-rewrite-setup $(setup-$(c):J=" ") : $(setup-options:J=" ") : $(version) : $(rewrite) ] ;
|
||||
setup-$(c) = $(setup-prefix)$(setup-$(c))$(setup-suffix) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user