2
0
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:
Juraj Ivančić
2014-01-14 11:14:03 +01:00
committed by U-Sivonja\Juraj
parent e50149de3d
commit db6c3d7a79
2 changed files with 114 additions and 8 deletions

View File

@@ -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. */

View File

@@ -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. */