diff --git a/src/dep.h b/src/dep.h
index e492a0b307..54386a8c17 100644
--- a/src/dep.h
+++ b/src/dep.h
@@ -53,6 +53,7 @@ struct nameseq
     unsigned int staticpattern : 1;             \
     unsigned int need_2nd_expansion : 1;        \
     unsigned int ignore_automatic_vars : 1;     \
+    unsigned int wait_after : 1;                \
     unsigned int is_explicit : 1
 
 struct dep
diff --git a/src/file.c b/src/file.c
index 765037507a..28f1ea3f5b 100644
--- a/src/file.c
+++ b/src/file.c
@@ -36,6 +36,47 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
    only work on files which have not yet been snapped. */
 int snapped_deps = 0;
 
+/* All file deps in the global namespace for which new_job() needs to wait
+ * until all commands have been processed (as via .NOTPARALLEL:). */
+static struct hash_table *a_file_wait;
+
+static unsigned long
+a_file_wait_hash_1 (const void *key)
+{
+  return_ISTRING_HASH_1 ((const char *) key);
+}
+
+static unsigned long
+a_file_wait_hash_2 (const void *key)
+{
+  return_ISTRING_HASH_2 ((const char *) key);
+}
+
+static int
+a_file_wait_hash_cmp (const void *x, const void *y)
+{
+  return_ISTRING_COMPARE ((const char *) x, (const char *) y);
+}
+
+static int
+a_file_wait_add(struct hash_table **htpp, const void *cvp)
+{
+  int rv;
+  void **slot;
+
+  if (a_file_wait == NULL)
+    {
+      a_file_wait = xmalloc (sizeof (*a_file_wait));
+      hash_init (a_file_wait, 256,
+        &a_file_wait_hash_1, &a_file_wait_hash_2, &a_file_wait_hash_cmp);
+    }
+
+  if ((rv = (*(slot = hash_find_slot (*htpp, cvp)) == NULL)))
+    hash_insert_at (*htpp, cvp, slot);
+
+  return rv;
+}
+
 /* Hash table of files the makefile knows how to make.  */
 
 static unsigned long
@@ -442,6 +483,8 @@ remove_intermediates (int sig)
 
 /* Given a string containing prerequisites (fully expanded), break it up into
    a struct dep list.  Enter each of these prereqs into the file database.
+   dep_targets_to_eval must be NULL but for first expansion pass, where it will
+   be used to create the necessary dependency relations for .WAIT:.
  */
 struct dep *
 split_prereqs (char *p)
@@ -472,6 +515,28 @@ split_prereqs (char *p)
         ood->ignore_mtime = 1;
     }
 
+  /* At each occurrance of .WAIT we want to place a barrier. */
+  /* C99 */{
+    struct dep *curr, *tail;
+
+    for (tail = NULL, curr = new; curr != NULL;)
+      {
+         if (strcmp (curr->name, ".WAIT") != 0)
+           {
+             tail = curr;
+             curr = curr->next;
+           }
+         else if (tail == NULL) /* xxx warn user of nonsense? */
+           new = curr = curr->next;
+         else
+           {
+             tail->wait_after = 1;
+             /* Take out .WAIT, noone else can deal with it. */
+             tail->next = curr = curr->next;
+           }
+      }
+  }
+
   return new;
 }
 
@@ -1203,4 +1268,18 @@ init_hash_files (void)
   hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp);
 }
 
+void
+file_wait_add (const char *name)
+{
+  assert (strcache_iscached (name));
+  (void) a_file_wait_add(&a_file_wait, name);
+}
+
+int
+file_wait_is_needed (const struct file *file)
+{
+  return (a_file_wait != NULL &&
+      hash_find_item (a_file_wait, file->name) != NULL);
+}
+
 /* EOF */
diff --git a/src/filedef.h b/src/filedef.h
index 972f85331c..8c9db82f6d 100644
--- a/src/filedef.h
+++ b/src/filedef.h
@@ -216,3 +216,7 @@ FILE_TIMESTAMP f_mtime (struct file *file, int search);
 
 /* Have we snapped deps yet?  */
 extern int snapped_deps;
