Add support for user defined "pool" to GN.

Allow user to define pool of limited size to limit the number of
concurrent tasks that are executed for a given set of tools. The
pool object directly correspond to a ninja pool and can be shared
by multiple targets.

Design document:
https://docs.google.com/document/d/1b598i4WmeFOe3_iRBrjPKSXdcR5R32UPtgxqKmoY2-M/view

BUG=612786

Review-Url: https://codereview.chromium.org/2006923004
Cr-Original-Commit-Position: refs/heads/master@{#397917}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 40451c5093a4108bf65d3aae30bea2ab014f4b94
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index 2dfcf7f..e136127 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -146,6 +146,8 @@
     "path_output.h",
     "pattern.cc",
     "pattern.h",
+    "pool.cc",
+    "pool.h",
     "qt_creator_writer.cc",
     "qt_creator_writer.h",
     "runtime_deps.cc",
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc
index 22b4c47..036d390 100644
--- a/tools/gn/builder.cc
+++ b/tools/gn/builder.cc
@@ -11,6 +11,7 @@
 #include "tools/gn/deps_iterator.h"
 #include "tools/gn/err.h"
 #include "tools/gn/loader.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/target.h"
@@ -263,6 +264,19 @@
   if (!AddDeps(record, toolchain->deps(), err))
     return false;
 
+  for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
+    Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
+    Tool* tool = toolchain->GetTool(tool_type);
+    if (!tool || tool->pool().label.is_null())
+      continue;
+
+    BuilderRecord* dep_record = GetOrCreateRecordOfType(
+        tool->pool().label, tool->pool().origin, BuilderRecord::ITEM_POOL, err);
+    if (!dep_record)
+      return false;
+    record->AddDep(dep_record);
+  }
+
   // The default toolchain gets generated by default. Also propogate the
   // generate flag if it depends on items in a non-default toolchain.
   if (record->should_generate() ||
@@ -429,6 +443,8 @@
     Toolchain* toolchain = record->item()->AsToolchain();
     if (!ResolveDeps(&toolchain->deps(), err))
       return false;
+    if (!ResolvePools(toolchain, err))
+      return false;
   }
 
   record->set_resolved(true);
@@ -497,6 +513,29 @@
   return true;
 }
 
+bool Builder::ResolvePools(Toolchain* toolchain, Err* err) {
+  for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
+    Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
+    Tool* tool = toolchain->GetTool(tool_type);
+    if (!tool || tool->pool().label.is_null())
+      continue;
+
+    BuilderRecord* record =
+        GetResolvedRecordOfType(tool->pool().label, toolchain->defined_from(),
+                                BuilderRecord::ITEM_POOL, err);
+    if (!record) {
+      *err = Err(tool->pool().origin, "Pool for tool not defined.",
+                 "I was hoping to find a pool " +
+                     tool->pool().label.GetUserVisibleName(false));
+      return false;
+    }
+
+    tool->set_pool(LabelPtrPair<Pool>(record->item()->AsPool()));
+  }
+
+  return true;
+}
+
 std::string Builder::CheckForCircularDependencies(
     const std::vector<const BuilderRecord*>& bad_records) const {
   std::vector<const BuilderRecord*> cycle;
diff --git a/tools/gn/builder.h b/tools/gn/builder.h
index 0445976..0c2fe70 100644
--- a/tools/gn/builder.h
+++ b/tools/gn/builder.h
@@ -119,6 +119,7 @@
   bool ResolveDeps(LabelTargetVector* deps, Err* err);
   bool ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err);
   bool ResolveToolchain(Target* target, Err* err);
+  bool ResolvePools(Toolchain* toolchain, Err* err);
 
   // Given a list of unresolved records, tries to find any circular
   // dependencies and returns the string describing the problem. If no circular
