mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 00:52:16 +00:00
Support more than 64 parallel jobs (-j).
Windows WaitForMultipleObjects() can wait on max. 64 handles. This limitation is overcome by splitting the handle set into parts which are of adequate size, and spawning a thread which does the waiting.
This commit is contained in:
committed by
U-Sivonja\Juraj
parent
e50149de3d
commit
db6c3d7a79
@@ -780,31 +780,137 @@ 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 last_chunk_size;
|
||||
HANDLE completed_event = INVALID_HANDLE_VALUE;
|
||||
HANDLE thread_handles[MAX_THREADS];
|
||||
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 which will notify
|
||||
* threads to stop waiting. Every wait set 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;
|
||||
if ( last_chunk_size )
|
||||
{
|
||||
/* The last chunk does not have event handle, so add it now. */
|
||||
active_handles[ num_active ] = completed_event;
|
||||
active_procs[ num_active ] = -1;
|
||||
++num_active;
|
||||
++num_threads;
|
||||
++last_chunk_size;
|
||||
}
|
||||
|
||||
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 )
|
||||
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_threads, 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 );
|
||||
}
|
||||
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. */
|
||||
|
||||
@@ -409,7 +409,7 @@
|
||||
#define MAXSYM 1024 /* longest symbol in the environment */
|
||||
#define MAXJPATH 1024 /* longest filename */
|
||||
|
||||
#define MAXJOBS 64 /* internally enforced -j limit */
|
||||
#define MAXJOBS 256 /* internally enforced -j limit */
|
||||
#define MAXARGC 32 /* words in $(JAMSHELL) */
|
||||
|
||||
/* Jam private definitions below. */
|
||||
|
||||
Reference in New Issue
Block a user