summaryrefslogtreecommitdiffstats
path: root/mojo/public/cpp/utility
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-29 00:39:26 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-29 00:39:26 +0000
commit3b3c6445122bf8144b08c94c42db00f6079e4c77 (patch)
tree8483986e8a9b4696543b1606c8fa1f28745dbcf0 /mojo/public/cpp/utility
parente97a6074124c0bbb4e57316e754b64e3eb0a8ee1 (diff)
downloadchromium_src-3b3c6445122bf8144b08c94c42db00f6079e4c77.zip
chromium_src-3b3c6445122bf8144b08c94c42db00f6079e4c77.tar.gz
chromium_src-3b3c6445122bf8144b08c94c42db00f6079e4c77.tar.bz2
Mojo: Move mojo/public/utility to mojo/public/cpp/utility.
R=sky@chromium.org Review URL: https://codereview.chromium.org/217443002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260324 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/public/cpp/utility')
-rw-r--r--mojo/public/cpp/utility/lib/mutex.cc52
-rw-r--r--mojo/public/cpp/utility/lib/run_loop.cc224
-rw-r--r--mojo/public/cpp/utility/lib/thread.cc69
-rw-r--r--mojo/public/cpp/utility/lib/thread_local.h61
-rw-r--r--mojo/public/cpp/utility/lib/thread_local_posix.cc39
-rw-r--r--mojo/public/cpp/utility/lib/thread_local_win.cc39
-rw-r--r--mojo/public/cpp/utility/mutex.h70
-rw-r--r--mojo/public/cpp/utility/run_loop.h108
-rw-r--r--mojo/public/cpp/utility/run_loop_handler.h25
-rw-r--r--mojo/public/cpp/utility/thread.h62
10 files changed, 749 insertions, 0 deletions
diff --git a/mojo/public/cpp/utility/lib/mutex.cc b/mojo/public/cpp/utility/lib/mutex.cc
new file mode 100644
index 0000000..23370e1
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/mutex.cc
@@ -0,0 +1,52 @@
+// 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/cpp/utility/mutex.h"
+
+#include <assert.h>
+#include <errno.h>
+
+namespace mojo {
+
+// Release builds have inlined (non-error-checking) definitions in the header.
+#if !defined(NDEBUG)
+Mutex::Mutex() {
+ pthread_mutexattr_t mutexattr;
+ int rv = pthread_mutexattr_init(&mutexattr);
+ assert(rv == 0);
+ rv = pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
+ assert(rv == 0);
+ rv = pthread_mutex_init(&mutex_, &mutexattr);
+ assert(rv == 0);
+ rv = pthread_mutexattr_destroy(&mutexattr);
+ assert(rv == 0);
+}
+
+Mutex::~Mutex() {
+ int rv = pthread_mutex_destroy(&mutex_);
+ assert(rv == 0);
+}
+
+void Mutex::Lock() {
+ int rv = pthread_mutex_lock(&mutex_);
+ assert(rv == 0);
+}
+
+void Mutex::Unlock() {
+ int rv = pthread_mutex_unlock(&mutex_);
+ assert(rv == 0);
+}
+
+bool Mutex::TryLock() {
+ int rv = pthread_mutex_trylock(&mutex_);
+ assert(rv == 0 || rv == EBUSY);
+ return rv == 0;
+}
+
+void Mutex::AssertHeld() {
+ assert(pthread_mutex_lock(&mutex_) == EDEADLK);
+}
+#endif // !defined(NDEBUG)
+
+} // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc
new file mode 100644
index 0000000..2bf6a07
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/run_loop.cc
@@ -0,0 +1,224 @@
+// 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/cpp/utility/run_loop.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "mojo/public/cpp/utility/lib/thread_local.h"
+#include "mojo/public/cpp/utility/run_loop_handler.h"
+
+namespace mojo {
+namespace {
+
+internal::ThreadLocalPointer<RunLoop> current_run_loop;
+
+const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0);
+
+} // namespace
+
+// State needed for one iteration of WaitMany().
+struct RunLoop::WaitState {
+ WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {}
+
+ std::vector<Handle> handles;
+ std::vector<MojoWaitFlags> wait_flags;
+ MojoDeadline deadline;
+};
+
+struct RunLoop::RunState {
+ RunState() : should_quit(false) {}
+
+ bool should_quit;
+};
+
+RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) {
+ assert(!current());
+ current_run_loop.Set(this);
+}
+
+RunLoop::~RunLoop() {
+ assert(current() == this);
+ current_run_loop.Set(NULL);
+}
+
+// static
+void RunLoop::SetUp() {
+ current_run_loop.Allocate();
+}
+
+// static
+void RunLoop::TearDown() {
+ assert(!current());
+ current_run_loop.Free();
+}
+
+// static
+RunLoop* RunLoop::current() {
+ return current_run_loop.Get();
+}
+
+void RunLoop::AddHandler(RunLoopHandler* handler,
+ const Handle& handle,
+ MojoWaitFlags wait_flags,
+ MojoDeadline deadline) {
+ assert(current() == this);
+ assert(handler);
+ assert(handle.is_valid());
+ // Assume it's an error if someone tries to reregister an existing handle.
+ assert(0u == handler_data_.count(handle));
+ HandlerData handler_data;
+ handler_data.handler = handler;
+ handler_data.wait_flags = wait_flags;
+ handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ?
+ kInvalidTimeTicks :
+ GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline);
+ handler_data.id = next_handler_id_++;
+ handler_data_[handle] = handler_data;
+}
+
+void RunLoop::RemoveHandler(const Handle& handle) {
+ assert(current() == this);
+ handler_data_.erase(handle);
+}
+
+bool RunLoop::HasHandler(const Handle& handle) const {
+ return handler_data_.find(handle) != handler_data_.end();
+}
+
+void RunLoop::Run() {
+ 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)
+ 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;
+}
+
+void RunLoop::Quit() {
+ assert(current() == this);
+ if (run_state_)
+ run_state_->should_quit = true;
+}
+
+bool RunLoop::Wait(bool non_blocking) {
+ const WaitState wait_state = GetWaitState(non_blocking);
+ if (wait_state.handles.empty()) {
+ Quit();
+ return false;
+ }
+
+ const MojoResult result =
+ WaitMany(wait_state.handles, wait_state.wait_flags, wait_state.deadline);
+ if (result >= 0) {
+ const size_t index = static_cast<size_t>(result);
+ assert(handler_data_.find(wait_state.handles[index]) !=
+ handler_data_.end());
+ handler_data_[wait_state.handles[index]].handler->OnHandleReady(
+ wait_state.handles[index]);
+ return true;
+ }
+
+ 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;
+}
+
+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_);
+ const MojoTimeTicks now(GetTimeTicksNow());
+ for (HandleToHandlerData::const_iterator i = cloned_handlers.begin();
+ i != cloned_handlers.end(); ++i) {
+ // Since we're iterating over a clone of the handlers, verify the handler is
+ // still valid before notifying.
+ if (i->second.deadline != kInvalidTimeTicks &&
+ i->second.deadline < now &&
+ handler_data_.find(i->first) != handler_data_.end() &&
+ 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;
+}
+
+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],
+ static_cast<MojoDeadline>(0));
+ if (result == MOJO_RESULT_INVALID_ARGUMENT ||
+ result == MOJO_RESULT_FAILED_PRECONDITION) {
+ // Remove the handle first, this way if OnHandleError() tries to remove
+ // the handle our iterator isn't invalidated.
+ assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end());
+ RunLoopHandler* handler =
+ handler_data_[wait_state.handles[i]].handler;
+ handler_data_.erase(wait_state.handles[i]);
+ handler->OnHandleError(wait_state.handles[i], result);
+ return true;
+ }
+ assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
+ }
+ return false;
+}
+
+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 (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
+ (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
+ min_time = i->second.deadline;
+ }
+ }
+ 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);
+ else
+ wait_state.deadline = static_cast<MojoDeadline>(min_time - now);
+ }
+ return wait_state;
+}
+
+} // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread.cc b/mojo/public/cpp/utility/lib/thread.cc
new file mode 100644
index 0000000..da33497
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread.cc
@@ -0,0 +1,69 @@
+// 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/cpp/utility/thread.h"
+
+#include <assert.h>
+
+namespace mojo {
+
+Thread::Thread()
+ : options_(),
+ thread_(),
+ started_(false),
+ joined_(false) {
+}
+
+Thread::Thread(const Options& options)
+ : options_(options),
+ thread_(),
+ started_(false),
+ joined_(false) {
+}
+
+Thread::~Thread() {
+ // If it was started, it must have been joined.
+ assert(!started_ || joined_);
+}
+
+void Thread::Start() {
+ assert(!started_);
+ assert(!joined_);
+
+ pthread_attr_t attr;
+ int rv MOJO_ALLOW_UNUSED = pthread_attr_init(&attr);
+ assert(rv == 0);
+
+ // Non-default stack size?
+ if (options_.stack_size() != 0) {
+ rv = pthread_attr_setstacksize(&attr, options_.stack_size());
+ assert(rv == 0);
+ }
+
+ started_ = true;
+ rv = pthread_create(&thread_, &attr, &ThreadRunTrampoline, this);
+ assert(rv == 0);
+
+ rv = pthread_attr_destroy(&attr);
+ assert(rv == 0);
+}
+
+void Thread::Join() {
+ // Must have been started but not yet joined.
+ assert(started_);
+ assert(!joined_);
+
+ joined_ = true;
+ int rv MOJO_ALLOW_UNUSED = pthread_join(thread_, NULL);
+ assert(rv == 0);
+}
+
+// static
+void* Thread::ThreadRunTrampoline(void* arg) {
+ Thread* self = static_cast<Thread*>(arg);
+ self->Run();
+ return NULL;
+}
+
+} // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread_local.h b/mojo/public/cpp/utility/lib/thread_local.h
new file mode 100644
index 0000000..4c3625d
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local.h
@@ -0,0 +1,61 @@
+// 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_CPP_UTILITY_LIB_THREAD_LOCAL_H_
+#define MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
+
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+namespace internal {
+
+// Helper functions that abstract the cross-platform APIs.
+struct ThreadLocalPlatform {
+#ifdef _WIN32
+ typedef unsigned long SlotType;
+#else
+ typedef pthread_key_t SlotType;
+#endif
+
+ static void AllocateSlot(SlotType* slot);
+ static void FreeSlot(SlotType slot);
+ static void* GetValueFromSlot(SlotType slot);
+ static void SetValueInSlot(SlotType slot, void* value);
+};
+
+// This class is intended to be statically allocated.
+template <typename P>
+class ThreadLocalPointer {
+ public:
+ ThreadLocalPointer() : slot_() {
+ }
+
+ void Allocate() {
+ ThreadLocalPlatform::AllocateSlot(&slot_);
+ }
+
+ void Free() {
+ ThreadLocalPlatform::FreeSlot(slot_);
+ }
+
+ P* Get() {
+ return static_cast<P*>(ThreadLocalPlatform::GetValueFromSlot(slot_));
+ }
+
+ void Set(P* value) {
+ ThreadLocalPlatform::SetValueInSlot(slot_, value);
+ }
+
+ private:
+ ThreadLocalPlatform::SlotType slot_;
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
diff --git a/mojo/public/cpp/utility/lib/thread_local_posix.cc b/mojo/public/cpp/utility/lib/thread_local_posix.cc
new file mode 100644
index 0000000..b33dfc6
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local_posix.cc
@@ -0,0 +1,39 @@
+// 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/cpp/utility/lib/thread_local.h"
+
+#include <assert.h>
+
+namespace mojo {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+ if (pthread_key_create(slot, NULL) != 0) {
+ assert(false);
+ }
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+ if (pthread_key_delete(slot) != 0) {
+ assert(false);
+ }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+ return pthread_getspecific(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+ if (pthread_setspecific(slot, value) != 0) {
+ assert(false);
+ }
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread_local_win.cc b/mojo/public/cpp/utility/lib/thread_local_win.cc
new file mode 100644
index 0000000..98841f7
--- /dev/null
+++ b/mojo/public/cpp/utility/lib/thread_local_win.cc
@@ -0,0 +1,39 @@
+// 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/cpp/utility/lib/thread_local.h"
+
+#include <assert.h>
+#include <windows.h>
+
+namespace mojo {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+ *slot = TlsAlloc();
+ assert(*slot != TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+ if (!TlsFree(slot)) {
+ assert(false);
+ }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+ return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+ if (!TlsSetValue(slot, value)) {
+ assert(false);
+ }
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/public/cpp/utility/mutex.h b/mojo/public/cpp/utility/mutex.h
new file mode 100644
index 0000000..35611c2
--- /dev/null
+++ b/mojo/public/cpp/utility/mutex.h
@@ -0,0 +1,70 @@
+// 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_CPP_UTILITY_MUTEX_H_
+#define MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_
+
+#ifdef _WIN32
+#error "Not implemented: See crbug.com/342893."
+#endif
+
+#include <pthread.h>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+#ifdef NDEBUG
+// Note: Make a C++ constant for |PTHREAD_MUTEX_INITIALIZER|. (We can't directly
+// use the C macro in an initializer list, since it might expand to |{ ... }|.)
+namespace internal {
+const pthread_mutex_t kPthreadMutexInitializer = PTHREAD_MUTEX_INITIALIZER;
+}
+#endif
+
+class Mutex {
+ public:
+#ifdef NDEBUG
+ Mutex() : mutex_(internal::kPthreadMutexInitializer) {}
+ ~Mutex() { pthread_mutex_destroy(&mutex_); }
+
+ void Lock() { pthread_mutex_lock(&mutex_); }
+ void Unlock() { pthread_mutex_unlock(&mutex_); }
+ bool TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
+
+ void AssertHeld() {}
+#else
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+ bool TryLock();
+
+ void AssertHeld();
+#endif
+
+ private:
+ pthread_mutex_t mutex_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(Mutex);
+};
+
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); }
+ ~MutexLock() { mutex_->Unlock(); }
+
+ private:
+ Mutex* const mutex_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLock);
+};
+
+// Catch bug where variable name is omitted (e.g., |MutexLock (&mu)|).
+#define MutexLock(x) MOJO_COMPILE_ASSERT(0, mutex_lock_missing_variable_name);
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_UTILITY_MUTEX_H_
diff --git a/mojo/public/cpp/utility/run_loop.h b/mojo/public/cpp/utility/run_loop.h
new file mode 100644
index 0000000..288a68e
--- /dev/null
+++ b/mojo/public/cpp/utility/run_loop.h
@@ -0,0 +1,108 @@
+// 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_CPP_UTILITY_RUN_LOOP_H_
+#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
+
+#include <map>
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+class RunLoopHandler;
+
+class RunLoop {
+ public:
+ RunLoop();
+ ~RunLoop();
+
+ // Sets up state needed for RunLoop. This must be invoked before creating a
+ // RunLoop.
+ static void SetUp();
+
+ // Cleans state created by Setup().
+ static void TearDown();
+
+ // Returns the RunLoop for the current thread. Returns NULL if not yet
+ // created.
+ static RunLoop* current();
+
+ // Registers a RunLoopHandler for the specified handle. Only one handler can
+ // be registered for a specified handle.
+ void AddHandler(RunLoopHandler* handler,
+ const Handle& handle,
+ MojoWaitFlags wait_flags,
+ MojoDeadline deadline);
+ void RemoveHandler(const Handle& handle);
+ bool HasHandler(const Handle& handle) const;
+
+ // 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:
+ struct RunState;
+ struct WaitState;
+
+ // Contains the data needed to track a request to AddHandler().
+ struct HandlerData {
+ HandlerData()
+ : handler(NULL),
+ wait_flags(MOJO_WAIT_FLAG_NONE),
+ deadline(0),
+ id(0) {}
+
+ RunLoopHandler* handler;
+ MojoWaitFlags wait_flags;
+ MojoTimeTicks deadline;
+ // See description of |RunLoop::next_handler_id_| for details.
+ int id;
+ };
+
+ 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) 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. Returns true if a
+ // RunLoopHandler was notified.
+ bool NotifyDeadlineExceeded();
+
+ // Removes the first invalid handle. This is called if MojoWaitMany() finds an
+ // 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(bool non_blocking) const;
+
+ HandleToHandlerData handler_data_;
+
+ // If non-NULL we're running (inside Run()). Member references a value on the
+ // stack.
+ RunState* run_state_;
+
+ // An ever increasing value assigned to each HandlerData::id. Used to detect
+ // uniqueness while notifying. That is, while notifying expired timers we copy
+ // |handler_data_| and only notify handlers whose id match. If the id does not
+ // match it means the handler was removed then added so that we shouldn't
+ // notify it.
+ int next_handler_id_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
diff --git a/mojo/public/cpp/utility/run_loop_handler.h b/mojo/public/cpp/utility/run_loop_handler.h
new file mode 100644
index 0000000..69838d5
--- /dev/null
+++ b/mojo/public/cpp/utility/run_loop_handler.h
@@ -0,0 +1,25 @@
+// 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_CPP_UTILITY_RUN_LOOP_HANDLER_H_
+#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_
+
+#include "mojo/public/cpp/system/core.h"
+
+namespace mojo {
+
+// Used by RunLoop to notify when a handle is either ready or has become
+// invalid.
+class RunLoopHandler {
+ public:
+ virtual void OnHandleReady(const Handle& handle) = 0;
+ virtual void OnHandleError(const Handle& handle, MojoResult result) = 0;
+
+ protected:
+ virtual ~RunLoopHandler() {}
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_HANDLER_H_
diff --git a/mojo/public/cpp/utility/thread.h b/mojo/public/cpp/utility/thread.h
new file mode 100644
index 0000000..b7d10ee
--- /dev/null
+++ b/mojo/public/cpp/utility/thread.h
@@ -0,0 +1,62 @@
+// 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_CPP_UTILITY_THREAD_H_
+#define MOJO_PUBLIC_CPP_UTILITY_THREAD_H_
+
+#ifdef _WIN32
+#error "Not implemented: See crbug.com/342893."
+#endif
+
+#include <pthread.h>
+#include <stddef.h>
+
+#include "mojo/public/cpp/system/macros.h"
+
+namespace mojo {
+
+// This class is thread-friendly, not thread-safe (e.g., you mustn't call
+// |Join()| from multiple threads and/or simultaneously try to destroy the
+// object).
+class Thread {
+ public:
+ // TODO(vtl): Support non-joinable? priority?
+ class Options {
+ public:
+ Options() : stack_size_(0) {}
+
+ // A stack size of 0 means the default.
+ size_t stack_size() const { return stack_size_; }
+ void set_stack_size(size_t stack_size) { stack_size_ = stack_size; }
+
+ private:
+ size_t stack_size_;
+
+ // Copy and assign allowed.
+ };
+
+ // TODO(vtl): Add name or name prefix?
+ Thread();
+ explicit Thread(const Options& options);
+ virtual ~Thread();
+
+ void Start();
+ void Join();
+
+ virtual void Run() = 0;
+
+ private:
+ static void* ThreadRunTrampoline(void* arg);
+
+ const Options options_;
+ pthread_t thread_;
+ bool started_;
+ bool joined_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_UTILITY_THREAD_H_