diff --git a/tools/gn/builder_record.cc b/tools/gn/builder_record.cc
index 842dbc4..107e441 100644
--- a/tools/gn/builder_record.cc
+++ b/tools/gn/builder_record.cc
@@ -26,6 +26,8 @@
       return "config";
     case ITEM_TOOLCHAIN:
       return "toolchain";
+    case ITEM_POOL:
+      return "pool";
     case ITEM_UNKNOWN:
     default:
       return "unknown";
@@ -41,6 +43,8 @@
       return !!item->AsConfig();
     case ITEM_TOOLCHAIN:
       return !!item->AsToolchain();
+    case ITEM_POOL:
+      return !!item->AsPool();
     case ITEM_UNKNOWN:
     default:
       return false;
@@ -55,6 +59,8 @@
     return ITEM_CONFIG;
   if (item->AsToolchain())
     return ITEM_TOOLCHAIN;
+  if (item->AsPool())
+    return ITEM_POOL;
 
   NOTREACHED();
   return ITEM_UNKNOWN;
diff --git a/tools/gn/builder_record.h b/tools/gn/builder_record.h
index a767c9b..7643b47 100644
--- a/tools/gn/builder_record.h
+++ b/tools/gn/builder_record.h
@@ -35,7 +35,8 @@
     ITEM_UNKNOWN,
     ITEM_TARGET,
     ITEM_CONFIG,
-    ITEM_TOOLCHAIN
+    ITEM_TOOLCHAIN,
+    ITEM_POOL
   };
 
   BuilderRecord(ItemType type, const Label& label);
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 59c54dc..c5b36cf 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -2143,6 +2143,47 @@
 
 
 ```
+## **pool**: Defines a pool object.
+
+```
+  Pool objects can be applied to a tool to limit the parallelism of the
+  build. This object has a single property "depth" corresponding to
+  the number of tasks that may run simultaneously.
+
+  As the file containing the pool definition may be executed in the
+  of more than one toolchain it is recommended to specify an explicit
+  toolchain when definining and referencing a pool.
+
+  A pool is referenced by its label just like a target.
+
+```
+
+### **Variables**
+
+```
+  depth*
+  * = required
+
+```
+
+### **Example**
+
+```
+  if (current_toolchain == default_toolchain) {
+    pool("link_pool") {
+      depth = 1
+    }
+  }
+
+  toolchain("toolchain") {
+    tool("link") {
+      command = "..."
+      pool = ":link_pool($default_toolchain)")
+    }
+  }
+
+
+```
 ## **print**: Prints to the console.
 
 ```
@@ -2913,6 +2954,14 @@
             "{{output_dir}}/{{target_output_name}}.lib",
           ]
 
+    pool [label, optional]
+
+        Label of the pool to use for the tool. Pools are used to limit
+        the number of tasks that can execute concurrently during the
+        build.
+
+        See also "gn help pool".
+
     link_output  [string with substitutions]
     depend_output  [string with substitutions]
     runtime_link_output  [string with substitutions]
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index aaa9b7e..210cc2c 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -8,6 +8,8 @@
 
 #include "tools/gn/err.h"
 #include "tools/gn/functions.h"
+#include "tools/gn/label.h"
+#include "tools/gn/label_ptr.h"
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
@@ -57,6 +59,31 @@
   return true;
 }
 
