*/
/* This file is ALSO:
+ * Copyright 2022 René Ferdinand Rivera Morell
* Copyright 2001-2004 David Abrahams.
* Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ * (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt)
*/
/*
#include "search.h"
#include "variable.h"
#include "output.h"
+#include "startup.h"
#include <assert.h>
#include <stdlib.h>
#endif
static CMD * make1cmds ( TARGET * );
-static LIST * make1list ( LIST *, TARGETS *, int flags );
+static LIST * make1list ( LIST *, const targets_uptr &, int32_t flags );
static SETTINGS * make1settings ( struct module_t *, LIST * vars );
static void make1bind ( TARGET * );
-static void push_cmds( CMDLIST * cmds, int status );
-static int cmd_sem_lock( TARGET * t );
+static void push_cmds( CMDLIST * cmds, int32_t status );
+static int32_t cmd_sem_lock( TARGET * t );
static void cmd_sem_unlock( TARGET * t );
-static int targets_contains( TARGETS * l, TARGET * t );
-static int targets_equal( TARGETS * l1, TARGETS * l2 );
+static bool targets_contains( const targets_uptr & l, TARGET * t );
+static bool targets_equal( const targets_uptr & l1, const targets_uptr & l2 );
/* Ugly static - it is too hard to carry it through the callbacks. */
static struct
{
- int failed;
- int skipped;
- int total;
- int made;
+ int32_t failed;
+ int32_t skipped;
+ int32_t total;
+ int32_t made;
} counts[ 1 ];
/* Target state. */
state * prev; /* previous state on stack */
TARGET * t; /* current target */
TARGET * parent; /* parent argument necessary for MAKE1A */
- int curstate; /* current state */
+ int32_t curstate; /* current state */
};
static void make1a( state * const );
static void make1b( state * const );
static void make1c( state const * const );
-static void make1c_closure( void * const closure, int status,
+static void make1c_closure( void * const closure, int32_t status,
timing_info const * const, char const * const cmd_stdout,
- char const * const cmd_stderr, int const cmd_exit_reason );
+ char const * const cmd_stderr, int32_t const cmd_exit_reason );
typedef struct _stack
{
static state * state_freelist = NULL;
/* Currently running command counter. */
-static int cmdsrunning;
+static int32_t cmdsrunning;
static state * alloc_state()
static state * push_state( stack * const pStack, TARGET * const t,
- TARGET * const parent, int const curstate )
+ TARGET * const parent, int32_t const curstate )
{
state * const pState = alloc_state();
pState->t = t;
* make1() - execute commands to update a list of targets and all of their dependencies
*/
-static int intr = 0;
-static int quit = 0;
+static int32_t intr = 0;
+static int32_t quit = 0;
-int make1( LIST * targets )
+int32_t make1( LIST * targets )
{
state * pState;
- int status = 0;
+ int32_t status = 0;
memset( (char *)counts, 0, sizeof( *counts ) );
/* If we were interrupted, exit now that all child processes
have finished. */
if ( intr )
- exit( EXITBAD );
+ b2::clean_exit( EXITBAD );
{
LISTITER iter, end;
TARGET * const parent_scc = target_scc( pState->parent );
if ( t != parent_scc )
{
- t->parents = targetentry( t->parents, parent_scc );
+ targetentry( t->parents, parent_scc );
++parent_scc->asynccnt;
}
}
/* Push dependency build requests (to be executed in the natural order). */
{
stack temp_stack = { NULL };
- TARGETS * c;
- for ( c = t->depends; c && !quit; c = c->next )
+ targets_ptr c;
+ for ( c = t->depends.get(); c && !quit; c = c->next.get() )
push_state( &temp_stack, c->target, t, T_STATE_MAKE1A );
push_stack_on_stack( &state_stack, &temp_stack );
}
*/
if ( !globs.noexec )
{
- TARGETS * c;
- for ( c = t->depends; c; c = c->next )
+ targets_ptr c;
+ for ( c = t->depends.get(); c; c = c->next.get() )
if ( c->target->status > t->status && !( c->target->flags &
T_FLAG_NOCARE ) )
{
default:
err_printf( "ERROR: %s has bad fate %d", object_str( t->name ),
t->fate );
- abort();
+ b2::clean_exit( b2::exit_result::failure );
}
/* Proceed to MAKE1C to begin executing the chain of commands prepared for
{
TARGET * const t = pState->t;
CMD * const cmd = (CMD *)t->cmds;
- int exec_flags = 0;
+ int32_t exec_flags = 0;
if ( cmd )
{
/* Tell parents their dependency has been built. */
{
- TARGETS * c;
+ targets_ptr c;
stack temp_stack = { NULL };
TARGET * additional_includes = NULL;
* cleaned up correctly.
*/
t->includes->includes = saved_includes;
- for ( c = t->dependants; c; c = c->next )
- c->target->depends = targetentry( c->target->depends,
- t->includes );
+ for ( c = t->dependants.get(); c; c = c->next.get() )
+ targetentry( c->target->depends, t->includes );
/* Will be processed below. */
additional_includes = t->includes;
}
}
if ( additional_includes )
- for ( c = t->parents; c; c = c->next )
+ for ( c = t->parents.get(); c; c = c->next.get() )
push_state( &temp_stack, additional_includes, c->target,
T_STATE_MAKE1A );
{
TARGET * const scc_root = target_scc( t );
assert( scc_root->progress < T_MAKE_DONE );
- for ( c = t->parents; c; c = c->next )
+ for ( c = t->parents.get(); c; c = c->next.get() )
{
if ( target_scc( c->target ) == scc_root )
push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B
);
else
- scc_root->parents = targetentry( scc_root->parents,
- c->target );
+ targetentry( scc_root->parents, c->target );
}
}
else
{
- for ( c = t->parents; c; c = c->next )
+ for ( c = t->parents.get(); c; c = c->next.get() )
push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
}
static void call_action_rule
(
TARGET * target,
- int status,
+ int32_t status,
timing_info const * time,
char const * executed_command,
char const * command_output
static void make1c_closure
(
void * const closure,
- int status_orig,
+ int32_t status_orig,
timing_info const * const time,
char const * const cmd_stdout,
char const * const cmd_stderr,
- int const cmd_exit_reason
+ int32_t const cmd_exit_reason
)
{
TARGET * const t = (TARGET *)closure;
}
/* push the next MAKE1C state after a command is run. */
-static void push_cmds( CMDLIST * cmds, int status )
+static void push_cmds( CMDLIST * cmds, int32_t status )
{
CMDLIST * cmd_iter;
for( cmd_iter = cmds; cmd_iter; cmd_iter = cmd_iter->next )
static CMD * make1cmds( TARGET * t )
{
CMD * cmds = 0;
- CMD * last_cmd;
+ CMD * last_cmd = 0;
LIST * shell = L0;
module_t * settings_module = 0;
TARGET * settings_target = 0;
- ACTIONS * a0;
- int const running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
+ ACTIONS * a0 = 0;
+ int32_t const running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
/* Step through actions.
*/
for ( a0 = t->actions; a0; a0 = a0->next )
{
RULE * rule = a0->action->rule;
- rule_actions * actions = rule->actions;
+ rule_actions_ptr actions = rule->actions;
SETTINGS * boundvars;
LIST * nt;
LIST * ns;
* Note that we loop through at least once, for sourceless actions.
*/
{
- int const length = list_length( ns );
- int start = 0;
- int chunk = length;
- int cmd_count = 0;
- TARGETS * semaphores = NULL;
- TARGETS * targets_iter;
- int unique_targets;
+ int32_t const length = list_length( ns );
+ int32_t start = 0;
+ int32_t chunk = length;
+ int32_t cmd_count = 0;
+ targets_uptr semaphores;
+ targets_ptr targets_iter;
+ int32_t unique_targets;
do
{
CMD * cmd;
- int cmd_check_result;
- int cmd_error_length;
- int cmd_error_max_length;
- int retry = 0;
- int accept_command = 0;
+ int32_t cmd_check_result;
+ int32_t cmd_error_length;
+ int32_t cmd_error_max_length;
+ int32_t retry = 0;
+ int32_t accept_command = 0;
/* Build cmd: cmd_new() takes ownership of its lists. */
cmd = cmd_new( rule, list_copy( nt ), list_sublist( ns, start,
: "contains a line that is too long";
assert( cmd_check_result == EXEC_CHECK_TOO_LONG ||
cmd_check_result == EXEC_CHECK_LINE_TOO_LONG );
- out_printf( "%s action %s (%d, max %d):\n", object_str(
- rule->name ), error_message, cmd_error_length,
- cmd_error_max_length );
+ out_printf(
+ "%s action %s (%d, max %d):\n",
+ object_str( rule->name ), error_message,
+ cmd_error_length, cmd_error_max_length );
/* Tell the user what did not fit. */
out_puts( cmd->buf->value );
- exit( EXITBAD );
+ b2::clean_exit( EXITBAD );
}
assert( !retry || !accept_command );
a0->action->last_cmd = last_cmd;
unique_targets = 0;
- for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next )
+ for ( targets_iter = a0->action->targets.get(); targets_iter; targets_iter = targets_iter->next.get() )
{
if ( targets_contains( targets_iter->next, targets_iter->target ) )
continue;
#if OPT_SEMAPHORE
/* Collect semaphores */
- for ( targets_iter = a0->action->targets; targets_iter; targets_iter = targets_iter->next )
+ for ( targets_iter = a0->action->targets.get(); targets_iter; targets_iter = targets_iter->next.get() )
{
TARGET * sem = targets_iter->target->semaphore;
if ( sem )
{
if ( ! targets_contains( semaphores, sem ) )
- semaphores = targetentry( semaphores, sem );
+ targetentry( semaphores, sem );
}
}
- ( ( CMD * )a0->action->first_cmd )->lock = semaphores;
- ( ( CMD * )a0->action->last_cmd )->unlock = semaphores;
+ ( ( CMD * )a0->action->first_cmd )->lock = semaphores.get();
+ ( ( CMD * )a0->action->last_cmd )->unlock = std::move(semaphores);
#endif
}
* make1list() - turn a list of targets into a LIST, for $(<) and $(>)
*/
-static LIST * make1list( LIST * l, TARGETS * targets, int flags )
+static LIST * make1list( LIST * l, const targets_uptr & ts, int32_t flags )
{
- for ( ; targets; targets = targets->next )
+ targets_ptr targets = ts.get();
+ for ( ; targets; targets = targets->next.get() )
{
TARGET * t = targets->target;
}
-static int targets_contains( TARGETS * l, TARGET * t )
+static bool targets_contains( const targets_uptr & ts, TARGET * t )
{
- for ( ; l; l = l->next )
+ targets_ptr l = ts.get();
+ for ( ; l; l = l->next.get() )
{
if ( t == l->target )
{
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
-static int targets_equal( TARGETS * l1, TARGETS * l2 )
+static bool targets_equal( const targets_uptr & ts1, const targets_uptr & ts2 )
{
- for ( ; l1 && l2; l1 = l1->next, l2 = l2->next )
+ targets_ptr l1 = ts1.get();
+ targets_ptr l2 = ts2.get();
+ for ( ; l1 && l2; l1 = l1->next.get(), l2 = l2->next.get() )
{
if ( l1->target != l2->target )
- return 0;
+ return false;
}
return !l1 && !l2;
}
#ifdef OPT_SEMAPHORE
-static int cmd_sem_lock( TARGET * t )
+static int32_t cmd_sem_lock( TARGET * t )
{
CMD * cmd = (CMD *)t->cmds;
- TARGETS * iter;
+ targets_ptr iter;
/* Check whether all the semaphores required for updating
* this target are free.
*/
- for ( iter = cmd->lock; iter; iter = iter->next )
+ for ( iter = cmd->lock; iter; iter = iter->next.get() )
{
if ( iter->target->asynccnt > 0 )
{
if ( DEBUG_EXECCMD )
out_printf( "SEM: %s is busy, delaying launch of %s\n",
object_str( iter->target->name ), object_str( t->name ) );
- iter->target->parents = targetentry( iter->target->parents, t );
+ targetentry( iter->target->parents, t );
return 0;
}
}
/* Lock the semaphores. */
- for ( iter = cmd->lock; iter; iter = iter->next )
+ for ( iter = cmd->lock; iter; iter = iter->next.get() )
{
++iter->target->asynccnt;
if ( DEBUG_EXECCMD )
static void cmd_sem_unlock( TARGET * t )
{
CMD * cmd = ( CMD * )t->cmds;
- TARGETS * iter;
+ targets_ptr iter;
/* Release the semaphores. */
- for ( iter = cmd->unlock; iter; iter = iter->next )
+ for ( iter = cmd->unlock.get(); iter; iter = iter->next.get() )
{
if ( DEBUG_EXECCMD )
out_printf( "SEM: %s is now free\n", object_str(
--iter->target->asynccnt;
assert( iter->target->asynccnt <= 0 );
}
- for ( iter = cmd->unlock; iter; iter = iter->next )
+ for ( iter = cmd->unlock.get(); iter; iter = iter->next.get() )
{
/* Find a waiting target that's ready */
while ( iter->target->parents )
{
- TARGETS * first = iter->target->parents;
- TARGET * t1 = first->target;
-
- /* Pop the first waiting CMD */
- if ( first->next )
- first->next->tail = first->tail;
- iter->target->parents = first->next;
- BJAM_FREE( first );
+ TARGET * t1 = iter->target->parents->target;
+
+ iter->target->parents = targets_pop(std::move(iter->target->parents));
if ( cmd_sem_lock( t1 ) )
{