diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-29 00:39:26 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-29 00:39:26 +0000 |
commit | 3b3c6445122bf8144b08c94c42db00f6079e4c77 (patch) | |
tree | 8483986e8a9b4696543b1606c8fa1f28745dbcf0 /mojo/public/cpp/utility/lib | |
parent | e97a6074124c0bbb4e57316e754b64e3eb0a8ee1 (diff) | |
download | chromium_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.cc | 52 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/run_loop.cc | 224 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread.cc | 69 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread_local.h | 61 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread_local_posix.cc | 39 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread_local_win.cc | 39 |
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 |