Mojo: AsyncWaiter and mojo/public/environment

Summary of changes:

 o BindingsSupport is gone:
   - mojo/public/bindings/lib depends on mojo/public/environment/,
     which is also a static library.
   - mojo/public/environment provides a default implementation of
     MojoAsyncWaiter (replacing the AsyncWait functionality of
     BindingsSupport).
   - mojo/public/environment provides TLS support for storing the
     current Buffer* (replacing the Set/GetCurrentBuffer functionality
     of BindingsSupport).
   - mojo/public/environment provides the Environment class, formerly
     part of mojo/public/utility/
   - The standalone implementation of mojo/public/environment/ depends
     on mojo/public/utility/ and assumes clients will be instantiating
     RunLoops on their threads.
   - The chromium-specific implementation of mojo/public/environment/
     depends on mojo/common/ and assumes clients will be instantiating
     MessageLoops on their threads.
   - The chromium-specific implementation of mojo/public/environment/
     is divided into two targets: mojo_environment_chromium and
     mojo_environment_chromium_impl. The former is a static library and
     the latter is a component. (This way all of the state--TLS keys--
     associated with the environment is kept in a DSO when using a
     component build.)

 o RemotePtr and Connector may optionally be parameterized with a
   MojoAsyncWaiter*, allowing users to customize how AsyncWait is
   implemented for a particular usage of bindings. This is needed by
   the GL library so that it can schedule work on an application
   defined run loop.

 o RunLoop gains a RunUntilIdle method to support tests. This allows us
   to delete SimpleBindingsSupport instead of converting it over to an
   implementation of MojoAsyncWaiter.

Review URL: https://codereview.chromium.org/134253004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244739 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/mojo/apps/js/bindings/support.cc b/mojo/apps/js/bindings/support.cc
index 65f6cae..bdb554b 100644
--- a/mojo/apps/js/bindings/support.cc
+++ b/mojo/apps/js/bindings/support.cc
@@ -14,7 +14,8 @@
 #include "gin/wrappable.h"
 #include "mojo/apps/js/bindings/handle.h"
 #include "mojo/apps/js/bindings/waiting_callback.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