+
+/* .WAIT logic */
+void file_wait_add (const char *name);
+int file_wait_is_needed (const struct file *file);
diff --git a/src/job.c b/src/job.c
index ee59b95b68..987ca33318 100644
--- a/src/job.c
+++ b/src/job.c
@@ -1909,7 +1909,7 @@ new_job (struct file *file)
      (This will notice if there is in fact no recipe.)  */
   start_waiting_job (c);
 
-  if (job_slots == 1 || not_parallel)
+  if (job_slots == 1 || not_parallel || file_wait_is_needed (file))
     /* Since there is only one job slot, make things run linearly.
        Wait for the child to die, setting the state to 'cs_finished'.  */
     while (file->command_state == cs_running)
diff --git a/src/read.c b/src/read.c
index c0e3315f41..85baf4fb37 100644
--- a/src/read.c
+++ b/src/read.c
@@ -2217,12 +2217,14 @@ record_files (struct nameseq *filenames, int are_also_makes,
       /* Add the dependencies to this file entry.  */
       if (this != 0)
         {
+          struct dep *d;
+
           /* Add the file's old deps and the new ones in THIS together.  */
           if (f->deps == 0)
             f->deps = this;
           else if (cmds != 0)
             {
-              struct dep *d = this;
+              d = this;
 
               /* If this rule has commands, put these deps first.  */
               while (d->next != 0)
@@ -2233,7 +2235,7 @@ record_files (struct nameseq *filenames, int are_also_makes,
             }
           else
             {
-              struct dep *d = f->deps;
+              d = f->deps;
 
               /* A rule without commands: put its prereqs at the end.  */
               while (d->next != 0)
@@ -2279,7 +2281,7 @@ record_files (struct nameseq *filenames, int are_also_makes,
 
         f->also_make = cpy;
       }
-    }
+  }
 }
 
 /* Search STRING for an unquoted STOPMAP.
diff --git a/src/remake.c b/src/remake.c
index f7605fc062..f21073eb25 100644
--- a/src/remake.c
+++ b/src/remake.c
@@ -68,6 +68,9 @@ static struct dep *goal_dep;
    All files start with considered == 0.  */
 static unsigned int considered = 0;
 
+static void a_check_wait_state (struct file *fp);
+static void a_recur_wait_state (struct file *fp);
+
 static enum update_status update_file (struct file *file, unsigned int depth);
 static enum update_status update_file_1 (struct file *file, unsigned int depth);
 static enum update_status check_dep (struct file *file, unsigned int depth,
@@ -104,6 +107,15 @@ update_goal_chain (struct goaldep *goaldeps)
   /* Start a fresh batch of consideration.  */
   ++considered;
 
+  /* Recursively check whether any of the goals that really are to be worked
+   * requires .WAIT serialization, and actually enable that if so. */
+  /* C99 */{
+      struct dep *dp;
+
+      for (dp = goals; dp != NULL; dp = dp->next)
+        a_check_wait_state (dp->file);
+    }
+
   /* Update all the goals until they are all finished.  */
 
   while (goals != 0)
@@ -295,6 +307,40 @@ show_goal_error (void)
       }
 }
 
+/* Recursively check whether any of the goals that really are to be worked
+ * requires .WAIT serialization, and actually enable that if so. */
+static void
+a_check_wait_state (struct file *fp)
+{
+  struct dep *tailp, *dp;
+
+  for (tailp = dp = fp->deps; dp != NULL; dp = dp->next)
+    {
+      if (dp->wait_after)
+        {
+          struct dep *xp;
+
+          for (xp = tailp; xp != dp->next; xp = xp->next)
+            a_recur_wait_state (xp->file);
+
+	  tailp = dp->next;
+	}
+
+      a_check_wait_state(dp->file);
+    }
+}
+
+static void
+a_recur_wait_state (struct file *fp)
+{
+  struct dep *dp;
+
+  file_wait_add (fp->name);
+
+  for (dp = fp->deps; dp != NULL; dp = dp->next)
+    a_recur_wait_state (dp->file);
+}
+
 /* If FILE is not up to date, execute the commands for it.
    Return 0 if successful, non-0 if unsuccessful;
    but with some flag settings, just call 'exit' if unsuccessful.