+// Reads the given label from the scope (if present) and puts the result into
+// dest. If the value is not a label, sets the error and returns false.
+bool ReadLabel(Scope* scope,
+               const char* var,
+               Tool* tool,
+               const ParseNode* origin,
+               const Label& current_toolchain,
+               void (Tool::*set)(const LabelPtrPair<Pool>&),
+               Err* err) {
+  const Value* v = scope->GetValue(var, true);
+  if (!v)
+    return true;  // Not present is fine.
+
+  Label label =
+      Label::Resolve(scope->GetSourceDir(), current_toolchain, *v, err);
+  if (err->has_error())
+    return false;
+
+  LabelPtrPair<Pool> pair(label);
+  pair.origin = origin;
+
+  (tool->*set)(pair);
+  return true;
+}
+
 // Calls the given validate function on each type in the list. On failure,
 // sets the error, blame the value, and return false.
 bool ValidateSubstitutionList(const std::vector<SubstitutionType>& list,
@@ -518,6 +545,14 @@
     "            \"{{output_dir}}/{{target_output_name}}.lib\",\n"
     "          ]\n"
     "\n"
+    "    pool [label, optional]\n"
+    "\n"
+    "        Label of the pool to use for the tool. Pools are used to limit\n"
+    "        the number of tasks that can execute concurrently during the\n"
+    "        build.\n"
+    "\n"
+    "        See also \"gn help pool\".\n"
+    "\n"
     "    link_output  [string with substitutions]\n"
     "    depend_output  [string with substitutions]\n"
     "    runtime_link_output  [string with substitutions]\n"
@@ -908,7 +943,9 @@
       !ReadPattern(&block_scope, "rspfile", subst_validator, tool.get(),
                    &Tool::set_rspfile, err) ||
       !ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(),
-                   &Tool::set_rspfile_content, err)) {
+                   &Tool::set_rspfile_content, err) ||
+      !ReadLabel(&block_scope, "pool", tool.get(), function, toolchain->label(),
+                 &Tool::set_pool, err)) {
     return Value();
   }
 
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index af413d6..24bc2c9 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -15,6 +15,7 @@
 #include "tools/gn/err.h"
 #include "tools/gn/input_file.h"
 #include "tools/gn/parse_tree.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/settings.h"
@@ -678,6 +679,94 @@
   return Value();
 }
 
+// pool ------------------------------------------------------------------------
+
+const char kPool[] = "pool";
+const char kPool_HelpShort[] =
+    "pool: Defines a pool object.";
+const char kPool_Help[] =
+    "pool: Defines a pool object.\n"
+    "\n"
+    "  Pool objects can be applied to a tool to limit the parallelism of the\n"
+    "  build. This object has a single property \"depth\" corresponding to\n"
+    "  the number of tasks that may run simultaneously.\n"
+    "\n"
+    "  As the file containing the pool definition may be executed in the\n"
+    "  of more than one toolchain it is recommended to specify an explicit\n"
+    "  toolchain when definining and referencing a pool.\n"
+    "\n"
+    "  A pool is referenced by its label just like a target.\n"
+    "\n"
+    "Variables\n"
+    "\n"
+    "  depth*\n"
+    "  * = required\n"
+    "\n"
+    "Example\n"
+    "\n"
+    "  if (current_toolchain == default_toolchain) {\n"
+    "    pool(\"link_pool\") {\n"
+    "      depth = 1\n"
+    "    }\n"
+    "  }\n"
+    "\n"
+    "  toolchain(\"toolchain\") {\n"
+    "    tool(\"link\") {\n"
+    "      command = \"...\"\n"
+    "      pool = \":link_pool($default_toolchain)\")\n"
+    "    }\n"
+    "  }\n";
+
+const char kDepth[] = "depth";
+
+Value RunPool(const FunctionCallNode* function,
+              const std::vector<Value>& args,
+              Scope* scope,
+              Err* err) {
+  NonNestableBlock non_nestable(scope, function, "pool");
+  if (!non_nestable.Enter(err))
+    return Value();
+
+  if (!EnsureSingleStringArg(function, args, err) ||
+      !EnsureNotProcessingImport(function, scope, err))
+    return Value();
+
+  Label label(MakeLabelForScope(scope, function, args[0].string_value()));
+
+  if (g_scheduler->verbose_logging())
+    g_scheduler->Log("Defining pool", label.GetUserVisibleName(true));
+
+  // Get the pool depth. It is an error to define a pool without a depth,
+  // so check first for the presence of the value.
+  const Value* depth = scope->GetValue(kDepth, true);
+  if (!depth) {
+    *err = Err(function, "Can't define a pool without depth.");
+    return Value();
+  }
+
+  if (!depth->VerifyTypeIs(Value::INTEGER, err))
+    return Value();
+
+  if (depth->int_value() < 0) {
+    *err = Err(function, "depth must be positive or nul.");
+    return Value();
+  }
+
+  // Create the new pool.
+  std::unique_ptr<Pool> pool(new Pool(scope->settings(), label));
+  pool->set_depth(depth->int_value());
+
+  // Save the generated item.
+  Scope::ItemVector* collector = scope->GetItemCollector();
+  if (!collector) {
+    *err = Err(function, "Can't define a pool in this context.");
+    return Value();
+  }
+  collector->push_back(pool.release());
+
+  return Value();
+}
+
 // print -----------------------------------------------------------------------
 
 const char kPrint[] = "print";
