summaryrefslogtreecommitdiffstats
path: root/mojo/public/cpp/utility/lib
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/lib
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/lib')
-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
6 files changed, 484 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