[flutter_runner] Increase thread stack sizes

Change-Id: I9cfb185f5610f90b1ba6f4c492866640ca633679
diff --git a/runtime/flutter_runner/BUILD.gn b/runtime/flutter_runner/BUILD.gn
index 7db8736..ea54651 100644
--- a/runtime/flutter_runner/BUILD.gn
+++ b/runtime/flutter_runner/BUILD.gn
@@ -98,6 +98,8 @@
       "task_observers.h",
       "task_runner_adapter.cc",
       "task_runner_adapter.h",
+      "thread.cc",
+      "thread.h",
       "unique_fdio_ns.h",
       "vsync_recorder.cc",
       "vsync_recorder.h",
diff --git a/runtime/flutter_runner/engine.cc b/runtime/flutter_runner/engine.cc
index b7a27a3..fb3cde2 100644
--- a/runtime/flutter_runner/engine.cc
+++ b/runtime/flutter_runner/engine.cc
@@ -17,9 +17,9 @@
 #include "topaz/runtime/dart/utils/files.h"
 
 #include "fuchsia_font_manager.h"
-#include "loop.h"
 #include "platform_view.h"
 #include "task_runner_adapter.h"
+#include "thread.h"
 
 namespace flutter_runner {
 
@@ -58,9 +58,8 @@
 
   // Launch the threads that will be used to run the shell. These threads will
   // be joined in the destructor.
-  for (auto& loop : host_loops_) {
-    loop.reset(MakeObservableLoop(false));
-    loop->StartThread();
+  for (auto& thread : threads_) {
+    thread.reset(new Thread());
   }
 
   // Set up the session connection.
@@ -183,9 +182,9 @@
   const flutter::TaskRunners task_runners(
       thread_label_,  // Dart thread labels
       CreateFMLTaskRunner(async_get_default_dispatcher()),  // platform
-      CreateFMLTaskRunner(host_loops_[0]->dispatcher()),    // gpu
-      CreateFMLTaskRunner(host_loops_[1]->dispatcher()),    // ui
-      CreateFMLTaskRunner(host_loops_[2]->dispatcher())     // io
+      CreateFMLTaskRunner(threads_[0]->dispatcher()),    // gpu
+      CreateFMLTaskRunner(threads_[1]->dispatcher()),    // ui
+      CreateFMLTaskRunner(threads_[2]->dispatcher())     // io
   );
 
   UpdateNativeThreadLabelNames(thread_label_, task_runners);
@@ -294,11 +293,11 @@
 
 Engine::~Engine() {
   shell_.reset();
-  for (const auto& loop : host_loops_) {
-    loop->Quit();
+  for (const auto& thread : threads_) {
+    thread->Quit();
   }
-  for (const auto& loop : host_loops_) {
-    loop->JoinThreads();
+  for (const auto& thread : threads_) {
+    thread->Join();
   }
 }
 
diff --git a/runtime/flutter_runner/engine.h b/runtime/flutter_runner/engine.h
index 0996401..b6cdc7f 100644
--- a/runtime/flutter_runner/engine.h
+++ b/runtime/flutter_runner/engine.h
@@ -15,6 +15,7 @@
 #include "flutter/fml/macros.h"
 #include "flutter/shell/common/shell.h"
 #include "isolate_configurator.h"
+#include "thread.h"
 
 namespace flutter_runner {
 
@@ -47,7 +48,7 @@
   Delegate& delegate_;
   const std::string thread_label_;
   flutter::Settings settings_;
-  std::array<std::unique_ptr<async::Loop>, 3> host_loops_;
+  std::array<std::unique_ptr<Thread>, 3> threads_;
   std::unique_ptr<IsolateConfigurator> isolate_configurator_;
   std::unique_ptr<flutter::Shell> shell_;
   zx::event vsync_event_;
diff --git a/runtime/flutter_runner/thread.cc b/runtime/flutter_runner/thread.cc
new file mode 100644
index 0000000..b3a88b9
--- /dev/null
+++ b/runtime/flutter_runner/thread.cc
@@ -0,0 +1,103 @@
+// Copyright 2017 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 "thread.h"
+
+#include <limits.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <lib/async-loop/cpp/loop.h>
+
+#include "flutter/fml/logging.h"
+#include "loop.h"
+
+namespace flutter_runner {
+
+typedef void (*ThreadEntry)(Thread*);
+
+namespace {
+
+size_t NextPageSizeMultiple(size_t size) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  FML_CHECK(page_size != 0);
+
+  size = std::max<size_t>(size, page_size);
+
+  size_t rem = size % page_size;
+
+  if (rem == 0) {
+    return size;
+  }
+
+  return size + page_size - rem;
+}
+
+bool CreateThread(pthread_t* thread,
+                  ThreadEntry main,
+                  Thread* argument,
+                  size_t stack_size) {
+  pthread_attr_t thread_attributes;
+
+  if (pthread_attr_init(&thread_attributes) != 0) {
+    return false;
+  }
+
+  stack_size = std::max<size_t>(NextPageSizeMultiple(PTHREAD_STACK_MIN),
+                                NextPageSizeMultiple(stack_size));
+
+  if (pthread_attr_setstacksize(&thread_attributes, stack_size) != 0) {
+    return false;
+  }
+
+  auto result =
+      pthread_create(thread, &thread_attributes,
+                     reinterpret_cast<void* (*)(void*)>(main), argument);
+
+  pthread_attr_destroy(&thread_attributes);
+
+  return result == 0;
+}
+
+}  // anonymous namespace
+
+Thread::Thread() {
+  loop_.reset(MakeObservableLoop(false));
+  valid_ = CreateThread(&thread_, [](Thread* thread) { thread->Main(); }, this,
+                        1 << 20);
+}
+
+Thread::~Thread() {
+  Join();
+}
+
+bool Thread::IsValid() const {
+  return valid_;
+}
+
+async_dispatcher_t* Thread::dispatcher() const {
+  return loop_->dispatcher();
+}
+
+void Thread::Main() {
+  async_set_default_dispatcher(loop_->dispatcher());
+  loop_->Run();
+}
+
+void Thread::Quit() {
+  loop_->Quit();
+}
+
+bool Thread::Join() {
+  if (!valid_) {
+    return false;
+  }
+
+  bool result = pthread_join(thread_, nullptr) == 0;
+  valid_ = false;
+  return result;
+}
+
+ }  // namespace flutter_runner
diff --git a/runtime/flutter_runner/thread.h b/runtime/flutter_runner/thread.h
new file mode 100644
index 0000000..c347102
--- /dev/null
+++ b/runtime/flutter_runner/thread.h
@@ -0,0 +1,44 @@
+// Copyright 2017 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 TOPAZ_RUNTIME_FLUTTER_RUNNER_THREAD_H_
+#define TOPAZ_RUNTIME_FLUTTER_RUNNER_THREAD_H_
+
+#include <pthread.h>
+
+#include <functional>
+
+#include <lib/async-loop/cpp/loop.h>
+
+#include "flutter/fml/macros.h"
+
+namespace flutter_runner {
+
+class Thread {
+ public:
+  Thread();
+
+  ~Thread();
+
+  void Quit();
+
+  bool Join();
+
+  bool IsValid() const;
+
+  async_dispatcher_t* dispatcher() const;
+
+ private:
+  bool valid_;
+  pthread_t thread_;
+  std::unique_ptr<async::Loop> loop_;
+
+  void Main();
+
+  FML_DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace flutter_runner
+
+ #endif  // TOPAZ_RUNTIME_FLUTTER_RUNNER_THREAD_H_