@@ -826,6 +915,7 @@
     INSERT_FUNCTION(GetPathInfo, false)
     INSERT_FUNCTION(GetTargetOutputs, false)
     INSERT_FUNCTION(Import, false)
+    INSERT_FUNCTION(Pool, false)
     INSERT_FUNCTION(Print, false)
     INSERT_FUNCTION(ProcessFileTemplate, false)
     INSERT_FUNCTION(ReadFile, false)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index 3ce945e..aadc966 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -222,6 +222,14 @@
                         BlockNode* block,
                         Err* err);
 
+extern const char kPool[];
+extern const char kPool_HelpShort[];
+extern const char kPool_Help[];
+Value RunPool(const FunctionCallNode* function,
+              const std::vector<Value>& args,
+              Scope* block_scope,
+              Err* err);
+
 extern const char kPrint[];
 extern const char kPrint_HelpShort[];
 extern const char kPrint_Help[];
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index 8428948..352a332 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -146,6 +146,8 @@
         'path_output.h',
         'pattern.cc',
         'pattern.h',
+        'pool.cc',
+        'pool.h',
         'qt_creator_writer.cc',
         'qt_creator_writer.h',
         'runtime_deps.cc',
diff --git a/tools/gn/item.cc b/tools/gn/item.cc
index b0efd64..4fb65d1 100644
--- a/tools/gn/item.cc
+++ b/tools/gn/item.cc
@@ -20,6 +20,12 @@
 const Config* Item::AsConfig() const {
   return nullptr;
 }
+Pool* Item::AsPool() {
+  return nullptr;
+}
+const Pool* Item::AsPool() const {
+  return nullptr;
+}
 Target* Item::AsTarget() {
   return nullptr;
 }
@@ -40,6 +46,8 @@
     return "target";
   if (AsToolchain())
     return "toolchain";
+  if (AsPool())
+    return "pool";
   NOTREACHED();
   return "this thing that I have no idea what it is";
 }
diff --git a/tools/gn/item.h b/tools/gn/item.h
index 069c3ed..3ec482a 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -12,6 +12,7 @@
 
 class Config;
 class ParseNode;
+class Pool;
 class Settings;
 class Target;
 class Toolchain;
@@ -38,6 +39,8 @@
   // Manual RTTI.
   virtual Config* AsConfig();
   virtual const Config* AsConfig() const;
+  virtual Pool* AsPool();
+  virtual const Pool* AsPool() const;
   virtual Target* AsTarget();
   virtual const Target* AsTarget() const;
   virtual Toolchain* AsToolchain();
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index 2cbb245..627edb2 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -23,6 +23,7 @@
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/input_file_manager.h"
 #include "tools/gn/ninja_utils.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/switches.h"
 #include "tools/gn/target.h"
@@ -129,24 +130,26 @@
     const std::vector<const Settings*>& all_settings,
     const Toolchain* default_toolchain,
     const std::vector<const Target*>& default_toolchain_targets,
+    const std::vector<const Pool*>& all_pools,
     std::ostream& out,
     std::ostream& dep_out)
     : build_settings_(build_settings),
       all_settings_(all_settings),
       default_toolchain_(default_toolchain),
       default_toolchain_targets_(default_toolchain_targets),
