summaryrefslogtreecommitdiff
path: root/src/remake.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/remake.c')
-rw-r--r--src/remake.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/src/remake.c b/src/remake.c
index 04daf49c..dec4667c 100644
--- a/src/remake.c
+++ b/src/remake.c
@@ -119,6 +119,7 @@ update_goal_chain (struct goaldep *goaldeps)
unsigned long last_cmd_count = 0;
int t = touch_flag, q = question_flag, n = just_print_flag;
enum update_status status = us_none;
+ const unsigned int depth = rebuilding_makefiles ? 1 : 0;
/* Duplicate the chain so we can remove things from it. */
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
@@ -137,6 +138,7 @@ update_goal_chain (struct goaldep *goaldeps)
while (goals != 0)
{
struct dep *gu, *g, *lastgoal;
+ int running = 0, wait = 0;
/* Start jobs that are waiting for the load to go down. */
@@ -154,16 +156,14 @@ update_goal_chain (struct goaldep *goaldeps)
while (gu != 0)
{
/* Iterate over all double-colon entries for this file. */
- struct file *file;
+ struct file *file, *dchead;
int stop = 0, any_not_updated = 0;
g = gu->shuf ? gu->shuf : gu;
goal_dep = g;
-
- for (file = g->file->double_colon ? g->file->double_colon : g->file;
- file != NULL;
- file = file->prev)
+ dchead = g->file->double_colon ? g->file->double_colon : g->file;
+ for (file = dchead; file != NULL; file = file->prev)
{
unsigned int ocommands_started;
enum update_status fail;
@@ -188,8 +188,24 @@ update_goal_chain (struct goaldep *goaldeps)
actually run. */
ocommands_started = commands_started;
- fail = update_file (file, rebuilding_makefiles ? 1 : 0);
+ stop = 0;
+
+ /* In the case of double colon rules, only the recipe of the 1st
+ rule should be blocked by .WAIT. The recipes of all subsequent
+ rules for the same file will execute sequentially in order
+ after the 1st. */
+ wait = file == dchead && g->wait_here && running;
+ if (wait)
+ {
+ DBF (DB_VERBOSE, _(".WAIT is blocking '%s'.\n"));
+ break;
+ }
+
+ fail = update_file (file, depth);
check_renamed (file);
+ running |= (file->command_state == cs_running
+ || file->command_state == cs_deps_running);
+
/* Set the goal's 'changed' flag if any commands were started
by calling update_file above. We check this flag below to
@@ -197,7 +213,6 @@ update_goal_chain (struct goaldep *goaldeps)
if (commands_started > ocommands_started)
g->changed = 1;
- stop = 0;
if ((fail || file->updated) && status < us_question)
{
/* We updated this goal. Update STATUS and decide whether
@@ -249,6 +264,9 @@ update_goal_chain (struct goaldep *goaldeps)
/* Reset FILE since it is null at the end of the loop. */
file = g->file;
+ if (wait)
+ break;
+
if (stop || !any_not_updated)
{
/* If we have found nothing whatever to do for the goal,
@@ -285,8 +303,9 @@ update_goal_chain (struct goaldep *goaldeps)
}
/* If we reached the end of the dependency graph update CONSIDERED
- for the next pass. */
- if (gu == 0)
+ for the next pass. In the case of waiting, increment CONSIDERED to
+ prevent the same file from getting pruned over and over again. */
+ if (gu == 0 || wait)
++considered;
}
@@ -384,7 +403,8 @@ update_file (struct file *file, unsigned int depth)
if (f->command_state == cs_running
|| f->command_state == cs_deps_running)
/* Don't run other :: rules for this target until
- this rule is finished. */
+ this rule is finished. Multiple recipes running in parallel and
+ updating the same target will corrupt the target. */
return us_success;
if (new > status)