@ -1472,6 +1472,7 @@ enum child_state {
GIT_CP_WAIT_CLEANUP ,
} ;
int run_processes_parallel_ungroup ;
struct parallel_processes {
void * data ;
@ -1495,6 +1496,7 @@ struct parallel_processes {
struct pollfd * pfd ;
unsigned shutdown : 1 ;
unsigned ungroup : 1 ;
int output_owner ;
struct strbuf buffered_output ; /* of finished children */
@ -1538,7 +1540,7 @@ static void pp_init(struct parallel_processes *pp,
get_next_task_fn get_next_task ,
start_failure_fn start_failure ,
task_finished_fn task_finished ,
void * data )
void * data , int ungroup )
{
int i ;
@ -1560,15 +1562,21 @@ static void pp_init(struct parallel_processes *pp,
pp - > nr_processes = 0 ;
pp - > output_owner = 0 ;
pp - > shutdown = 0 ;
pp - > ungroup = ungroup ;
CALLOC_ARRAY ( pp - > children , n ) ;
CALLOC_ARRAY ( pp - > pfd , n ) ;
if ( pp - > ungroup )
pp - > pfd = NULL ;
else
CALLOC_ARRAY ( pp - > pfd , n ) ;
strbuf_init ( & pp - > buffered_output , 0 ) ;
for ( i = 0 ; i < n ; i + + ) {
strbuf_init ( & pp - > children [ i ] . err , 0 ) ;
child_process_init ( & pp - > children [ i ] . process ) ;
pp - > pfd [ i ] . events = POLLIN | POLLHUP ;
pp - > pfd [ i ] . fd = - 1 ;
if ( pp - > pfd ) {
pp - > pfd [ i ] . events = POLLIN | POLLHUP ;
pp - > pfd [ i ] . fd = - 1 ;
}
}
pp_for_signal = pp ;
@ -1616,24 +1624,31 @@ static int pp_start_one(struct parallel_processes *pp)
BUG ( " bookkeeping is hard " ) ;
code = pp - > get_next_task ( & pp - > children [ i ] . process ,
& pp - > children [ i ] . err ,
pp - > ungroup ? NULL : & pp - > children [ i ] . err ,
pp - > data ,
& pp - > children [ i ] . data ) ;
if ( ! code ) {
strbuf_addbuf ( & pp - > buffered_output , & pp - > children [ i ] . err ) ;
strbuf_reset ( & pp - > children [ i ] . err ) ;
if ( ! pp - > ungroup ) {
strbuf_addbuf ( & pp - > buffered_output , & pp - > children [ i ] . err ) ;
strbuf_reset ( & pp - > children [ i ] . err ) ;
}
return 1 ;
}
pp - > children [ i ] . process . err = - 1 ;
pp - > children [ i ] . process . stdout_to_stderr = 1 ;
if ( ! pp - > ungroup ) {
pp - > children [ i ] . process . err = - 1 ;
pp - > children [ i ] . process . stdout_to_stderr = 1 ;
}
pp - > children [ i ] . process . no_stdin = 1 ;
if ( start_command ( & pp - > children [ i ] . process ) ) {
code = pp - > start_failure ( & pp - > children [ i ] . err ,
code = pp - > start_failure ( pp - > ungroup ? NULL :
& pp - > children [ i ] . err ,
pp - > data ,
pp - > children [ i ] . data ) ;
strbuf_addbuf ( & pp - > buffered_output , & pp - > children [ i ] . err ) ;
strbuf_reset ( & pp - > children [ i ] . err ) ;
if ( ! pp - > ungroup ) {
strbuf_addbuf ( & pp - > buffered_output , & pp - > children [ i ] . err ) ;
strbuf_reset ( & pp - > children [ i ] . err ) ;
}
if ( code )
pp - > shutdown = 1 ;
return code ;
@ -1641,7 +1656,8 @@ static int pp_start_one(struct parallel_processes *pp)
pp - > nr_processes + + ;
pp - > children [ i ] . state = GIT_CP_WORKING ;
pp - > pfd [ i ] . fd = pp - > children [ i ] . process . err ;
if ( pp - > pfd )
pp - > pfd [ i ] . fd = pp - > children [ i ] . process . err ;
return 0 ;
}
@ -1675,6 +1691,7 @@ static void pp_buffer_stderr(struct parallel_processes *pp, int output_timeout)
static void pp_output ( struct parallel_processes * pp )
{
int i = pp - > output_owner ;
if ( pp - > children [ i ] . state = = GIT_CP_WORKING & &
pp - > children [ i ] . err . len ) {
strbuf_write ( & pp - > children [ i ] . err , stderr ) ;
@ -1697,7 +1714,7 @@ static int pp_collect_finished(struct parallel_processes *pp)
code = finish_command ( & pp - > children [ i ] . process ) ;
code = pp - > task_finished ( code ,
code = pp - > task_finished ( code , pp - > ungroup ? NULL :
& pp - > children [ i ] . err , pp - > data ,
pp - > children [ i ] . data ) ;
@ -1708,10 +1725,13 @@ static int pp_collect_finished(struct parallel_processes *pp)
pp - > nr_processes - - ;
pp - > children [ i ] . state = GIT_CP_FREE ;
pp - > pfd [ i ] . fd = - 1 ;
if ( pp - > pfd )
pp - > pfd [ i ] . fd = - 1 ;
child_process_init ( & pp - > children [ i ] . process ) ;
if ( i ! = pp - > output_owner ) {
if ( pp - > ungroup ) {
; /* no strbuf_*() work to do here */
} else if ( i ! = pp - > output_owner ) {
strbuf_addbuf ( & pp - > buffered_output , & pp - > children [ i ] . err ) ;
strbuf_reset ( & pp - > children [ i ] . err ) ;
} else {
@ -1748,9 +1768,14 @@ int run_processes_parallel(int n,
int i , code ;
int output_timeout = 100 ;
int spawn_cap = 4 ;
int ungroup = run_processes_parallel_ungroup ;
struct parallel_processes pp ;
pp_init ( & pp , n , get_next_task , start_failure , task_finished , pp_cb ) ;
/* unset for the next API user */
run_processes_parallel_ungroup = 0 ;
pp_init ( & pp , n , get_next_task , start_failure , task_finished , pp_cb ,
ungroup ) ;
while ( 1 ) {
for ( i = 0 ;
i < spawn_cap & & ! pp . shutdown & &
@ -1767,8 +1792,15 @@ int run_processes_parallel(int n,
}
if ( ! pp . nr_processes )
break ;
pp_buffer_stderr ( & pp , output_timeout ) ;
pp_output ( & pp ) ;
if ( ungroup ) {
int i ;
for ( i = 0 ; i < pp . max_processes ; i + + )
pp . children [ i ] . state = GIT_CP_WAIT_CLEANUP ;
} else {
pp_buffer_stderr ( & pp , output_timeout ) ;
pp_output ( & pp ) ;
}
code = pp_collect_finished ( & pp ) ;
if ( code ) {
pp . shutdown = 1 ;