+      all_pools_(all_pools),
       out_(out),
       dep_out_(dep_out),
       path_output_(build_settings->build_dir(),
-                   build_settings->root_path_utf8(), ESCAPE_NINJA) {
-}
+                   build_settings->root_path_utf8(),
+                   ESCAPE_NINJA) {}
 
 NinjaBuildWriter::~NinjaBuildWriter() {
 }
 
 bool NinjaBuildWriter::Run(Err* err) {
   WriteNinjaRules();
-  WriteLinkPool();
+  WriteAllPools();
   WriteSubninjas();
   return WritePhonyAndAllRules(err);
 }
@@ -157,13 +160,14 @@
     const std::vector<const Settings*>& all_settings,
     const Toolchain* default_toolchain,
     const std::vector<const Target*>& default_toolchain_targets,
+    const std::vector<const Pool*>& all_pools,
     Err* err) {
   ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
 
   std::stringstream file;
   std::stringstream depfile;
   NinjaBuildWriter gen(build_settings, all_settings, default_toolchain,
-                       default_toolchain_targets, file, depfile);
+                       default_toolchain_targets, all_pools, file, depfile);
   if (!gen.Run(err))
     return false;
 
@@ -224,10 +228,17 @@
   out_ << std::endl;
 }
 
-void NinjaBuildWriter::WriteLinkPool() {
+void NinjaBuildWriter::WriteAllPools() {
   out_ << "pool link_pool\n"
        << "  depth = " << default_toolchain_->concurrent_links() << std::endl
        << std::endl;
+
+  for (const Pool* pool : all_pools_) {
+    std::string pool_name = pool->GetNinjaName(default_toolchain_->label());
+    out_ << "pool " << pool_name << std::endl
+         << "  depth = " << pool->depth() << std::endl
+         << std::endl;
+  }
 }
 
 void NinjaBuildWriter::WriteSubninjas() {
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h
index e94f93d..358ecc6 100644
--- a/tools/gn/ninja_build_writer.h
+++ b/tools/gn/ninja_build_writer.h
@@ -14,6 +14,7 @@
 
 class BuildSettings;
 class Err;
+class Pool;
 class Settings;
 class Target;
 class Toolchain;
@@ -28,12 +29,14 @@
       const std::vector<const Settings*>& all_settings,
       const Toolchain* default_toolchain,
       const std::vector<const Target*>& default_toolchain_targets,
+      const std::vector<const Pool*>& all_pools,
       Err* err);
 
   NinjaBuildWriter(const BuildSettings* settings,
                    const std::vector<const Settings*>& all_settings,
                    const Toolchain* default_toolchain,
                    const std::vector<const Target*>& default_toolchain_targets,
+                   const std::vector<const Pool*>& all_pools,
                    std::ostream& out,
                    std::ostream& dep_out);
   ~NinjaBuildWriter();
@@ -42,7 +45,7 @@
 
  private:
   void WriteNinjaRules();
-  void WriteLinkPool();
+  void WriteAllPools();
   void WriteSubninjas();
   bool WritePhonyAndAllRules(Err* err);
 
@@ -52,6 +55,7 @@
   std::vector<const Settings*> all_settings_;
   const Toolchain* default_toolchain_;
   std::vector<const Target*> default_toolchain_targets_;
+  std::vector<const Pool*> all_pools_;
   std::ostream& out_;
   std::ostream& dep_out_;
   PathOutput path_output_;
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc
index 48d7302..955eb1c 100644
--- a/tools/gn/ninja_build_writer_unittest.cc
+++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/ninja_build_writer.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/target.h"
 #include "tools/gn/test_with_scope.h"
@@ -31,12 +32,19 @@
   target_bar.SetToolchain(setup.toolchain());
   ASSERT_TRUE(target_bar.OnResolved(&err));
 
+  Pool swiming_pool(setup.settings(),
+                    Label(SourceDir("//swiming/"), "pool",
+                          SourceDir("//other/"), "toolchain"));
+  swiming_pool.set_depth(42);
+
   std::ostringstream ninja_out;
   std::ostringstream depfile_out;
   std::vector<const Settings*> all_settings = {setup.settings()};
   std::vector<const Target*> targets = {&target_foo, &target_bar};
+  std::vector<const Pool*> all_pools = {&swiming_pool};
   NinjaBuildWriter writer(setup.build_settings(), all_settings,
-                          setup.toolchain(), targets, ninja_out, depfile_out);
+                          setup.toolchain(), targets, all_pools, ninja_out,
+                          depfile_out);
   ASSERT_TRUE(writer.Run(&err));
 
   const char expected_rule_gn[] = "rule gn\n";