+#include "mojo/public/environment/default_async_waiter.h"
+#include "mojo/public/system/core_cpp.h"
 
 namespace mojo {
 namespace js {
@@ -27,8 +28,14 @@
   gin::Handle<WaitingCallback> waiting_callback =
       WaitingCallback::Create(args.isolate(), callback);
 
-  BindingsSupport::AsyncWaitID wait_id = BindingsSupport::Get()->AsyncWait(
-      handle, flags, waiting_callback.get());
+  MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter();
+  MojoAsyncWaitID wait_id = waiter->AsyncWait(
+      waiter,
+      handle.value(),
+      flags,
+      MOJO_DEADLINE_INDEFINITE,
+      &WaitingCallback::CallOnHandleReady,
+      waiting_callback.get());
 
   waiting_callback->set_wait_id(wait_id);
 
@@ -38,8 +45,10 @@
 void CancelWait(WaitingCallback* waiting_callback) {
   if (!waiting_callback->wait_id())
     return;
-  BindingsSupport::Get()->CancelWait(waiting_callback->wait_id());
-  waiting_callback->set_wait_id(NULL);
+
+  MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter();
+  waiter->CancelWait(waiter, waiting_callback->wait_id());
+  waiting_callback->set_wait_id(0);
 }
 
 gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
diff --git a/mojo/apps/js/bindings/waiting_callback.cc b/mojo/apps/js/bindings/waiting_callback.cc
index 6769eb7e..87c28bf 100644
--- a/mojo/apps/js/bindings/waiting_callback.cc
+++ b/mojo/apps/js/bindings/waiting_callback.cc
@@ -36,8 +36,13 @@
   return gin::CreateHandle(isolate, new WaitingCallback(isolate, callback));
 }
 
+// static
+void WaitingCallback::CallOnHandleReady(void* closure, MojoResult result) {
+  static_cast<WaitingCallback*>(closure)->OnHandleReady(result);
+}
+
 void WaitingCallback::OnHandleReady(MojoResult result) {
-  wait_id_ = NULL;
+  wait_id_ = 0;
 
   if (!runner_)
     return;
diff --git a/mojo/apps/js/bindings/waiting_callback.h b/mojo/apps/js/bindings/waiting_callback.h
index 63b3dda..c841028 100644
--- a/mojo/apps/js/bindings/waiting_callback.h
+++ b/mojo/apps/js/bindings/waiting_callback.h
@@ -8,35 +8,37 @@
 #include "gin/handle.h"
 #include "gin/runner.h"
 #include "gin/wrappable.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
+#include "mojo/public/system/async_waiter.h"
 
 namespace mojo {
 namespace js {
 
-class WaitingCallback : public gin::Wrappable<WaitingCallback>,
-                        public BindingsSupport::AsyncWaitCallback {
+class WaitingCallback : public gin::Wrappable<WaitingCallback> {
  public:
   static gin::WrapperInfo kWrapperInfo;
 
   static gin::Handle<WaitingCallback> Create(
       v8::Isolate* isolate, v8::Handle<v8::Function> callback);
 
-  BindingsSupport::AsyncWaitID wait_id() const {
+  MojoAsyncWaitID wait_id() const {
     return wait_id_;
   }
 
-  void set_wait_id(BindingsSupport::AsyncWaitID wait_id) {
+  void set_wait_id(MojoAsyncWaitID wait_id) {
     wait_id_ = wait_id;
   }
 
+  // MojoAsyncWaitCallback
+  static void CallOnHandleReady(void* closure, MojoResult result);
+
  private:
   WaitingCallback(v8::Isolate* isolate, v8::Handle<v8::Function> callback);
   virtual ~WaitingCallback();
 
-  virtual void OnHandleReady(MojoResult result) OVERRIDE;
+  void OnHandleReady(MojoResult result);
 
   base::WeakPtr<gin::Runner> runner_;
-  BindingsSupport::AsyncWaitID wait_id_;
+  MojoAsyncWaitID wait_id_;
 
   DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
 };
diff --git a/mojo/apps/js/main.cc b/mojo/apps/js/main.cc
index 3ecca28..bfc6e2c 100644
--- a/mojo/apps/js/main.cc
+++ b/mojo/apps/js/main.cc
@@ -5,7 +5,6 @@
 #include "base/message_loop/message_loop.h"
 #include "gin/public/isolate_holder.h"
 #include "mojo/apps/js/mojo_runner_delegate.h"
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/public/gles2/gles2.h"
 #include "mojo/public/system/core_cpp.h"
 #include "mojo/public/system/macros.h"
@@ -38,13 +37,10 @@
 }  // namespace mojo
 
 extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) {
-  mojo::common::BindingsSupportImpl bindings_support;
-  mojo::BindingsSupport::Set(&bindings_support);
   MojoGLES2Initialize();
 
   mojo::apps::Start(pipe, "mojo/apps/js/main");
 
   MojoGLES2Terminate();
-  mojo::BindingsSupport::Set(NULL);
   return MOJO_RESULT_OK;
 }
diff --git a/mojo/common/bindings_support_impl.cc b/mojo/common/bindings_support_impl.cc
deleted file mode 100644
index 0e1f6a1..0000000
--- a/mojo/common/bindings_support_impl.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2013 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 "mojo/common/bindings_support_impl.h"
-
-#include "base/atomic_ref_count.h"
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/threading/thread_local.h"
-#include "mojo/common/handle_watcher.h"
-
-namespace mojo {
-namespace common {
-namespace {
-base::LazyInstance<base::ThreadLocalPointer<Buffer> >::Leaky lazy_tls_ptr =
-    LAZY_INSTANCE_INITIALIZER;
-}
-
-// Context is used to track the number of HandleWatcher objects in use by a
-// particular BindingsSupportImpl instance.
-class BindingsSupportImpl::Context
-    : public base::RefCountedThreadSafe<BindingsSupportImpl::Context> {
- public:
-  void CallOnHandleReady(HandleWatcher* watcher,
-                         AsyncWaitCallback* callback,
-                         MojoResult result) {
-    delete watcher;
-    callback->OnHandleReady(result);
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<Context>;
-  virtual ~Context() {}
-};
-
-BindingsSupportImpl::BindingsSupportImpl()
-    : context_(new Context()) {
-}
-
-BindingsSupportImpl::~BindingsSupportImpl() {
-  // All HandleWatcher instances created through this interface should have
-  // been destroyed.
-  DCHECK(context_->HasOneRef());
-}
-
-Buffer* BindingsSupportImpl::GetCurrentBuffer() {
-  return lazy_tls_ptr.Pointer()->Get();
-}
-
-Buffer* BindingsSupportImpl::SetCurrentBuffer(Buffer* buf) {
-  Buffer* old_buf = lazy_tls_ptr.Pointer()->Get();
-  lazy_tls_ptr.Pointer()->Set(buf);
-  return old_buf;
-}
-
-BindingsSupport::AsyncWaitID BindingsSupportImpl::AsyncWait(
-    const Handle& handle,
-    MojoWaitFlags flags,
-    AsyncWaitCallback* callback) {
-  // This instance will be deleted when done or cancelled.
-  HandleWatcher* watcher = new HandleWatcher();
-
-  watcher->Start(handle,
-                 flags,
-                 MOJO_DEADLINE_INDEFINITE,
-                 base::Bind(&Context::CallOnHandleReady,
-                            context_,
-                            watcher,
-                            callback));
-  return watcher;
-}
-
-void BindingsSupportImpl::CancelWait(AsyncWaitID async_wait_id) {
-  HandleWatcher* watcher = static_cast<HandleWatcher*>(async_wait_id);
-  delete watcher;
-}
-
-}  // namespace common
-}  // namespace mojo
diff --git a/mojo/common/bindings_support_impl.h b/mojo/common/bindings_support_impl.h
deleted file mode 100644
index 2f08ba07..0000000
--- a/mojo/common/bindings_support_impl.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 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 MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_
-#define MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_
-
-#include "mojo/public/bindings/lib/bindings_support.h"
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/common/mojo_common_export.h"
-
-namespace mojo {
-namespace common {
-
-class MOJO_COMMON_EXPORT BindingsSupportImpl
-    : NON_EXPORTED_BASE(public BindingsSupport) {
- public:
-  BindingsSupportImpl();
-  virtual ~BindingsSupportImpl();
-
-  // BindingsSupport methods:
-  virtual Buffer* GetCurrentBuffer() OVERRIDE;
-  virtual Buffer* SetCurrentBuffer(Buffer* buf) OVERRIDE;
-  virtual AsyncWaitID AsyncWait(const Handle& handle, MojoWaitFlags flags,
-                                AsyncWaitCallback* callback) OVERRIDE;
-  virtual void CancelWait(AsyncWaitID async_wait_id) OVERRIDE;
-
- private:
-  class Context;
-  scoped_refptr<Context> context_;
-
-  DISALLOW_COPY_AND_ASSIGN(BindingsSupportImpl);
-};
-
-}  // namespace common
-}  // namespace mojo
-
-#endif  // MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_
diff --git a/mojo/common/common_type_converters_unittest.cc b/mojo/common/common_type_converters_unittest.cc
index 90649fd..39e770a 100644
--- a/mojo/common/common_type_converters_unittest.cc
+++ b/mojo/common/common_type_converters_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/common/common_type_converters.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -23,20 +22,7 @@
 
 }  // namespace
 
-class CommonTypeConvertersTest : public testing::Test {
- private:
-  virtual void SetUp() OVERRIDE {
-    BindingsSupport::Set(&bindings_support_);
-  }
-
-  virtual void TearDown() OVERRIDE {
-    BindingsSupport::Set(NULL);
-  }
-
-  BindingsSupportImpl bindings_support_;
-};
-
-TEST_F(CommonTypeConvertersTest, StringPiece) {
+TEST(CommonTypeConvertersTest, StringPiece) {
   AllocationScope scope;
 
   std::string kText("hello world");
diff --git a/mojo/environment/async_waiter_impl.cc b/mojo/environment/async_waiter_impl.cc
new file mode 100644
index 0000000..ab0599a9
--- /dev/null
+++ b/mojo/environment/async_waiter_impl.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 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 "mojo/environment/async_waiter_impl.h"
+
+#include "base/bind.h"
+#include "mojo/common/handle_watcher.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+void OnHandleReady(common::HandleWatcher* watcher,
+                   MojoAsyncWaitCallback callback,
+                   uintptr_t user_data,
+                   MojoResult result) {
+  delete watcher;
+  callback(user_data, result);
+}
+
+MojoAsyncWaitID AsyncWait(MojoAsyncWaiter* waiter,
+                          MojoHandle handle,
+                          MojoWaitFlags flags,
+                          MojoDeadline deadline,
+                          MojoAsyncWaitCallback callback,
+                          uintptr_t user_data) {
+  // This instance will be deleted when done or cancelled.
+  common::HandleWatcher* watcher = new common::HandleWatcher();
+  watcher->Start(Handle(handle), flags, deadline,
+                 base::Bind(&OnHandleReady, watcher, callback, user_data));
+  return reinterpret_cast<MojoAsyncWaitID>(watcher);
+}
+
+void CancelWait(MojoAsyncWaiter* waiter, MojoAsyncWaitID wait_id) {
+  delete reinterpret_cast<common::HandleWatcher*>(wait_id);
+}
+
+MojoAsyncWaiter s_default_async_waiter = {
+  AsyncWait,
+  CancelWait
+};
+
+}  // namespace
+
+MojoAsyncWaiter* GetDefaultAsyncWaiterImpl() {
+  return &s_default_async_waiter;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/environment/async_waiter_impl.h b/mojo/environment/async_waiter_impl.h
new file mode 100644
index 0000000..686d3ce
--- /dev/null
+++ b/mojo/environment/async_waiter_impl.h
@@ -0,0 +1,19 @@
+// Copyright 2014 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 MOJO_ENVIRONMENT_ASYNC_WAITER_IMPL_H_
+#define MOJO_ENVIRONMENT_ASYNC_WAITER_IMPL_H_
+
+#include "mojo/public/environment/async_waiter.h"
+#include "mojo/environment/mojo_environment_impl_export.h"
+
+namespace mojo {
+namespace internal {
+
+MOJO_ENVIRONMENT_IMPL_EXPORT MojoAsyncWaiter* GetDefaultAsyncWaiterImpl();
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_ENVIRONMENT_ASYNC_WAITER_IMPL_H_
diff --git a/mojo/environment/buffer_tls.cc b/mojo/environment/buffer_tls.cc
new file mode 100644
index 0000000..4d078ef24
--- /dev/null
+++ b/mojo/environment/buffer_tls.cc
@@ -0,0 +1,21 @@
+// Copyright 2014 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 "mojo/public/environment/buffer_tls.h"
+
+#include "mojo/environment/buffer_tls_impl.h"
+
+namespace mojo {
+namespace internal {
+
+Buffer* GetCurrentBuffer() {
+  return GetCurrentBufferImpl();
+}
+
+Buffer* SetCurrentBuffer(Buffer* buf) {
+  return SetCurrentBufferImpl(buf);
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/environment/buffer_tls_impl.cc b/mojo/environment/buffer_tls_impl.cc
new file mode 100644
index 0000000..f196cb1
--- /dev/null
+++ b/mojo/environment/buffer_tls_impl.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 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 "mojo/environment/buffer_tls_impl.h"
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<Buffer> >::Leaky lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+Buffer* GetCurrentBufferImpl() {
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+Buffer* SetCurrentBufferImpl(Buffer* buf) {
+  Buffer* old_buf = lazy_tls_ptr.Pointer()->Get();
+  lazy_tls_ptr.Pointer()->Set(buf);
+  return old_buf;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/environment/buffer_tls_impl.h b/mojo/environment/buffer_tls_impl.h
new file mode 100644
index 0000000..3d24196
--- /dev/null
+++ b/mojo/environment/buffer_tls_impl.h
@@ -0,0 +1,21 @@
+// Copyright 2014 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 MOJO_ENVIRONMENT_BUFFER_TLS_IMPL_H_
+#define MOJO_ENVIRONMENT_BUFFER_TLS_IMPL_H_
+
+#include "mojo/environment/mojo_environment_impl_export.h"
+
+namespace mojo {
+class Buffer;
+
+namespace internal {
+
+MOJO_ENVIRONMENT_IMPL_EXPORT Buffer* GetCurrentBufferImpl();
+MOJO_ENVIRONMENT_IMPL_EXPORT Buffer* SetCurrentBufferImpl(Buffer* buffer);
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_ENVIRONMENT_BUFFER_TLS_IMPL_H_
diff --git a/mojo/environment/default_async_waiter.cc b/mojo/environment/default_async_waiter.cc
new file mode 100644
index 0000000..7a46c07
--- /dev/null
+++ b/mojo/environment/default_async_waiter.cc
@@ -0,0 +1,15 @@
+// Copyright 2014 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 "mojo/public/environment/default_async_waiter.h"
+
+#include "mojo/environment/default_async_waiter_impl.h"
+
+namespace mojo {
+
+MojoAsyncWaiter* GetDefaultAsyncWaiter() {
+  return internal::GetDefaultAsyncWaiterImpl();
+}
+
+}  // namespace mojo
diff --git a/mojo/environment/default_async_waiter_impl.cc b/mojo/environment/default_async_waiter_impl.cc
new file mode 100644
index 0000000..576dd98
--- /dev/null
+++ b/mojo/environment/default_async_waiter_impl.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 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 "mojo/environment/default_async_waiter_impl.h"
+
+#include "base/bind.h"
+#include "mojo/common/handle_watcher.h"
+
+namespace mojo {
+namespace internal {
+namespace {
+
+void OnHandleReady(common::HandleWatcher* watcher,
+                   MojoAsyncWaitCallback callback,
+                   void* closure,
+                   MojoResult result) {
+  delete watcher;
+  callback(closure, result);
+}
+
+MojoAsyncWaitID AsyncWait(MojoAsyncWaiter* waiter,
+                          MojoHandle handle,
+                          MojoWaitFlags flags,
+                          MojoDeadline deadline,
+                          MojoAsyncWaitCallback callback,
+                          void* closure) {
+  // This instance will be deleted when done or cancelled.
+  common::HandleWatcher* watcher = new common::HandleWatcher();
+  watcher->Start(Handle(handle), flags, deadline,
+                 base::Bind(&OnHandleReady, watcher, callback, closure));
+  return reinterpret_cast<MojoAsyncWaitID>(watcher);
+}
+
+void CancelWait(MojoAsyncWaiter* waiter, MojoAsyncWaitID wait_id) {
+  delete reinterpret_cast<common::HandleWatcher*>(wait_id);
+}
+
+MojoAsyncWaiter s_default_async_waiter = {
+  AsyncWait,
+  CancelWait
+};
+
+}  // namespace
+
+MojoAsyncWaiter* GetDefaultAsyncWaiterImpl() {
+  return &s_default_async_waiter;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/environment/default_async_waiter_impl.h b/mojo/environment/default_async_waiter_impl.h
new file mode 100644
index 0000000..cf2f7c2
--- /dev/null
+++ b/mojo/environment/default_async_waiter_impl.h
@@ -0,0 +1,19 @@
+// Copyright 2014 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 MOJO_ENVIRONMENT_DEFAULT_ASYNC_WAITER_IMPL_H_
+#define MOJO_ENVIRONMENT_DEFAULT_ASYNC_WAITER_IMPL_H_
+
+#include "mojo/environment/mojo_environment_impl_export.h"
+#include "mojo/public/system/async_waiter.h"
+
+namespace mojo {
+namespace internal {
+
+MOJO_ENVIRONMENT_IMPL_EXPORT MojoAsyncWaiter* GetDefaultAsyncWaiterImpl();
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_ENVIRONMENT_DEFAULT_ASYNC_WAITER_IMPL_H_
diff --git a/mojo/environment/environment.cc b/mojo/environment/environment.cc
new file mode 100644
index 0000000..c65908c
--- /dev/null
+++ b/mojo/environment/environment.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 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 "mojo/public/environment/environment.h"
+
+namespace mojo {
+
+// These methods do nothing as we rely on LazyInstance<T> to instantiate all of
+// our global state in this implementation of the environment library.
+
+Environment::Environment() {
+  // no-op
+}
+
+Environment::~Environment() {
+  // no-op
+}
+
+}  // namespace mojo
diff --git a/mojo/environment/mojo_environment_impl_export.h b/mojo/environment/mojo_environment_impl_export.h
new file mode 100644
index 0000000..0255425
--- /dev/null
+++ b/mojo/environment/mojo_environment_impl_export.h
@@ -0,0 +1,32 @@
+// Copyright 2014 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 MOJO_ENVIRONMENT_MOJO_ENVIRONMENT_IMPL_EXPORT_H_
+#define MOJO_ENVIRONMENT_MOJO_ENVIRONMENT_IMPL_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(WIN32)
+
+#if defined(MOJO_ENVIRONMENT_IMPL_IMPLEMENTATION)
+#define MOJO_ENVIRONMENT_IMPL_EXPORT __declspec(dllexport)
+#else
+#define MOJO_ENVIRONMENT_IMPL_EXPORT __declspec(dllimport)
+#endif
+
+#else  // !defined(WIN32)
+
+#if defined(MOJO_ENVIRONMENT_IMPL_IMPLEMENTATION)
+#define MOJO_ENVIRONMENT_IMPL_EXPORT __attribute__((visibility("default")))
+#else
+#define MOJO_ENVIRONMENT_IMPL_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+
+#else  // !defined(COMPONENT_BUILD)
+#define MOJO_ENVIRONMENT_IMPL_EXPORT
+#endif
+
+#endif  // MOJO_ENVIRONMENT_MOJO_ENVIRONMENT_IMPL_EXPORT_H_
diff --git a/mojo/examples/aura_demo/aura_demo.cc b/mojo/examples/aura_demo/aura_demo.cc
index 70da6f9..64fe621 100644
--- a/mojo/examples/aura_demo/aura_demo.cc
+++ b/mojo/examples/aura_demo/aura_demo.cc
@@ -8,12 +8,10 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/examples/aura_demo/demo_screen.h"
 #include "mojo/examples/aura_demo/root_window_host_mojo.h"
 #include "mojo/examples/compositor_app/compositor_host.h"
 #include "mojo/examples/compositor_app/gles2_client_impl.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
 #include "mojo/public/bindings/lib/remote_ptr.h"
 #include "mojo/public/gles2/gles2.h"
 #include "mojo/public/system/core.h"
@@ -197,8 +195,6 @@
   CommandLine::Init(0, NULL);
   base::AtExitManager at_exit;
   base::MessageLoop loop;
-  mojo::common::BindingsSupportImpl bindings_support_impl;
-  mojo::BindingsSupport::Set(&bindings_support_impl);
   MojoGLES2Initialize();
 
   // TODO(beng): This crashes in a DCHECK on X11 because this thread's
@@ -210,6 +206,5 @@
   loop.Run();
 
   MojoGLES2Terminate();
-  mojo::BindingsSupport::Set(NULL);
   return MOJO_RESULT_OK;
 }
diff --git a/mojo/examples/compositor_app/compositor_app.cc b/mojo/examples/compositor_app/compositor_app.cc
index 2865fb99..d2547fd 100644
--- a/mojo/examples/compositor_app/compositor_app.cc
+++ b/mojo/examples/compositor_app/compositor_app.cc
@@ -6,10 +6,8 @@
 #include <string>
 
 #include "base/message_loop/message_loop.h"
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/examples/compositor_app/compositor_host.h"
 #include "mojo/examples/compositor_app/gles2_client_impl.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
 #include "mojo/public/bindings/lib/remote_ptr.h"
 #include "mojo/public/gles2/gles2.h"
 #include "mojo/public/system/core.h"
@@ -98,8 +96,6 @@
 extern "C" SAMPLE_APP_EXPORT MojoResult CDECL MojoMain(
     MojoHandle shell_handle) {
   base::MessageLoop loop;
-  mojo::common::BindingsSupportImpl bindings_support_impl;
-  mojo::BindingsSupport::Set(&bindings_support_impl);
   MojoGLES2Initialize();
 
   mojo::examples::SampleApp app(
@@ -107,6 +103,5 @@
   loop.Run();
 
   MojoGLES2Terminate();
-  mojo::BindingsSupport::Set(NULL);
   return MOJO_RESULT_OK;
 }
diff --git a/mojo/examples/sample_app/sample_app.cc b/mojo/examples/sample_app/sample_app.cc
index c9183f2..8b3d763 100644
--- a/mojo/examples/sample_app/sample_app.cc
+++ b/mojo/examples/sample_app/sample_app.cc
@@ -6,12 +6,11 @@
 #include <string>
 
 #include "mojo/examples/sample_app/gles2_client_impl.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
 #include "mojo/public/bindings/lib/remote_ptr.h"
+#include "mojo/public/environment/environment.h"
 #include "mojo/public/gles2/gles2.h"
 #include "mojo/public/system/core.h"
 #include "mojo/public/system/macros.h"
-#include "mojo/public/utility/environment.h"
 #include "mojo/public/utility/run_loop.h"
 #include "mojom/native_viewport.h"
 #include "mojom/shell.h"
@@ -94,6 +93,5 @@
   loop.Run();
 
   MojoGLES2Terminate();
-  mojo::BindingsSupport::Set(NULL);
   return MOJO_RESULT_OK;
 }
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index 1b06f5f9..415ab6689 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -35,6 +35,7 @@
         'mojo_js_unittests',
         'mojo_public_test_support',
         'mojo_public_bindings_unittests',
+        'mojo_public_environment_unittests',
         'mojo_public_system_perftests',
         'mojo_public_system_unittests',
         'mojo_public_utility_unittests',
@@ -197,8 +198,6 @@
         'mojo_system',
       ],
       'sources': [
-        'common/bindings_support_impl.cc',
-        'common/bindings_support_impl.h',
         'common/common_type_converters.cc',
         'common/common_type_converters.h',
         'common/handle_watcher.cc',
@@ -239,6 +238,7 @@
         '../base/base.gyp:base_message_loop_tests',
         '../testing/gtest.gyp:gtest',
         'mojo_bindings',
+        'mojo_environment_chromium',
         'mojo_common_lib',
         'mojo_common_test_support',
         'mojo_public_test_support',
@@ -262,6 +262,45 @@
       ],
     },
     {
+      'target_name': 'mojo_environment_chromium',
+      'type': 'static_library',
+      'dependencies': [
+        'mojo_environment_chromium_impl',
+      ],
+      'sources': [
+        'environment/default_async_waiter.cc',
+        'environment/buffer_tls.cc',
+        'environment/environment.cc',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'export_dependent_settings': [
+        'mojo_environment_chromium_impl',
+      ],
+    },
+    {
+      'target_name': 'mojo_environment_chromium_impl',
+      'type': '<(component)',
+      'defines': [
+        'MOJO_ENVIRONMENT_IMPL_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        'mojo_common_lib'
+      ],
+      'sources': [
+        'environment/default_async_waiter_impl.cc',
+        'environment/default_async_waiter_impl.h',
+        'environment/buffer_tls_impl.cc',
+        'environment/buffer_tls_impl.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
       'target_name': 'mojo_shell_lib',
       'type': 'static_library',
       'dependencies': [
@@ -326,6 +365,7 @@
         '../ui/gl/gl.gyp:gl',
         '../url/url.gyp:url_lib',
         'mojo_common_lib',
+        'mojo_environment_chromium',
         'mojo_shell_lib',
         'mojo_system',
         'mojo_system_impl',
@@ -349,6 +389,7 @@
         '../base/base.gyp:base',
         '../testing/gtest.gyp:gtest',
         'mojo_common_lib',
+        'mojo_environment_chromium',
         'mojo_run_all_unittests',
         'mojo_shell_lib',
       ],
@@ -409,6 +450,7 @@
             '../ui/gfx/gfx.gyp:gfx_geometry',
             '../ui/gl/gl.gyp:gl',
             'mojo_common_lib',
+            'mojo_environment_chromium',
             'mojo_jni_headers',
             'mojo_shell_bindings',
             'mojo_shell_lib',
diff --git a/mojo/mojo_apps.gypi b/mojo/mojo_apps.gypi
index f53960c..17c8b93 100644
--- a/mojo/mojo_apps.gypi
+++ b/mojo/mojo_apps.gypi
@@ -10,6 +10,7 @@
         '../ui/gl/gl.gyp:gl',
         '../v8/tools/gyp/v8.gyp:v8',
         'mojo_common_lib',
+        'mojo_environment_chromium',
         'mojo_gles2',
         'mojo_gles2_bindings',
         'mojo_native_viewport_bindings',
diff --git a/mojo/mojo_examples.gypi b/mojo/mojo_examples.gypi
index 48bd657e..de0e1e3 100644
--- a/mojo/mojo_examples.gypi
+++ b/mojo/mojo_examples.gypi
@@ -12,6 +12,7 @@
         '../ui/gfx/gfx.gyp:gfx',
         '../ui/gfx/gfx.gyp:gfx_geometry',
         '../ui/gl/gl.gyp:gl',
+        'mojo_environment_chromium',
         'mojo_gles2',
         'mojo_gles2_bindings',
         'mojo_native_viewport_bindings',
@@ -47,6 +48,7 @@
         '../ui/gfx/gfx.gyp:gfx_geometry',
         '../ui/gl/gl.gyp:gl',
         'mojo_common_lib',
+        'mojo_environment_chromium',
         'mojo_gles2',
         'mojo_gles2_bindings',
         'mojo_native_viewport_bindings',
@@ -91,6 +93,7 @@
             '../ui/ui.gyp:ui',
             '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
             'mojo_common_lib',
+            'mojo_environment_chromium',
             'mojo_gles2',
             'mojo_gles2_bindings',
             'mojo_native_viewport_bindings',
diff --git a/mojo/mojo_public.gypi b/mojo/mojo_public.gypi
index 488f373..88302e4 100644
--- a/mojo/mojo_public.gypi
+++ b/mojo/mojo_public.gypi
@@ -15,6 +15,7 @@
         ],
       },
       'sources': [
+        'public/system/async_waiter.h',
         'public/system/core.h',
         'public/system/core_cpp.h',
         'public/system/core_private.cc',
@@ -42,10 +43,12 @@
       'dependencies': [
         '../testing/gtest.gyp:gtest',
         'mojo_bindings',
+        'mojo_environment_standalone',
         'mojo_public_test_support',
         'mojo_run_all_unittests',
         'mojo_sample_service',
         'mojo_system',
+        'mojo_utility',
       ],
       'sources': [
         'public/tests/bindings/array_unittest.cc',
@@ -57,13 +60,27 @@
         'public/tests/bindings/math_calculator.mojom',
         'public/tests/bindings/sample_factory.mojom',
         'public/tests/bindings/sample_service_unittests.cc',
-        'public/tests/bindings/simple_bindings_support.cc',
-        'public/tests/bindings/simple_bindings_support.h',
         'public/tests/bindings/test_structs.mojom',
       ],
       'includes': [ 'public/bindings/mojom_bindings_generator.gypi' ],
     },
     {
+      'target_name': 'mojo_public_environment_unittests',
+      'type': 'executable',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../testing/gtest.gyp:gtest',
+        'mojo_environment_standalone',
+        'mojo_public_test_support',
+        'mojo_run_all_unittests',
+        'mojo_system',
+        'mojo_utility',
+      ],
+      'sources': [
+        'public/tests/environment/async_waiter_unittest.cc',
+      ],
+    },
+    {
       'target_name': 'mojo_public_system_unittests',
       'type': 'executable',
       'dependencies': [
@@ -92,7 +109,6 @@
         'mojo_utility',
       ],
       'sources': [
-        'public/tests/utility/bindings_support_impl_unittest.cc',
         'public/tests/utility/run_loop_unittest.cc',
         'public/tests/utility/thread_local_unittest.cc',
       ],
@@ -126,8 +142,6 @@
         'public/bindings/lib/bindings_internal.h',
         'public/bindings/lib/bindings_serialization.cc',
         'public/bindings/lib/bindings_serialization.h',
-        'public/bindings/lib/bindings_support.cc',
-        'public/bindings/lib/bindings_support.h',
         'public/bindings/lib/buffer.cc',
         'public/bindings/lib/buffer.h',
         'public/bindings/lib/connector.cc',
@@ -153,13 +167,25 @@
       ],
     },
     {
+      'target_name': 'mojo_environment_standalone',
+      'type': 'static_library',
+      'sources': [
+        'public/environment/default_async_waiter.h',
+        'public/environment/buffer_tls.h',
+        'public/environment/environment.h',
+        'public/environment/standalone/default_async_waiter.cc',
+        'public/environment/standalone/buffer_tls.cc',
+        'public/environment/standalone/buffer_tls_setup.h',
+        'public/environment/standalone/environment.cc',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
       'target_name': 'mojo_utility',
       'type': 'static_library',
       'sources': [
-        'public/utility/bindings_support_impl.cc',
-        'public/utility/bindings_support_impl.h',
-        'public/utility/environment.cc',
-        'public/utility/environment.h',
         'public/utility/run_loop.cc',
         'public/utility/run_loop.h',
         'public/utility/run_loop_handler.h',
diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi
index 10714755..bd5dfa92 100644
--- a/mojo/mojo_services.gypi
+++ b/mojo/mojo_services.gypi
@@ -53,6 +53,7 @@
         '../ui/gfx/gfx.gyp:gfx',
         '../ui/gfx/gfx.gyp:gfx_geometry',
         'mojo_common_lib',
+        'mojo_environment_chromium',
         'mojo_gles2_service',
         'mojo_native_viewport_bindings',
         'mojo_shell_bindings',
diff --git a/mojo/public/DEPS b/mojo/public/DEPS
index 4458cb2..0c679b9 100644
--- a/mojo/public/DEPS
+++ b/mojo/public/DEPS
@@ -2,7 +2,5 @@
   "-base",
   "-build",
   "-mojo",
-
   "+mojo/public",
-  "+testing",
 ]
diff --git a/mojo/public/README.md b/mojo/public/README.md
index 08f9881..32fc4b1 100644
--- a/mojo/public/README.md
+++ b/mojo/public/README.md
@@ -7,15 +7,25 @@
 Bindings
 --------
 
-This directory contains a static library that clients can link into their
-binary. The contents of this directory are not binary stable because each
-client is free to use whichever version they prefer.
+This directory contains a static library that clients may link into their
+binary. The contents of this directory are not binary stable as each client is
+free to use whichever version they prefer.
 
 This directory also contains a compiler that translates mojom interface
 definition files into idiomatic bindings for various languages, including
 C++ and JavaScript. Clients are expected to statically link with the generated
 code, which reads and writes the binary stable IPC message format.
 
+Environment
+-----------
+
+This directory contains a static library that clients may link into their
+binary. The contents of this directory are not binary stable as each client is
+free to use whichever version they prefer.
+
+The environment static library represents the shared state that is needed to
+support the Bindings and GLES2 libraries. It depends on the Utility library.
+
 GLES2
 -----
 
@@ -39,3 +49,14 @@
 
 This directory contains tests for code contained in the public API. Mojo
 clients are expected to ignore this directory.
+
+Utility
+-------
+
+This directory contains a static library that clients may link into their
+binary. The contents of this directory are not binary stable as each client is
+free to use whichever version they prefer.
+
+The Utility static library most notably defines an implementation of a RunLoop
+based on the MojoWaitMany that clients may use as the basis for asynchronous
+message processing.
diff --git a/mojo/public/bindings/lib/DEPS b/mojo/public/bindings/lib/DEPS
new file mode 100644
index 0000000..7f810b1
--- /dev/null
+++ b/mojo/public/bindings/lib/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "-mojo"
+  "+mojo/public/environment"
+  "+mojo/public/system"
+]
diff --git a/mojo/public/bindings/lib/bindings_support.cc b/mojo/public/bindings/lib/bindings_support.cc
deleted file mode 100644
index 8ea2013..0000000
--- a/mojo/public/bindings/lib/bindings_support.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 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 "mojo/public/bindings/lib/bindings_support.h"
-
-#include <assert.h>
-#include <stddef.h>
-
-namespace mojo {
-
-namespace {
-BindingsSupport* g_bindings_support = NULL;
-}
-
-// static
-void BindingsSupport::Set(BindingsSupport* support) {
-  g_bindings_support = support;
-}
-
-// static
-BindingsSupport* BindingsSupport::Get() {
-  assert(g_bindings_support);
-  return g_bindings_support;
-}
-
-}  // namespace mojo
diff --git a/mojo/public/bindings/lib/bindings_support.h b/mojo/public/bindings/lib/bindings_support.h
deleted file mode 100644
index 555131d..0000000
--- a/mojo/public/bindings/lib/bindings_support.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 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 MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SUPPORT_H_
-#define MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SUPPORT_H_
-
-#include "mojo/public/system/core_cpp.h"
-
-namespace mojo {
-class Buffer;
-
-// An embedder of the bindings library MUST implement BindingsSupport and call
-// BindingsSupport::Set prior to using the library.
-class BindingsSupport {
- public:
-  class AsyncWaitCallback {
-   public:
-    virtual ~AsyncWaitCallback() {}
-    virtual void OnHandleReady(MojoResult result) = 0;
-  };
-
-  typedef void* AsyncWaitID;
-
-  static void Set(BindingsSupport* support);
-  static BindingsSupport* Get();
-
-  // Get/set the current thread's Buffer pointer. SetCurrentBuffer returns the
-  // previously current Buffer.
-  virtual Buffer* GetCurrentBuffer() = 0;
-  virtual Buffer* SetCurrentBuffer(Buffer* buf) = 0;
-
-  // Asynchronously call MojoWait on a background thread, and pass the result
-  // of MojoWait to the given AsyncWaitCallback on the current thread.  Returns
-  // an AsyncWaitID that can be used with CancelWait to stop waiting. This
-  // identifier becomes invalid once the callback runs.
-  virtual AsyncWaitID AsyncWait(const Handle& handle,
-                                MojoWaitFlags flags,
-                                AsyncWaitCallback* callback) = 0;
-
-  // Cancel an existing call to AsyncWait with the given AsyncWaitID. The
-  // corresponding AsyncWaitCallback's OnHandleReady method will not be called
-  // in this case.
-  virtual void CancelWait(AsyncWaitID id) = 0;
-
- protected:
-  virtual ~BindingsSupport() {}
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_BINDINGS_LIB_BINDINGS_SUPPORT_H_
diff --git a/mojo/public/bindings/lib/buffer.cc b/mojo/public/bindings/lib/buffer.cc
index 6b303fb..bb7a53a 100644
--- a/mojo/public/bindings/lib/buffer.cc
+++ b/mojo/public/bindings/lib/buffer.cc
@@ -11,7 +11,7 @@
 #include <algorithm>
 
 #include "mojo/public/bindings/lib/bindings_serialization.h"
-#include "mojo/public/bindings/lib/bindings_support.h"
+#include "mojo/public/environment/buffer_tls.h"
 
 // Scrub memory in debug builds to help catch use-after-free bugs.
 #ifdef NDEBUG
@@ -25,17 +25,16 @@
 //-----------------------------------------------------------------------------
 
 Buffer::Buffer() {
-  previous_ = BindingsSupport::Get()->SetCurrentBuffer(this);
+  previous_ = internal::SetCurrentBuffer(this);
 }
 
 Buffer::~Buffer() {
-  Buffer* buf MOJO_ALLOW_UNUSED =
-      BindingsSupport::Get()->SetCurrentBuffer(previous_);
+  Buffer* buf MOJO_ALLOW_UNUSED = internal::SetCurrentBuffer(previous_);
   assert(buf == this);
 }
 
 Buffer* Buffer::current() {
-  return BindingsSupport::Get()->GetCurrentBuffer();
+  return internal::GetCurrentBuffer();
 }
 
 //-----------------------------------------------------------------------------
diff --git a/mojo/public/bindings/lib/connector.cc b/mojo/public/bindings/lib/connector.cc
index 1befc2b..e8f54aa 100644
--- a/mojo/public/bindings/lib/connector.cc
+++ b/mojo/public/bindings/lib/connector.cc
@@ -14,8 +14,10 @@
 
 // ----------------------------------------------------------------------------
 
-Connector::Connector(ScopedMessagePipeHandle message_pipe)
-    : message_pipe_(message_pipe.Pass()),
+Connector::Connector(ScopedMessagePipeHandle message_pipe,
+                     MojoAsyncWaiter* waiter)
+    : waiter_(waiter),
+      message_pipe_(message_pipe.Pass()),
       incoming_receiver_(NULL),
       error_(false) {
 }
@@ -54,19 +56,26 @@
 }
 
 void Connector::WaitToReadMore() {
-  read_callback_.SetOwnerToNotify(this);
-  read_callback_.SetAsyncWaitID(
-      BindingsSupport::Get()->AsyncWait(message_pipe_.get(),
-                                        MOJO_WAIT_FLAG_READABLE,
-                                        &read_callback_));
+  CallAsyncWait(MOJO_WAIT_FLAG_READABLE, &read_callback_);
 }
 
 void Connector::WaitToWriteMore() {
-  write_callback_.SetOwnerToNotify(this);
-  write_callback_.SetAsyncWaitID(
-      BindingsSupport::Get()->AsyncWait(message_pipe_.get(),
-                                        MOJO_WAIT_FLAG_WRITABLE,
-                                        &write_callback_));
+  CallAsyncWait(MOJO_WAIT_FLAG_WRITABLE, &write_callback_);
+}
+
+void Connector::CallAsyncWait(MojoWaitFlags flags, Callback* callback) {
+  callback->SetOwnerToNotify(this);
+  callback->SetAsyncWaitID(
+      waiter_->AsyncWait(waiter_,
+                         message_pipe_.get().value(),
+                         MOJO_WAIT_FLAG_READABLE,
+                         MOJO_DEADLINE_INDEFINITE,
+                         &Callback::OnHandleReady,
+                         callback));
+}
+
+void Connector::CallCancelWait(MojoAsyncWaitID async_wait_id) {
+  waiter_->CancelWait(waiter_, async_wait_id);
 }
 
 void Connector::ReadMore() {
@@ -155,7 +164,7 @@
 
 Connector::Callback::~Callback() {
   if (owner_)
-    BindingsSupport::Get()->CancelWait(async_wait_id_);
+    owner_->CallCancelWait(async_wait_id_);
 }
 
 void Connector::Callback::SetOwnerToNotify(Connector* owner) {
@@ -163,15 +172,20 @@
   owner_ = owner;
 }
 
-void Connector::Callback::SetAsyncWaitID(BindingsSupport::AsyncWaitID id) {
+void Connector::Callback::SetAsyncWaitID(MojoAsyncWaitID id) {
   async_wait_id_ = id;
 }
 
-void Connector::Callback::OnHandleReady(MojoResult result) {
-  assert(owner_);
+// static
+void Connector::Callback::OnHandleReady(void* closure, MojoResult result) {
+  Callback* self = static_cast<Callback*>(closure);
+
+  // Reset |owner_| to indicate that we are no longer in the waiting state.
+
+  assert(self->owner_);
   Connector* owner = NULL;
-  std::swap(owner, owner_);
-  owner->OnHandleReady(this, result);
+  std::swap(owner, self->owner_);
+  owner->OnHandleReady(self, result);
 }
 
 }  // namespace internal
diff --git a/mojo/public/bindings/lib/connector.h b/mojo/public/bindings/lib/connector.h
index 35e62939..c90979e 100644
--- a/mojo/public/bindings/lib/connector.h
+++ b/mojo/public/bindings/lib/connector.h
@@ -5,9 +5,9 @@
 #ifndef MOJO_PUBLIC_BINDINGS_LIB_CONNECTOR_H_
 #define MOJO_PUBLIC_BINDINGS_LIB_CONNECTOR_H_
 
-#include "mojo/public/bindings/lib/bindings_support.h"
 #include "mojo/public/bindings/lib/message.h"
 #include "mojo/public/bindings/lib/message_queue.h"
+#include "mojo/public/environment/default_async_waiter.h"
 #include "mojo/public/system/core_cpp.h"
 
 namespace mojo {
@@ -23,7 +23,8 @@
 class Connector : public MessageReceiver {
  public:
   // The Connector takes ownership of |message_pipe|.
-  explicit Connector(ScopedMessagePipeHandle message_pipe);
+  explicit Connector(ScopedMessagePipeHandle message_pipe,
+                     MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter());
   virtual ~Connector();
 
   // Sets the receiver to handle messages read from the message pipe.  The
@@ -39,29 +40,33 @@
   virtual bool Accept(Message* message) MOJO_OVERRIDE;
 
  private:
-  class Callback : public BindingsSupport::AsyncWaitCallback {
+  class Callback {
    public:
     Callback();
-    virtual ~Callback();
+    ~Callback();
 
     void SetOwnerToNotify(Connector* owner);
-    void SetAsyncWaitID(BindingsSupport::AsyncWaitID async_wait_id);
+    void SetAsyncWaitID(MojoAsyncWaitID async_wait_id);
 
-    virtual void OnHandleReady(MojoResult result) MOJO_OVERRIDE;
+    static void OnHandleReady(void* closure, MojoResult result);
 
    private:
     Connector* owner_;
-    BindingsSupport::AsyncWaitID async_wait_id_;
+    MojoAsyncWaitID async_wait_id_;
   };
   friend class Callback;
 
   void OnHandleReady(Callback* callback, MojoResult result);
   void WaitToReadMore();
   void WaitToWriteMore();
+  void CallAsyncWait(MojoWaitFlags flags, Callback* callback);
+  void CallCancelWait(MojoAsyncWaitID async_wait_id);
   void ReadMore();
   void WriteMore();
   void WriteOne(Message* message, bool* wait_to_write);
 
+  MojoAsyncWaiter* waiter_;
+
   ScopedMessagePipeHandle message_pipe_;
   MessageReceiver* incoming_receiver_;
   MessageQueue write_queue_;
diff --git a/mojo/public/bindings/lib/remote_ptr.h b/mojo/public/bindings/lib/remote_ptr.h
index a0c42e3..3ab5fb20 100644
--- a/mojo/public/bindings/lib/remote_ptr.h
+++ b/mojo/public/bindings/lib/remote_ptr.h
@@ -48,13 +48,15 @@
 //
 template <typename S>
 class RemotePtr {
+  struct State;
   MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(RemotePtr, RValue);
 
  public:
   RemotePtr() : state_(NULL) {}
   explicit RemotePtr(ScopedMessagePipeHandle message_pipe,
-                     typename S::_Peer* peer = NULL)
-      : state_(new State(message_pipe.Pass(), peer)) {
+                     typename S::_Peer* peer = NULL,
+                     MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter())
+      : state_(new State(message_pipe.Pass(), peer, waiter)) {
   }
 
   // Move-only constructor and operator=.
@@ -87,9 +89,10 @@
   }
 
   void reset(ScopedMessagePipeHandle message_pipe,
-             typename S::_Peer* peer = NULL) {
+             typename S::_Peer* peer = NULL,
+             MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) {
     delete state_;
-    state_ = new State(message_pipe.Pass(), peer);
+    state_ = new State(message_pipe.Pass(), peer, waiter);
   }
 
   bool encountered_error() const {
@@ -99,8 +102,9 @@
 
  private:
   struct State {
-    State(ScopedMessagePipeHandle message_pipe, typename S::_Peer* peer)
-        : connector(message_pipe.Pass()),
+    State(ScopedMessagePipeHandle message_pipe, typename S::_Peer* peer,
+          MojoAsyncWaiter* waiter)
+        : connector(message_pipe.Pass(), waiter),
           proxy(&connector),
           stub(peer) {
       if (peer)
diff --git a/mojo/public/environment/DEPS b/mojo/public/environment/DEPS
new file mode 100644
index 0000000..7758789c
--- /dev/null
+++ b/mojo/public/environment/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "-mojo/public"
+  "+mojo/public/system"
+]
diff --git a/mojo/public/environment/buffer_tls.h b/mojo/public/environment/buffer_tls.h
new file mode 100644
index 0000000..60929e9
--- /dev/null
+++ b/mojo/public/environment/buffer_tls.h
@@ -0,0 +1,20 @@
+// Copyright 2014 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 MOJO_PUBLIC_ENVIRONMENT_BUFFER_TLS_H_
+#define MOJO_PUBLIC_ENVIRONMENT_BUFFER_TLS_H_
+
+namespace mojo {
+class Buffer;
+
+namespace internal {
+
+// Get/Set the |Buffer*| associated with current thread.
+Buffer* GetCurrentBuffer();
+Buffer* SetCurrentBuffer(Buffer* buffer);
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_ENVIRONMENT_BUFFER_TLS_H_
diff --git a/mojo/public/environment/default_async_waiter.h b/mojo/public/environment/default_async_waiter.h
new file mode 100644
index 0000000..97cef12
--- /dev/null
+++ b/mojo/public/environment/default_async_waiter.h
@@ -0,0 +1,17 @@
+// Copyright 2014 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 MOJO_PUBLIC_ENVIRONMENT_DEFAULT_ASYNC_WAITER_H_
+#define MOJO_PUBLIC_ENVIRONMENT_DEFAULT_ASYNC_WAITER_H_
+
+#include "mojo/public/system/async_waiter.h"
+
+namespace mojo {
+
+// Returns a default implementation of MojoAsyncWaiter.
+MojoAsyncWaiter* GetDefaultAsyncWaiter();
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_ENVIRONMENT_DEFAULT_ASYNC_WAITER_H_
diff --git a/mojo/public/environment/environment.h b/mojo/public/environment/environment.h
new file mode 100644
index 0000000..ce93726
--- /dev/null
+++ b/mojo/public/environment/environment.h
@@ -0,0 +1,24 @@
+// Copyright 2014 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 MOJO_PUBLIC_ENVIRONMENT_ENVIRONMENT_H_
+#define MOJO_PUBLIC_ENVIRONMENT_ENVIRONMENT_H_
+
+#include "mojo/public/system/macros.h"
+
+namespace mojo {
+
+// This class must be instantiated before using any Mojo APIs.
+class Environment {
+ public:
+  Environment();
+  ~Environment();
+
+ private:
+  MOJO_DISALLOW_COPY_AND_ASSIGN(Environment);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_ENVIRONMENT_ENVIRONMENT_H_
diff --git a/mojo/public/environment/standalone/DEPS b/mojo/public/environment/standalone/DEPS
new file mode 100644
index 0000000..a04b88fc
--- /dev/null
+++ b/mojo/public/environment/standalone/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/public/environment"
+  "+mojo/public/utility"
+]
diff --git a/mojo/public/environment/standalone/buffer_tls.cc b/mojo/public/environment/standalone/buffer_tls.cc
new file mode 100644
index 0000000..a26d30d
--- /dev/null
+++ b/mojo/public/environment/standalone/buffer_tls.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 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 "mojo/public/environment/buffer_tls.h"
+
+#include "mojo/public/environment/standalone/buffer_tls_setup.h"
+#include "mojo/public/utility/thread_local.h"
+
+namespace mojo {
+namespace internal {
+
+static ThreadLocalPlatform::SlotType s_slot;
+
+void SetUpCurrentBuffer() {
+  ThreadLocalPlatform::AllocateSlot(&s_slot);
+}
+
+void TearDownCurrentBuffer() {
+  ThreadLocalPlatform::FreeSlot(s_slot);
+}
+
+Buffer* GetCurrentBuffer() {
+  return static_cast<Buffer*>(ThreadLocalPlatform::GetValueFromSlot(s_slot));
+}
+
+Buffer* SetCurrentBuffer(Buffer* buf) {
+  Buffer* old_buf = GetCurrentBuffer();
+  ThreadLocalPlatform::SetValueInSlot(s_slot, buf);
+  return old_buf;
+}
+
+}  // namespace internal
+}  // namespace mojo
diff --git a/mojo/public/environment/standalone/buffer_tls_setup.h b/mojo/public/environment/standalone/buffer_tls_setup.h
new file mode 100644
index 0000000..8f5daa13
--- /dev/null
+++ b/mojo/public/environment/standalone/buffer_tls_setup.h
@@ -0,0 +1,17 @@
+// Copyright 2014 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 MOJO_PUBLIC_ENVIRONMENT_STANDALONE_BUFFER_TLS_SETUP_H_
+#define MOJO_PUBLIC_ENVIRONMENT_STANDALONE_BUFFER_TLS_SETUP_H_
+
+namespace mojo {
+namespace internal {
+
+void SetUpCurrentBuffer();
+void TearDownCurrentBuffer();
+
+}  // namespace internal
+}  // namespace mojo
+
+#endif  // MOJO_PUBLIC_ENVIRONMENT_STANDALONE_BUFFER_TLS_SETUP_H_
diff --git a/mojo/public/environment/standalone/default_async_waiter.cc b/mojo/public/environment/standalone/default_async_waiter.cc
new file mode 100644
index 0000000..ff2dfae
--- /dev/null
+++ b/mojo/public/environment/standalone/default_async_waiter.cc
@@ -0,0 +1,93 @@
+// Copyright 2014 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 "mojo/public/environment/default_async_waiter.h"
+
+#include <assert.h>
+
+#include "mojo/public/utility/run_loop.h"
+#include "mojo/public/utility/run_loop_handler.h"
+
+namespace mojo {
+namespace {
+
+// RunLoopHandler implementation used for a request to AsyncWait(). There are
+// two ways RunLoopHandlerImpl is deleted:
+// . when the handle is ready (or errored).
+// . when CancelWait() is invoked.
+class RunLoopHandlerImpl : public RunLoopHandler {
+ public:
+  RunLoopHandlerImpl(const Handle& handle,
+                     MojoAsyncWaitCallback callback,
+                     void* closure)
+      : handle_(handle),
+        callback_(callback),
+        closure_(closure) {
+  }
+
+  virtual ~RunLoopHandlerImpl() {
+    RunLoop::current()->RemoveHandler(handle_);
+  }
+
+  // RunLoopHandler:
+  virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
+    NotifyCallback(MOJO_RESULT_OK);
+  }
+
+  virtual void OnHandleError(const Handle& handle,
+                             MojoResult result) MOJO_OVERRIDE {
+    NotifyCallback(result);
+  }
+
+ private:
+  void NotifyCallback(MojoResult result) {
+    // Delete this to unregister the handle. That way if the callback
+    // reregisters everything is ok.
+    MojoAsyncWaitCallback callback = callback_;
+    void* closure = closure_;
+    delete this;
+
+    callback(closure, result);
+  }
+
+  const Handle handle_;
+  MojoAsyncWaitCallback callback_;
+  void* closure_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopHandlerImpl);
+};
+
+MojoAsyncWaitID AsyncWait(MojoAsyncWaiter* waiter,
+                          MojoHandle handle,
+                          MojoWaitFlags flags,
+                          MojoDeadline deadline,
+                          MojoAsyncWaitCallback callback,
+                          void* closure) {
+  RunLoop* run_loop = RunLoop::current();
+  assert(run_loop);
+
+  // |run_loop_handler| is destroyed either when the handle is ready or if
+  // CancelWait is invoked.
+  RunLoopHandlerImpl* run_loop_handler =
+      new RunLoopHandlerImpl(Handle(handle), callback, closure);
+  run_loop->AddHandler(run_loop_handler, Handle(handle), flags, deadline);
+  return reinterpret_cast<MojoAsyncWaitID>(run_loop_handler);
+}
+
+void CancelWait(MojoAsyncWaiter* waiter, MojoAsyncWaitID wait_id) {
+  delete reinterpret_cast<RunLoopHandlerImpl*>(wait_id);
+}
+
+MojoAsyncWaiter s_default_async_waiter = {
+  AsyncWait,
+  CancelWait
+};
+
+}  // namespace
+
+MojoAsyncWaiter* GetDefaultAsyncWaiter() {
+  return &s_default_async_waiter;
+}
+
+}  // namespace mojo
diff --git a/mojo/public/environment/standalone/environment.cc b/mojo/public/environment/standalone/environment.cc
new file mode 100644
index 0000000..39d2219
--- /dev/null
+++ b/mojo/public/environment/standalone/environment.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 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 "mojo/public/environment/environment.h"
+
+#include "mojo/public/environment/standalone/buffer_tls_setup.h"
+#include "mojo/public/utility/run_loop.h"
+
+namespace mojo {
+
+Environment::Environment() {
+  internal::SetUpCurrentBuffer();
+  RunLoop::SetUp();
+}
+
+Environment::~Environment() {
+  RunLoop::TearDown();
+  internal::TearDownCurrentBuffer();
+}
+
+}  // namespace mojo
diff --git a/mojo/public/system/async_waiter.h b/mojo/public/system/async_waiter.h
new file mode 100644
index 0000000..fc7c2075
--- /dev/null
+++ b/mojo/public/system/async_waiter.h
@@ -0,0 +1,40 @@
+// Copyright 2014 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 MOJO_PUBLIC_SYSTEM_ASYNC_WAITER_H_
+#define MOJO_PUBLIC_SYSTEM_ASYNC_WAITER_H_
+
+#include "mojo/public/system/core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uintptr_t MojoAsyncWaitID;
+
+typedef void (*MojoAsyncWaitCallback)(void* closure, MojoResult result);
+
+struct MojoAsyncWaiter {
+  // Asynchronously call MojoWait on a background thread, and pass the result
+  // of MojoWait to the given MojoAsyncWaitCallback on the current thread.
+  // Returns a non-zero MojoAsyncWaitID that can be used with CancelWait to
+  // stop waiting. This identifier becomes invalid once the callback runs.
+  MojoAsyncWaitID (*AsyncWait)(MojoAsyncWaiter* waiter,
+                               MojoHandle handle,
+                               MojoWaitFlags flags,
+                               MojoDeadline deadline,
+                               MojoAsyncWaitCallback callback,
+                               void* closure);
+
+  // Cancel an existing call to AsyncWait with the given MojoAsyncWaitID. The
+  // corresponding MojoAsyncWaitCallback will not be called in this case.
+  void (*CancelWait)(MojoAsyncWaiter* waiter,
+                     MojoAsyncWaitID wait_id);
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // MOJO_PUBLIC_SYSTEM_ASYNC_WAITER_H_
diff --git a/mojo/public/tests/bindings/array_unittest.cc b/mojo/public/tests/bindings/array_unittest.cc
index bb46c67a..dac4b50 100644
--- a/mojo/public/tests/bindings/array_unittest.cc
+++ b/mojo/public/tests/bindings/array_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "mojo/public/bindings/lib/array.h"
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
@@ -11,7 +11,7 @@
 
 // Tests that basic Array operations work.
 TEST(ArrayTest, Basic) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   // 8 bytes for the array, with 8 bytes left over for elements.
   internal::FixedBuffer buf(8 + 8*sizeof(char));
@@ -34,7 +34,7 @@
 // Tests that basic Array<bool> operations work, and that it's packed into 1
 // bit per element.
 TEST(ArrayTest, Bool) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   // 8 bytes for the array header, with 8 bytes left over for elements.
   internal::FixedBuffer buf(8 + 3);
@@ -57,7 +57,7 @@
 
 // Tests that Array<Handle> supports transferring handles.
 TEST(ArrayTest, Handle) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   AllocationScope scope;
 
diff --git a/mojo/public/tests/bindings/buffer_unittest.cc b/mojo/public/tests/bindings/buffer_unittest.cc
index ab181505..06cb4ca 100644
--- a/mojo/public/tests/bindings/buffer_unittest.cc
+++ b/mojo/public/tests/bindings/buffer_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "mojo/public/bindings/lib/bindings_serialization.h"
 #include "mojo/public/bindings/lib/buffer.h"
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
@@ -21,7 +21,7 @@
 
 // Tests small and large allocations in ScratchBuffer.
 TEST(ScratchBufferTest, Basic) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   // Test that a small allocation is placed on the stack.
   internal::ScratchBuffer buf;
@@ -42,7 +42,7 @@
 
 // Tests that Buffer::current() returns the correct value.
 TEST(ScratchBufferTest, Stacked) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   EXPECT_FALSE(Buffer::current());
 
@@ -61,7 +61,7 @@
 
 // Tests that FixedBuffer allocates memory aligned to 8 byte boundaries.
 TEST(FixedBufferTest, Alignment) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   internal::FixedBuffer buf(internal::Align(10) * 2);
   ASSERT_EQ(buf.size(), 16u * 2);
@@ -81,7 +81,7 @@
 
 // Tests that FixedBuffer::Leak passes ownership to the caller.
 TEST(FixedBufferTest, Leak) {
-  SimpleBindingsSupport bindings_support;
+  Environment env;
 
   void* ptr = NULL;
   void* buf_ptr = NULL;
diff --git a/mojo/public/tests/bindings/connector_unittest.cc b/mojo/public/tests/bindings/connector_unittest.cc
index 4e1feba..a814ffc8 100644
--- a/mojo/public/tests/bindings/connector_unittest.cc
+++ b/mojo/public/tests/bindings/connector_unittest.cc
@@ -5,11 +5,11 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "mojo/public/bindings/lib/bindings_support.h"
 #include "mojo/public/bindings/lib/connector.h"
 #include "mojo/public/bindings/lib/message_queue.h"
+#include "mojo/public/environment/environment.h"
 #include "mojo/public/system/macros.h"
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/utility/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
@@ -59,7 +59,7 @@
   }
 
   void PumpMessages() {
-    bindings_support_.Process();
+    loop_.RunUntilIdle();
   }
 
  protected:
@@ -67,7 +67,8 @@
   ScopedMessagePipeHandle handle1_;
 
  private:
-  SimpleBindingsSupport bindings_support_;
+  Environment env_;
+  RunLoop loop_;
 };
 
 TEST_F(ConnectorTest, Basic) {
diff --git a/mojo/public/tests/bindings/handle_passing_unittest.cc b/mojo/public/tests/bindings/handle_passing_unittest.cc
index 21b26f21..ca2d2709 100644
--- a/mojo/public/tests/bindings/handle_passing_unittest.cc
+++ b/mojo/public/tests/bindings/handle_passing_unittest.cc
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 #include "mojo/public/bindings/lib/remote_ptr.h"
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
 #include "mojo/public/tests/test_support.h"
+#include "mojo/public/utility/run_loop.h"
 #include "mojom/sample_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -125,17 +126,18 @@
 
 }  // namespace
 
-class BindingsHandlePassingTest : public testing::Test {
+class HandlePassingTest : public testing::Test {
  public:
   void PumpMessages() {
-    bindings_support_.Process();
+    loop_.RunUntilIdle();
   }
 
  private:
-  SimpleBindingsSupport bindings_support_;
+  Environment env_;
+  RunLoop loop_;
 };
 
-TEST_F(BindingsHandlePassingTest, Basic) {
+TEST_F(HandlePassingTest, Basic) {
   ScopedMessagePipeHandle pipe0;
   ScopedMessagePipeHandle pipe1;
   CreateMessagePipe(&pipe0, &pipe1);
@@ -152,7 +154,7 @@
   EXPECT_TRUE(factory_client.got_response());
 }
 
-TEST_F(BindingsHandlePassingTest, PassInvalid) {
+TEST_F(HandlePassingTest, PassInvalid) {
   ScopedMessagePipeHandle pipe0;
   ScopedMessagePipeHandle pipe1;
   CreateMessagePipe(&pipe0, &pipe1);
diff --git a/mojo/public/tests/bindings/remote_ptr_unittest.cc b/mojo/public/tests/bindings/remote_ptr_unittest.cc
index d990bceb..f4f3b23 100644
--- a/mojo/public/tests/bindings/remote_ptr_unittest.cc
+++ b/mojo/public/tests/bindings/remote_ptr_unittest.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "mojo/public/bindings/lib/remote_ptr.h"
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
+#include "mojo/public/utility/run_loop.h"
 #include "mojom/math_calculator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -89,7 +90,7 @@
   }
 
   void PumpMessages() {
-    bindings_support_.Process();
+    loop_.RunUntilIdle();
   }
 
  protected:
@@ -97,7 +98,8 @@
   ScopedMessagePipeHandle pipe1_;
 
  private:
-  SimpleBindingsSupport bindings_support_;
+  Environment env_;
+  RunLoop loop_;
 };
 
 TEST_F(RemotePtrTest, EndToEnd) {
diff --git a/mojo/public/tests/bindings/sample_service_unittests.cc b/mojo/public/tests/bindings/sample_service_unittests.cc
index 3fe8a11..f31b08d 100644
--- a/mojo/public/tests/bindings/sample_service_unittests.cc
+++ b/mojo/public/tests/bindings/sample_service_unittests.cc
@@ -6,7 +6,7 @@
 #include <ostream>
 #include <string>
 
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
 #include "mojom/sample_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -286,7 +286,7 @@
 }  // namespace
 
 TEST(BindingsSampleTest, Basic) {
-  mojo::test::SimpleBindingsSupport bindings_support;
+  mojo::Environment env;
   SimpleMessageReceiver receiver;
 
   // User has a proxy to a Service somehow.
diff --git a/mojo/public/tests/bindings/simple_bindings_support.cc b/mojo/public/tests/bindings/simple_bindings_support.cc
deleted file mode 100644
index ceabc1e..0000000
--- a/mojo/public/tests/bindings/simple_bindings_support.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2013 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 "mojo/public/tests/bindings/simple_bindings_support.h"
-
-#include <stdlib.h>
-
-#include <algorithm>
-
-namespace mojo {
-namespace test {
-
-SimpleBindingsSupport::SimpleBindingsSupport()
-    : buf_(NULL) {
-  BindingsSupport::Set(this);
-}
-
-SimpleBindingsSupport::~SimpleBindingsSupport() {
-  BindingsSupport::Set(NULL);
-
-  for (WaiterList::iterator it = waiters_.begin(); it != waiters_.end(); ++it)
-    delete *it;
-}
-
-Buffer* SimpleBindingsSupport::SetCurrentBuffer(Buffer* buf) {
-  // This is a simplistic implementation that assumes it is only ever used from
-  // a single thread, which is common in tests.
-  std::swap(buf_, buf);
-  return buf;
-}
-
-Buffer* SimpleBindingsSupport::GetCurrentBuffer() {
-  return buf_;
-}
-
-BindingsSupport::AsyncWaitID SimpleBindingsSupport::AsyncWait(
-    const Handle& handle,
-    MojoWaitFlags flags,
-    AsyncWaitCallback* callback) {
-  Waiter* waiter = new Waiter();
-  waiter->handle = handle;
-  waiter->flags = flags;
-  waiter->callback = callback;
-  waiters_.push_back(waiter);
-  return waiter;
-}
-
-void SimpleBindingsSupport::CancelWait(AsyncWaitID async_wait_id) {
-  Waiter* waiter = static_cast<Waiter*>(async_wait_id);
-
-  WaiterList::iterator it = waiters_.begin();
-  while (it != waiters_.end()) {
-    if (*it == waiter) {
-      WaiterList::iterator doomed = it++;
-      waiters_.erase(doomed);
-    } else {
-      ++it;
-    }
-  }
-
-  delete waiter;
-}
-
-void SimpleBindingsSupport::Process() {
-  for (;;) {
-    typedef std::pair<AsyncWaitCallback*, MojoResult> Result;
-    std::list<Result> results;
-
-    WaiterList::iterator it = waiters_.begin();
-    while (it != waiters_.end()) {
-      Waiter* waiter = *it;
-      MojoResult result;
-      if (IsReady(waiter->handle, waiter->flags, &result)) {
-        results.push_back(std::make_pair(waiter->callback, result));
-        WaiterList::iterator doomed = it++;
-        waiters_.erase(doomed);
-        delete waiter;
-      } else {
-        ++it;
-      }
-    }
-
-    for (std::list<Result>::const_iterator it = results.begin();
-         it != results.end();
-         ++it) {
-      it->first->OnHandleReady(it->second);
-    }
-    if (results.empty())
-      break;
-  }
-}
-
-bool SimpleBindingsSupport::IsReady(const Handle& handle, MojoWaitFlags flags,
-                                    MojoResult* result) {
-  *result = Wait(handle, flags, 0);
-  return *result != MOJO_RESULT_DEADLINE_EXCEEDED;
-}
-
-}  // namespace test
-}  // namespace mojo
diff --git a/mojo/public/tests/bindings/simple_bindings_support.h b/mojo/public/tests/bindings/simple_bindings_support.h
deleted file mode 100644
index e1246256..0000000
--- a/mojo/public/tests/bindings/simple_bindings_support.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 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 MOJO_PUBLIC_TESTS_SIMPLE_BINDINGS_SUPPORT_H_
-#define MOJO_PUBLIC_TESTS_SIMPLE_BINDINGS_SUPPORT_H_
-
-#include <list>
-
-#include "mojo/public/bindings/lib/bindings_support.h"
-
-namespace mojo {
-namespace test {
-
-class SimpleBindingsSupport : public BindingsSupport {
- public:
-  SimpleBindingsSupport();
-  virtual ~SimpleBindingsSupport();
-
-  virtual Buffer* SetCurrentBuffer(Buffer* buf) MOJO_OVERRIDE;
-  virtual Buffer* GetCurrentBuffer() MOJO_OVERRIDE;
-
-  virtual AsyncWaitID AsyncWait(const Handle& handle,
-                                MojoWaitFlags flags,
-                                AsyncWaitCallback* callback) MOJO_OVERRIDE;
-  virtual void CancelWait(AsyncWaitID async_wait_id) MOJO_OVERRIDE;
-
-  // This method is called by unit tests to check the status of any handles
-  // that we are asynchronously waiting on and to dispatch callbacks for any
-  // handles that are ready.
-  void Process();
-
- private:
-  bool IsReady(const Handle& handle, MojoWaitFlags flags, MojoResult* result);
-
-  struct Waiter {
-    Handle handle;
-    MojoWaitFlags flags;
-    AsyncWaitCallback* callback;
-  };
-
-  typedef std::list<Waiter*> WaiterList;
-  WaiterList waiters_;
-
-  Buffer* buf_;
-};
-
-}  // namespace test
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_TESTS_SIMPLE_BINDINGS_SUPPORT_H_
diff --git a/mojo/public/tests/bindings/type_conversion_unittest.cc b/mojo/public/tests/bindings/type_conversion_unittest.cc
index fb92b60..ad0d1f73 100644
--- a/mojo/public/tests/bindings/type_conversion_unittest.cc
+++ b/mojo/public/tests/bindings/type_conversion_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/public/tests/bindings/simple_bindings_support.h"
+#include "mojo/public/environment/environment.h"
 #include "mojom/test_structs.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -66,7 +66,7 @@
 
 class TypeConversionTest : public testing::Test {
  private:
-  SimpleBindingsSupport bindings_support_;
+  Environment env_;
 };
 
 TEST_F(TypeConversionTest, String) {
diff --git a/mojo/public/tests/environment/async_waiter_unittest.cc b/mojo/public/tests/environment/async_waiter_unittest.cc
new file mode 100644
index 0000000..dd0f3972
--- /dev/null
+++ b/mojo/public/tests/environment/async_waiter_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 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 "mojo/public/environment/default_async_waiter.h"
+
+#include "mojo/public/environment/environment.h"
+#include "mojo/public/system/core_cpp.h"
+#include "mojo/public/tests/test_support.h"
+#include "mojo/public/utility/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+class TestAsyncWaitCallback {
+ public:
+  TestAsyncWaitCallback() : result_count_(0), last_result_(MOJO_RESULT_OK) {
+  }
+  virtual ~TestAsyncWaitCallback() {}
+
+  int result_count() const { return result_count_; }
+
+  MojoResult last_result() const { return last_result_; }
+
+  // MojoAsyncWaitCallback:
+  static void OnHandleReady(void* closure, MojoResult result) {
+    TestAsyncWaitCallback* self = static_cast<TestAsyncWaitCallback*>(closure);
+    self->result_count_++;
+    self->last_result_ = result;
+  }
+
+ private:
+  int result_count_;
+  MojoResult last_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAsyncWaitCallback);
+};
+
+MojoAsyncWaitID CallAsyncWait(const Handle& handle,
+                              MojoWaitFlags flags,
+                              TestAsyncWaitCallback* callback) {
+  MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter();
+  return waiter->AsyncWait(waiter,
+                           handle.value(),
+                           flags,
+                           MOJO_DEADLINE_INDEFINITE,
+                           &TestAsyncWaitCallback::OnHandleReady,
+                           callback);
+}
+
+void CallCancelWait(MojoAsyncWaitID wait_id) {
+  MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter();
+  waiter->CancelWait(waiter, wait_id);
+}
+
+class AsyncWaiterTest : public testing::Test {
+ public:
+  AsyncWaiterTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    Test::SetUp();
+    environment_.reset(new Environment);
+    run_loop_.reset(new RunLoop);
+  }
+  virtual void TearDown() OVERRIDE {
+    run_loop_.reset();
+    environment_.reset(NULL);
+    Test::TearDown();
+  }
+
+ private:
+  scoped_ptr<Environment> environment_;
+  scoped_ptr<RunLoop> run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncWaiterTest);
+};
+
+// Verifies AsyncWaitCallback is notified when pipe is ready.
+TEST_F(AsyncWaiterTest, CallbackNotified) {
+  TestAsyncWaitCallback callback;
+  MessagePipe test_pipe;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            test::WriteEmptyMessage(test_pipe.handle1.get()));
+
+  CallAsyncWait(test_pipe.handle0.get(),
+                MOJO_WAIT_FLAG_READABLE,
+                &callback);
+  RunLoop::current()->Run();
+  EXPECT_EQ(1, callback.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback.last_result());
+}
+
+// Verifies 2 AsyncWaitCallbacks are notified when there pipes are ready.
+TEST_F(AsyncWaiterTest, TwoCallbacksNotified) {
+  TestAsyncWaitCallback callback1;
+  TestAsyncWaitCallback callback2;
+  MessagePipe test_pipe1;
+  MessagePipe test_pipe2;
+  EXPECT_EQ(MOJO_RESULT_OK,
+            test::WriteEmptyMessage(test_pipe1.handle1.get()));
+  EXPECT_EQ(MOJO_RESULT_OK,
+            test::WriteEmptyMessage(test_pipe2.handle1.get()));
+
+  CallAsyncWait(test_pipe1.handle0.get(), MOJO_WAIT_FLAG_READABLE, &callback1);
+  CallAsyncWait(test_pipe2.handle0.get(), MOJO_WAIT_FLAG_READABLE, &callback2);
+
+  RunLoop::current()->Run();
+  EXPECT_EQ(1, callback1.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback1.last_result());
+  EXPECT_EQ(1, callback2.result_count());
+  EXPECT_EQ(MOJO_RESULT_OK, callback2.last_result());
+}
+
+// Verifies cancel works.
+TEST_F(AsyncWaiterTest, CancelCallback) {
+  TestAsyncWaitCallback callback;
+  MessagePipe test_pipe;
+  EXPECT_EQ(MOJO_RESULT_OK, test::WriteEmptyMessage(test_pipe.handle1.get()));
+
+  CallCancelWait(
+      CallAsyncWait(test_pipe.handle0.get(),
+                    MOJO_WAIT_FLAG_READABLE,
+                    &callback));
+  RunLoop::current()->Run();
+  EXPECT_EQ(0, callback.result_count());
+}
+
+}  // namespace
+}  // namespace mojo
diff --git a/mojo/public/tests/utility/bindings_support_impl_unittest.cc b/mojo/public/tests/utility/bindings_support_impl_unittest.cc
deleted file mode 100644
index b2c248c..0000000
--- a/mojo/public/tests/utility/bindings_support_impl_unittest.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2013 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 "mojo/public/utility/bindings_support_impl.h"
-
-#include "base/basictypes.h"
-#include "mojo/public/system/core_cpp.h"
-#include "mojo/public/tests/test_support.h"
-#include "mojo/public/utility/environment.h"
-#include "mojo/public/utility/run_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace {
-
-class TestAsyncWaitCallback : public BindingsSupport::AsyncWaitCallback {
- public:
-  TestAsyncWaitCallback() : result_count_(0), last_result_(MOJO_RESULT_OK) {
-  }
-  virtual ~TestAsyncWaitCallback() {}
-
-  int result_count() const { return result_count_; }
-
-  MojoResult last_result() const { return last_result_; }
-
-  // RunLoopHandler:
-  virtual void OnHandleReady(MojoResult result) OVERRIDE {
-    result_count_++;
-    last_result_ = result;
-  }
-
- private:
-  int result_count_;
-  MojoResult last_result_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestAsyncWaitCallback);
-};
-
-class BindingsSupportImplTest : public testing::Test {
- public:
-  BindingsSupportImplTest() {}
-
-  virtual void SetUp() OVERRIDE {
-    Test::SetUp();
-    environment_.reset(new Environment);
-    run_loop_.reset(new RunLoop);
-  }
-  virtual void TearDown() OVERRIDE {
-    run_loop_.reset();
-    environment_.reset(NULL);
-    Test::TearDown();
-  }
-
- private:
-  scoped_ptr<Environment> environment_;
-  scoped_ptr<RunLoop> run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(BindingsSupportImplTest);
-};
-
-// Verifies AsyncWaitCallback is notified when pipe is ready.
-TEST_F(BindingsSupportImplTest, CallbackNotified) {
-  TestAsyncWaitCallback callback;
-  MessagePipe test_pipe;
-  EXPECT_EQ(MOJO_RESULT_OK,
-            test::WriteEmptyMessage(test_pipe.handle1.get()));
-
-  BindingsSupport::Get()->AsyncWait(test_pipe.handle0.get(),
-                                    MOJO_WAIT_FLAG_READABLE, &callback);
-  RunLoop::current()->Run();
-  EXPECT_EQ(1, callback.result_count());
-  EXPECT_EQ(MOJO_RESULT_OK, callback.last_result());
-}
-
-// Verifies 2 AsyncWaitCallbacks are notified when there pipes are ready.
-TEST_F(BindingsSupportImplTest, TwoCallbacksNotified) {
-  TestAsyncWaitCallback callback1;
-  TestAsyncWaitCallback callback2;
-  MessagePipe test_pipe1;
-  MessagePipe test_pipe2;
-  EXPECT_EQ(MOJO_RESULT_OK,
-            test::WriteEmptyMessage(test_pipe1.handle1.get()));
-  EXPECT_EQ(MOJO_RESULT_OK,
-            test::WriteEmptyMessage(test_pipe2.handle1.get()));
-
-  BindingsSupport::Get()->AsyncWait(test_pipe1.handle0.get(),
-                                    MOJO_WAIT_FLAG_READABLE, &callback1);
-  BindingsSupport::Get()->AsyncWait(test_pipe2.handle0.get(),
-                                    MOJO_WAIT_FLAG_READABLE, &callback2);
-  RunLoop::current()->Run();
-  EXPECT_EQ(1, callback1.result_count());
-  EXPECT_EQ(MOJO_RESULT_OK, callback1.last_result());
-  EXPECT_EQ(1, callback2.result_count());
-  EXPECT_EQ(MOJO_RESULT_OK, callback2.last_result());
-}
-
-// Verifies cancel works.
-TEST_F(BindingsSupportImplTest, CancelCallback) {
-  TestAsyncWaitCallback callback;
-  MessagePipe test_pipe;
-  EXPECT_EQ(MOJO_RESULT_OK, test::WriteEmptyMessage(test_pipe.handle1.get()));
-
-  BindingsSupport::Get()->CancelWait(
-      BindingsSupport::Get()->AsyncWait(test_pipe.handle0.get(),
-                                        MOJO_WAIT_FLAG_READABLE, &callback));
-  RunLoop::current()->Run();
-  EXPECT_EQ(0, callback.result_count());
-}
-
-}  // namespace
-}  // namespace mojo
diff --git a/mojo/public/utility/DEPS b/mojo/public/utility/DEPS
new file mode 100644
index 0000000..dd7669a
--- /dev/null
+++ b/mojo/public/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/public/system",
+]
diff --git a/mojo/public/utility/bindings_support_impl.cc b/mojo/public/utility/bindings_support_impl.cc
deleted file mode 100644
index b78f782..0000000
--- a/mojo/public/utility/bindings_support_impl.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2013 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 "mojo/public/utility/bindings_support_impl.h"
-
-#include <assert.h>
-
-#include "mojo/public/bindings/lib/buffer.h"
-#include "mojo/public/utility/run_loop.h"
-#include "mojo/public/utility/run_loop_handler.h"
-#include "mojo/public/utility/thread_local.h"
-
-namespace mojo {
-namespace internal {
-namespace {
-
-ThreadLocalPointer<Buffer>* tls_buffer = NULL;
-
-// RunLoopHandler implementation used for a request to AsyncWait(). There are
-// two ways RunLoopHandlerImpl is deleted:
-// . when the handle is ready (or errored).
-// . when BindingsSupport::CancelWait() is invoked.
-class RunLoopHandlerImpl : public RunLoopHandler {
- public:
-  RunLoopHandlerImpl(const Handle& handle,
-                     BindingsSupport::AsyncWaitCallback* callback)
-      : handle_(handle),
-        callback_(callback) {}
-  virtual ~RunLoopHandlerImpl() {
-    RunLoop::current()->RemoveHandler(handle_);
-  }
-
-  // RunLoopHandler:
-  virtual void OnHandleReady(const Handle& handle) MOJO_OVERRIDE {
-    NotifyCallback(MOJO_RESULT_OK);
-  }
-
-  virtual void OnHandleError(const Handle& handle,
-                             MojoResult result) MOJO_OVERRIDE {
-    NotifyCallback(result);
-  }
-
- private:
-  void NotifyCallback(MojoResult result) {
-    // Delete this to unregister the handle. That way if the callback
-    // reregisters everything is ok.
-    BindingsSupport::AsyncWaitCallback* callback = callback_;
-    delete this;
-
-    callback->OnHandleReady(result);
-  }
-
-  const Handle handle_;
-  BindingsSupport::AsyncWaitCallback* callback_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopHandlerImpl);
-};
-
-}  // namespace
-
-BindingsSupportImpl::BindingsSupportImpl() {
-}
-
-BindingsSupportImpl::~BindingsSupportImpl() {
-}
-
-// static
-void BindingsSupportImpl::SetUp() {
-  assert(!tls_buffer);
-  tls_buffer = new ThreadLocalPointer<Buffer>;
-}
-
-// static
-void BindingsSupportImpl::TearDown() {
-  assert(tls_buffer);
-  delete tls_buffer;
-  tls_buffer = NULL;
-}
-
-Buffer* BindingsSupportImpl::GetCurrentBuffer() {
-  return tls_buffer->Get();
-}
-
-Buffer* BindingsSupportImpl::SetCurrentBuffer(Buffer* buf) {
-  Buffer* old_buf = tls_buffer->Get();
-  tls_buffer->Set(buf);
-  return old_buf;
-}
-
-BindingsSupport::AsyncWaitID BindingsSupportImpl::AsyncWait(
-    const Handle& handle,
-    MojoWaitFlags flags,
-    AsyncWaitCallback* callback) {
-  RunLoop* run_loop = RunLoop::current();
-  assert(run_loop);
-  // |run_loop_handler| is destroyed either when the handle is ready or if
-  // CancelWait is invoked.
-  RunLoopHandlerImpl* run_loop_handler =
-      new RunLoopHandlerImpl(handle, callback);
-  run_loop->AddHandler(run_loop_handler, handle, flags,
-                       MOJO_DEADLINE_INDEFINITE);
-  return run_loop_handler;
-}
-
-void BindingsSupportImpl::CancelWait(AsyncWaitID async_wait_id) {
-  delete static_cast<RunLoopHandlerImpl*>(async_wait_id);
-}
-
-}  // namespace internal
-}  // namespace mojo
diff --git a/mojo/public/utility/bindings_support_impl.h b/mojo/public/utility/bindings_support_impl.h
deleted file mode 100644
index 6216227..0000000
--- a/mojo/public/utility/bindings_support_impl.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 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 MOJO_PUBLIC_UTILITY_BINDINGS_SUPPORT_IMPL_H_
-#define MOJO_PUBLIC_UTILITY_BINDINGS_SUPPORT_IMPL_H_
-
-#include "mojo/public/bindings/lib/bindings_support.h"
-#include "mojo/public/system/macros.h"
-
-namespace mojo {
-namespace internal {
-
-// BindingsSupport implementation that uses RunLoop. Before using this you must
-// have created a RunLoop on the current thread.
-// You shouldn't create this directly, instead use Environment.
-class BindingsSupportImpl : public BindingsSupport {
- public:
-  BindingsSupportImpl();
-  virtual ~BindingsSupportImpl();
-
-  // Sets up state needed for BindingsSupportImpl. This must be invoked before
-  // creating a BindingsSupportImpl.
-  static void SetUp();
-
-  // Cleans state created by Setup().
-  static void TearDown();
-
-  // BindingsSupport methods:
-  virtual Buffer* GetCurrentBuffer() MOJO_OVERRIDE;
-  virtual Buffer* SetCurrentBuffer(Buffer* buf) MOJO_OVERRIDE;
-  virtual AsyncWaitID AsyncWait(const Handle& handle,
-                                MojoWaitFlags flags,
-                                AsyncWaitCallback* callback) MOJO_OVERRIDE;
-  virtual void CancelWait(AsyncWaitID async_wait_id) MOJO_OVERRIDE;
-
- private:
-  MOJO_DISALLOW_COPY_AND_ASSIGN(BindingsSupportImpl);
-};
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_UTILITY_BINDINGS_SUPPORT_IMPL_H_
diff --git a/mojo/public/utility/environment.cc b/mojo/public/utility/environment.cc
deleted file mode 100644
index b492030..0000000
--- a/mojo/public/utility/environment.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2013 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 "mojo/public/utility/environment.h"
-
-#include "mojo/public/utility/bindings_support_impl.h"
-#include "mojo/public/utility/run_loop.h"
-
-namespace mojo {
-
-Environment::Environment() : bindings_support_(NULL) {
-  RunLoop::SetUp();
-
-  internal::BindingsSupportImpl::SetUp();
-  bindings_support_ = new internal::BindingsSupportImpl;
-  BindingsSupport::Set(bindings_support_);
-}
-
-Environment::~Environment() {
-  // Allow for someone to have replaced BindingsSupport.
-  if (BindingsSupport::Get() == bindings_support_)
-    BindingsSupport::Set(NULL);
-  delete bindings_support_;
-  internal::BindingsSupportImpl::TearDown();
-
-  RunLoop::TearDown();
-}
-
-}  // namespace mojo
diff --git a/mojo/public/utility/environment.h b/mojo/public/utility/environment.h
deleted file mode 100644
index e7ea6a73..0000000
--- a/mojo/public/utility/environment.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 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 MOJO_PUBLIC_UTILITY_ENVIRONMENT_H_
-#define MOJO_PUBLIC_UTILITY_ENVIRONMENT_H_
-
-#include "mojo/public/system/macros.h"
-
-namespace mojo {
-
-namespace internal {
-class BindingsSupportImpl;
-}  // namespace internal
-
-class RunLoop;
-
-// Use Environment to cofigure state.
-class Environment {
- public:
-  Environment();
-  ~Environment();
-
- private:
-  internal::BindingsSupportImpl* bindings_support_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(Environment);
-};
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_UTILITY_ENVIRONMENT_H_
diff --git a/mojo/public/utility/run_loop.cc b/mojo/public/utility/run_loop.cc
index 56f7c42..bec828d 100644
--- a/mojo/public/utility/run_loop.cc
+++ b/mojo/public/utility/run_loop.cc
@@ -103,7 +103,21 @@
   RunState run_state;
   run_state_ = &run_state;
   while (!run_state.should_quit)
-    Wait();
+    Wait(false);
+  run_state_ = old_state;
+}
+
+void RunLoop::RunUntilIdle() {
+  assert(current() == this);
+  // We don't currently support nesting.
+  assert(!run_state_);
+  RunState* old_state = run_state_;
+  RunState run_state;
+  run_state_ = &run_state;
+  while (!run_state.should_quit) {
+    if (!Wait(true))
+      break;
+  }
   run_state_ = old_state;
 }
 
@@ -113,11 +127,11 @@
     run_state_->should_quit = true;
 }
 
-void RunLoop::Wait() {
-  const WaitState wait_state = GetWaitState();
+bool RunLoop::Wait(bool non_blocking) {
+  const WaitState wait_state = GetWaitState(non_blocking);
   if (wait_state.handles.empty()) {
     Quit();
-    return;
+    return false;
   }
 
   const MojoResult result =
@@ -128,23 +142,24 @@
            handler_data_.end());
     handler_data_[wait_state.handles[index]].handler->OnHandleReady(
         wait_state.handles[index]);
-  } else {
-    switch (result) {
-      case MOJO_RESULT_INVALID_ARGUMENT:
-      case MOJO_RESULT_FAILED_PRECONDITION:
-        RemoveFirstInvalidHandle(wait_state);
-        break;
-      case MOJO_RESULT_DEADLINE_EXCEEDED:
-        break;
-      default:
-        assert(false);
-    }
+    return true;
   }
 
-  NotifyDeadlineExceeded();
+  switch (result) {
+    case MOJO_RESULT_INVALID_ARGUMENT:
+    case MOJO_RESULT_FAILED_PRECONDITION:
+      return RemoveFirstInvalidHandle(wait_state);
+    case MOJO_RESULT_DEADLINE_EXCEEDED:
+      return NotifyDeadlineExceeded();
+  }
+
+  assert(false);
+  return false;
 }
 
-void RunLoop::NotifyDeadlineExceeded() {
+bool RunLoop::NotifyDeadlineExceeded() {
+  bool notified = false;
+
   // Make a copy in case someone tries to add/remove new handlers as part of
   // notifying.
   const HandleToHandlerData cloned_handlers(handler_data_);
@@ -159,11 +174,14 @@
         handler_data_[i->first].id == i->second.id) {
       handler_data_.erase(i->first);
       i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED);
+      notified = true;
     }
   }
+
+  return notified;
 }
 
-void RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
+bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
   for (size_t i = 0; i < wait_state.handles.size(); ++i) {
     const MojoResult result =
         mojo::Wait(wait_state.handles[i], wait_state.wait_flags[i],
@@ -177,26 +195,28 @@
           handler_data_[wait_state.handles[i]].handler;
       handler_data_.erase(wait_state.handles[i]);
       handler->OnHandleError(wait_state.handles[i], result);
-      return;
-    } else {
-      assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
+      return true;
     }
+    assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
   }
+  return false;
 }
 
-RunLoop::WaitState RunLoop::GetWaitState() const {
+RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
   WaitState wait_state;
   MojoTimeTicks min_time = kInvalidTimeTicks;
   for (HandleToHandlerData::const_iterator i = handler_data_.begin();
        i != handler_data_.end(); ++i) {
     wait_state.handles.push_back(i->first);
     wait_state.wait_flags.push_back(i->second.wait_flags);
-    if (i->second.deadline != kInvalidTimeTicks &&
+    if (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
         (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
       min_time = i->second.deadline;
     }
   }
-  if (min_time != kInvalidTimeTicks) {
+  if (non_blocking) {
+    wait_state.deadline = static_cast<MojoDeadline>(0);
+  } else if (min_time != kInvalidTimeTicks) {
     const MojoTimeTicks now = GetTimeTicksNow();
     if (min_time < now)
       wait_state.deadline = static_cast<MojoDeadline>(0);
diff --git a/mojo/public/utility/run_loop.h b/mojo/public/utility/run_loop.h
index 49c8c2d..be39edb2 100644
--- a/mojo/public/utility/run_loop.h
+++ b/mojo/public/utility/run_loop.h
@@ -41,6 +41,12 @@
   // Runs the loop servicing handles as they are ready. This returns when Quit()
   // is invoked, or there no more handles.
   void Run();
+
+  // Runs the loop servicing any handles that are ready. Does not wait for
+  // handles to become ready before returning. Returns early if Quit() is
+  // invoked.
+  void RunUntilIdle();
+
   void Quit();
 
  private:
@@ -65,18 +71,21 @@
   typedef std::map<Handle, HandlerData> HandleToHandlerData;
 
   // Waits for a handle to be ready. Returns after servicing at least one
-  // handle (or there are no more handles).
-  void Wait();
+  // handle (or there are no more handles) unless |non_blocking| is true,
+  // in which case it will also return if servicing at least one handle
+  // would require blocking. Returns true if a RunLoopHandler was notified.
+  bool Wait(bool non_blocking);
 
-  // Notifies any handlers whose deadline has expired.
-  void NotifyDeadlineExceeded();
+  // Notifies any handlers whose deadline has expired. Returns true if a
+  // RunLoopHandler was notified.
+  bool NotifyDeadlineExceeded();
 
   // Removes the first invalid handle. This is called if MojoWaitMany() finds an
-  // invalid handle.
-  void RemoveFirstInvalidHandle(const WaitState& wait_state);
+  // invalid handle. Returns true if a RunLoopHandler was notified.
+  bool RemoveFirstInvalidHandle(const WaitState& wait_state);
 
   // Returns the state needed to pass to WaitMany().
-  WaitState GetWaitState() const;
+  WaitState GetWaitState(bool non_blocking) const;
 
   HandleToHandlerData handler_data_;
 
diff --git a/mojo/services/native_viewport/native_viewport_service.cc b/mojo/services/native_viewport/native_viewport_service.cc
index 0352ddf..4a375ea2 100644
--- a/mojo/services/native_viewport/native_viewport_service.cc
+++ b/mojo/services/native_viewport/native_viewport_service.cc
@@ -6,7 +6,6 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/services/gles2/gles2_impl.h"
 #include "mojo/services/native_viewport/native_viewport.h"
 #include "mojom/native_viewport.h"
@@ -182,15 +181,10 @@
 
 extern "C" MOJO_NATIVE_VIEWPORT_EXPORT MojoResult MojoMain(
     const MojoHandle shell_handle) {
-  mojo::common::BindingsSupportImpl bindings_support_impl;
-  mojo::BindingsSupport::Set(&bindings_support_impl);
-
   base::MessageLoopForUI loop;
   mojo::services::NativeViewportService app(
       mojo::MakeScopedHandle(mojo::MessagePipeHandle(shell_handle)).Pass());
   base::MessageLoop::current()->Run();
-
-  mojo::BindingsSupport::Set(NULL);
   return MOJO_RESULT_OK;
 }
 
diff --git a/mojo/shell/context.cc b/mojo/shell/context.cc
index 2cb8a54f..3f136c25 100644
--- a/mojo/shell/context.cc
+++ b/mojo/shell/context.cc
@@ -20,14 +20,12 @@
               scoped_ptr<net::NetworkDelegate>(new NetworkDelegate()),
               storage_.profile_path()) {
   embedder::Init();
-  BindingsSupport::Set(&bindings_support_impl_);
   dynamic_service_loader_.reset(new DynamicServiceLoader(this));
   service_manager_.set_default_loader(dynamic_service_loader_.get());
 }
 
 Context::~Context() {
   service_manager_.set_default_loader(NULL);
-  BindingsSupport::Set(NULL);
 }
 
 }  // namespace shell
diff --git a/mojo/shell/context.h b/mojo/shell/context.h
index 566440f..2a4c5c2 100644
--- a/mojo/shell/context.h
+++ b/mojo/shell/context.h
@@ -5,7 +5,6 @@
 #ifndef MOJO_SHELL_CONTEXT_H_
 #define MOJO_SHELL_CONTEXT_H_
 
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/shell/loader.h"
 #include "mojo/shell/service_manager.h"
 #include "mojo/shell/storage.h"
@@ -40,7 +39,6 @@
   Storage storage_;
   Loader loader_;
   ServiceManager service_manager_;
-  common::BindingsSupportImpl bindings_support_impl_;
   scoped_ptr<DynamicServiceLoader> dynamic_service_loader_;
 
 #if defined(OS_ANDROID)
diff --git a/mojo/shell/service_manager_unittest.cc b/mojo/shell/service_manager_unittest.cc
index 9573694..549d7622 100644
--- a/mojo/shell/service_manager_unittest.cc
+++ b/mojo/shell/service_manager_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/message_loop/message_loop.h"
-#include "mojo/common/bindings_support_impl.h"
 #include "mojo/public/bindings/lib/remote_ptr.h"
 #include "mojo/shell/service_manager.h"
 #include "mojom/shell.h"
@@ -81,7 +80,6 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    mojo::BindingsSupport::Set(&support_);
     GURL test_url("test:testService");
     service_manager_.reset(new ServiceManager);
     service_manager_->SetLoaderForURL(this, test_url);
@@ -94,7 +92,6 @@
     test_client_.reset(NULL);
     test_app_.reset(NULL);
     service_manager_.reset(NULL);
-    mojo::BindingsSupport::Set(NULL);
   }
 
   virtual void Load(const GURL& url,
@@ -103,7 +100,6 @@
   }
 
  protected:
-  common::BindingsSupportImpl support_;
   base::MessageLoop loop_;
   scoped_ptr<TestApp> test_app_;
   scoped_ptr<TestClientImpl> test_client_;
diff --git a/mojo/tools/mojob.sh b/mojo/tools/mojob.sh
index 5d99a6a..ae05015 100755
--- a/mojo/tools/mojob.sh
+++ b/mojo/tools/mojob.sh
@@ -50,11 +50,11 @@
   "out/$1/mojo_common_unittests" || exit 1
   "out/$1/mojo_js_unittests" || exit 1
   "out/$1/mojo_public_bindings_unittests" || exit 1
+  "out/$1/mojo_public_environment_unittests" || exit 1
   "out/$1/mojo_public_system_unittests" || exit 1
   "out/$1/mojo_public_utility_unittests" || exit 1
   "out/$1/mojo_shell_unittests" || exit 1
   "out/$1/mojo_system_unittests" || exit 1
-  "out/$1/mojo_utility_unittests" || exit 1
 }
 
 do_perftests() {