@@ -48,6 +56,9 @@
   const char expected_link_pool[] =
       "pool link_pool\n"
       "  depth = 0\n"
+      "\n"
+      "pool other_toolchain_swiming_pool\n"
+      "  depth = 42\n"
       "\n";
   const char expected_toolchain[] =
       "subninja toolchain.ninja\n"
@@ -102,8 +113,10 @@
   std::ostringstream depfile_out;
   std::vector<const Settings*> all_settings = { setup.settings() };
   std::vector<const Target*> targets = { &target_foo, &target_bar };
+  std::vector<const Pool*> all_pools;
   NinjaBuildWriter writer(setup.build_settings(), all_settings,
-                          setup.toolchain(), targets, ninja_out, depfile_out);
+                          setup.toolchain(), targets, all_pools, ninja_out,
+                          depfile_out);
   ASSERT_FALSE(writer.Run(&err));
 
   const char expected_help_test[] =
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc
index e7459eb..1deff58 100644
--- a/tools/gn/ninja_toolchain_writer.cc
+++ b/tools/gn/ninja_toolchain_writer.cc
@@ -11,6 +11,7 @@
 #include "tools/gn/build_settings.h"
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/ninja_utils.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/substitution_writer.h"
 #include "tools/gn/target.h"
@@ -113,6 +114,10 @@
       type == Toolchain::TYPE_SOLINK_MODULE ||
       type == Toolchain::TYPE_LINK) {
     out_ << kIndent << "pool = link_pool\n";
+  } else if (tool->pool().ptr) {
+    std::string pool_name =
+        tool->pool().ptr->GetNinjaName(settings_->default_toolchain_label());
+    out_ << kIndent << "pool = " << pool_name << std::endl;
   }
 
   if (tool->restat())
diff --git a/tools/gn/ninja_writer.cc b/tools/gn/ninja_writer.cc
index 154f017..7d26f48 100644
--- a/tools/gn/ninja_writer.cc
+++ b/tools/gn/ninja_writer.cc
@@ -29,9 +29,11 @@
 
   std::vector<const Settings*> all_settings;
   std::vector<const Target*> default_targets;
-  if (!writer.WriteToolchains(&all_settings, &default_targets, err))
+  std::vector<const Pool*> all_pools;
+  if (!writer.WriteToolchains(&all_settings, &default_targets, &all_pools, err))
     return false;
-  return writer.WriteRootBuildfiles(all_settings, default_targets, err);
+  return writer.WriteRootBuildfiles(all_settings, default_targets, all_pools,
+                                    err);
 }
 
 // static
@@ -42,11 +44,14 @@
     Err* err) {
   NinjaWriter writer(build_settings, builder);
   std::vector<const Target*> default_targets;
-  return writer.WriteToolchains(all_settings, &default_targets, err);
+  std::vector<const Pool*> all_pools;
+  return writer.WriteToolchains(all_settings, &default_targets, &all_pools,
+                                err);
 }
 
 bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
                                   std::vector<const Target*>* default_targets,
+                                  std::vector<const Pool*>* all_pools,
                                   Err* err) {
   // Categorize all targets by toolchain.
   typedef std::map<Label, std::vector<const Target*> > CategorizedMap;
@@ -79,6 +84,7 @@
 
   // Write out the toolchain buildfiles, and also accumulate the set of
   // all settings and find the list of targets in the default toolchain.
+  UniqueVector<const Pool*> pools;
   for (const auto& i : categorized) {
     const Settings* settings =
         builder_->loader()->GetToolchainSettings(i.first);
@@ -91,8 +97,16 @@
           "Couldn't open toolchain buildfile(s) for writing").PrintToStdout();
       return false;
     }
+
+    for (int j = Toolchain::TYPE_NONE + 1; j < Toolchain::TYPE_NUMTYPES; j++) {
+      Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(j);
+      const Tool* tool = toolchain->GetTool(tool_type);
+      if (tool && tool->pool().ptr)
+        pools.push_back(tool->pool().ptr);
+    }
   }
 
+  *all_pools = pools.vector();
   *default_targets = categorized[default_label];
   return true;
 }
@@ -100,6 +114,7 @@
 bool NinjaWriter::WriteRootBuildfiles(
     const std::vector<const Settings*>& all_settings,
     const std::vector<const Target*>& default_targets,
+    const std::vector<const Pool*>& all_pools,
     Err* err) {
   // All Settings objects should have the same default toolchain, and there
   // should always be at least one settings object in the build.
@@ -110,5 +125,5 @@
   // Write the root buildfile.
   return NinjaBuildWriter::RunAndWriteFile(build_settings_, all_settings,
                                            default_toolchain, default_targets,
-                                           err);
+                                           all_pools, err);
 }
diff --git a/tools/gn/ninja_writer.h b/tools/gn/ninja_writer.h
index fa4a433..ea8fc47 100644
--- a/tools/gn/ninja_writer.h
+++ b/tools/gn/ninja_writer.h
@@ -14,6 +14,7 @@
 class Builder;
 class BuildSettings;
 class Err;
+class Pool;
 class Settings;
 class Target;
 
@@ -36,12 +37,13 @@
   NinjaWriter(const BuildSettings* build_settings, Builder* builder);
   ~NinjaWriter();
 
-  bool WriteToolchains(
-      std::vector<const Settings*>* all_settings,
-      std::vector<const Target*>* default_targets,
-      Err* err);
+  bool WriteToolchains(std::vector<const Settings*>* all_settings,
+                       std::vector<const Target*>* default_targets,
+                       std::vector<const Pool*>* all_pools,
+                       Err* err);
   bool WriteRootBuildfiles(const std::vector<const Settings*>& all_settings,
                            const std::vector<const Target*>& default_targets,
+                           const std::vector<const Pool*>& all_pools,
                            Err* err);
 
   const BuildSettings* build_settings_;
diff --git a/tools/gn/pool.cc b/tools/gn/pool.cc
new file mode 100644
index 0000000..e4fc206
--- /dev/null
+++ b/tools/gn/pool.cc
@@ -0,0 +1,48 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/pool.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+
+Pool::Pool(const Settings* settings, const Label& label)
+    : Item(settings, label) {}
+
+Pool::~Pool() {}
+
+Pool* Pool::AsPool() {
+  return this;
+}
+
+const Pool* Pool::AsPool() const {
+  return this;
+}
+
+std::string Pool::GetNinjaName(const Label& default_toolchain) const {
+  bool include_toolchain = label().toolchain_dir() != default_toolchain.dir() ||
+                           label().toolchain_name() != default_toolchain.name();
+  return GetNinjaName(include_toolchain);
+}
+
+std::string Pool::GetNinjaName(bool include_toolchain) const {
+  std::ostringstream buffer;
+  if (include_toolchain) {
+    DCHECK(label().toolchain_dir().is_source_absolute());
+    std::string toolchain_dir = label().toolchain_dir().value();
+    for (std::string::size_type i = 2; i < toolchain_dir.size(); ++i) {
+      buffer << (toolchain_dir[i] == '/' ? '_' : toolchain_dir[i]);
+    }
+    buffer << label().toolchain_name() << "_";
+  }
+
+  DCHECK(label().dir().is_source_absolute());
+  std::string label_dir = label().dir().value();
+  for (std::string::size_type i = 2; i < label_dir.size(); ++i) {
+    buffer << (label_dir[i] == '/' ? '_' : label_dir[i]);
+  }
+  buffer << label().name();
+  return buffer.str();
+}
diff --git a/tools/gn/pool.h b/tools/gn/pool.h
new file mode 100644
index 0000000..d719364
--- /dev/null
+++ b/tools/gn/pool.h
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_POOL_H_
+#define TOOLS_GN_POOL_H_
+
+#include <string>
+
+#include "tools/gn/item.h"
+
+// Represents a named pool in the dependency graph.
+//
+// A pool is used to limit the parallelism of task invocation in the
+// generated ninja build. Pools are referenced by toolchains.
+class Pool : public Item {
+ public:
+  Pool(const Settings* settings, const Label& label);
+  ~Pool() override;
+
+  Pool(const Pool&) = delete;
+  Pool& operator=(const Pool&) = delete;
+
+  // Item implementation.
+  Pool* AsPool() override;
+  const Pool* AsPool() const override;
+
+  // The pool depth (number of task to run simultaneously).
+  int64_t depth() const { return depth_; }
+  void set_depth(int64_t depth) { depth_ = depth; }
+
+  // The pool name in generated ninja files.
+  std::string GetNinjaName(const Label& default_toolchain) const;
+
+ private:
+  std::string GetNinjaName(bool include_toolchain) const;
+
+  int64_t depth_ = 0;
+};
+
+#endif  // TOOLS_GN_POOL_H_
diff --git a/tools/gn/tool.h b/tools/gn/tool.h
index f6727ed..96ff7c0 100644
--- a/tools/gn/tool.h
+++ b/tools/gn/tool.h
@@ -9,9 +9,13 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include "tools/gn/label.h"
+#include "tools/gn/label_ptr.h"
 #include "tools/gn/substitution_list.h"
 #include "tools/gn/substitution_pattern.h"
 
+class Pool;
+
 class Tool {
  public:
   enum DepsFormat {
@@ -173,6 +177,9 @@
     rspfile_content_ = content;
   }
 
+  const LabelPtrPair<Pool>& pool() const { return pool_; }
+  void set_pool(const LabelPtrPair<Pool>& pool) { pool_ = pool; }
+
   // Other functions ----------------------------------------------------------
 
   // Called when the toolchain is saving this tool, after everything is filled
@@ -191,6 +198,8 @@
     return substitution_bits_;
   }
 
+  bool OnResolved(Err* err);
+
  private:
   SubstitutionPattern command_;
   std::string default_output_extension_;
@@ -209,6 +218,7 @@
   bool restat_;
   SubstitutionPattern rspfile_;
   SubstitutionPattern rspfile_content_;
+  LabelPtrPair<Pool> pool_;
 
   bool complete_;
 
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index 14d2bfd..03c9c59 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -86,6 +86,11 @@
   }
 }
 
+Tool* Toolchain::GetTool(ToolType type) {
+  DCHECK(type != TYPE_NONE);
+  return tools_[static_cast<size_t>(type)].get();
+}
+
 const Tool* Toolchain::GetTool(ToolType type) const {
   DCHECK(type != TYPE_NONE);
   return tools_[static_cast<size_t>(type)].get();
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index 0c20726..76858de 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -78,6 +78,7 @@
   static std::string ToolTypeToName(ToolType type);
 
   // Returns null if the tool hasn't been defined.
+  Tool* GetTool(ToolType type);
   const Tool* GetTool(ToolType type) const;
 
   // Set a tool. When all tools are configured, you should call