diff options
author | rockot <rockot@chromium.org> | 2015-11-12 17:33:59 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-13 01:34:47 +0000 |
commit | 85dce086001825a2faa4e75755a669f5e08a1cad (patch) | |
tree | 722de1d974f799b3d1ee1ca4c81bb8b0fa75a95d /mojo/public/cpp/utility/lib | |
parent | 415b73b1a400a994a86e6f29709aa0271e895dd5 (diff) | |
download | chromium_src-85dce086001825a2faa4e75755a669f5e08a1cad.zip chromium_src-85dce086001825a2faa4e75755a669f5e08a1cad.tar.gz chromium_src-85dce086001825a2faa4e75755a669f5e08a1cad.tar.bz2 |
Move third_party/mojo/src/mojo/public to mojo/public
BUG=None
NOPRESUBMIT=true
Review URL: https://codereview.chromium.org/1410053006
Cr-Commit-Position: refs/heads/master@{#359461}
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 | 267 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread.cc | 64 | ||||
-rw-r--r-- | mojo/public/cpp/utility/lib/thread_local.h | 54 | ||||
-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, 515 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..7faf748 --- /dev/null +++ b/mojo/public/cpp/utility/lib/run_loop.cc @@ -0,0 +1,267 @@ +// 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<MojoHandleSignals> handle_signals; + MojoDeadline deadline; +}; + +struct RunLoop::RunState { + RunState() : should_quit(false) {} + + bool should_quit; +}; + +RunLoop::RunLoop() + : run_state_(nullptr), next_handler_id_(0), next_sequence_number_(0) { + assert(!current()); + current_run_loop.Set(this); +} + +RunLoop::~RunLoop() { + assert(current() == this); + NotifyHandlers(MOJO_RESULT_ABORTED, IGNORE_DEADLINE); + current_run_loop.Set(nullptr); +} + +// 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, + MojoHandleSignals handle_signals, + 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.handle_signals = handle_signals; + 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() { + RunInternal(UNTIL_EMPTY); +} + +void RunLoop::RunUntilIdle() { + RunInternal(UNTIL_IDLE); +} + +void RunLoop::RunInternal(RunMode run_mode) { + assert(current() == this); + RunState* old_state = run_state_; + RunState run_state; + run_state_ = &run_state; + for (;;) { + bool did_work = DoDelayedWork(); + if (run_state.should_quit) + break; + did_work |= Wait(run_mode == UNTIL_IDLE); + if (run_state.should_quit) + break; + if (!did_work && run_mode == UNTIL_IDLE) + break; + } + run_state_ = old_state; +} + +bool RunLoop::DoDelayedWork() { + MojoTimeTicks now = GetTimeTicksNow(); + if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) { + PendingTask task = delayed_tasks_.top(); + delayed_tasks_.pop(); + task.task.Run(); + return true; + } + return false; +} + +void RunLoop::Quit() { + assert(current() == this); + if (run_state_) + run_state_->should_quit = true; +} + +void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) { + assert(current() == this); + MojoTimeTicks run_time = delay + GetTimeTicksNow(); + delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++)); +} + +bool RunLoop::Wait(bool non_blocking) { + const WaitState wait_state = GetWaitState(non_blocking); + if (wait_state.handles.empty()) { + if (delayed_tasks_.empty()) + Quit(); + return false; + } + + const WaitManyResult wmr = + WaitMany(wait_state.handles, wait_state.handle_signals, + wait_state.deadline, nullptr); + + if (!wmr.IsIndexValid()) { + assert(wmr.result == MOJO_RESULT_DEADLINE_EXCEEDED); + return NotifyHandlers(MOJO_RESULT_DEADLINE_EXCEEDED, CHECK_DEADLINE); + } + + Handle handle = wait_state.handles[wmr.index]; + assert(handler_data_.find(handle) != handler_data_.end()); + RunLoopHandler* handler = handler_data_[handle].handler; + + switch (wmr.result) { + case MOJO_RESULT_OK: + handler->OnHandleReady(handle); + return true; + case MOJO_RESULT_INVALID_ARGUMENT: + case MOJO_RESULT_FAILED_PRECONDITION: + // Remove the handle first, this way if OnHandleError() tries to remove + // the handle our iterator isn't invalidated. + handler_data_.erase(handle); + handler->OnHandleError(handle, wmr.result); + return true; + default: + assert(false); + return false; + } +} + +bool RunLoop::NotifyHandlers(MojoResult error, CheckDeadline check) { + 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) { + // Only check deadline exceeded if that's what we're notifying. + if (check == CHECK_DEADLINE && + (i->second.deadline == kInvalidTimeTicks || i->second.deadline > now)) { + continue; + } + + // Since we're iterating over a clone of the handlers, verify the handler + // is still valid before notifying. + if (handler_data_.find(i->first) == handler_data_.end() || + handler_data_[i->first].id != i->second.id) { + continue; + } + + RunLoopHandler* handler = i->second.handler; + handler_data_.erase(i->first); + handler->OnHandleError(i->first, error); + notified = true; + } + + return notified; +} + +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.handle_signals.push_back(i->second.handle_signals); + if (!non_blocking && i->second.deadline != kInvalidTimeTicks && + (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { + min_time = i->second.deadline; + } + } + if (!delayed_tasks_.empty()) { + MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time; + if (min_time == kInvalidTimeTicks) + min_time = delayed_min_time; + else + min_time = std::min(min_time, delayed_min_time); + } + 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; +} + +RunLoop::PendingTask::PendingTask(const Closure& task, + MojoTimeTicks run_time, + uint64_t sequence_number) + : task(task), run_time(run_time), sequence_number(sequence_number) { +} + +RunLoop::PendingTask::~PendingTask() { +} + +bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const { + if (run_time != other.run_time) { + // std::priority_queue<> puts the least element at the end of the queue. We + // want the soonest eligible task to be at the head of the queue, so + // run_times further in the future are considered lesser. + return run_time > other.run_time; + } + + return sequence_number > other.sequence_number; +} + +} // 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..40f0bdd --- /dev/null +++ b/mojo/public/cpp/utility/lib/thread.cc @@ -0,0 +1,64 @@ +// 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 = pthread_attr_init(&attr); + MOJO_ALLOW_UNUSED_LOCAL(rv); + 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 = pthread_join(thread_, nullptr); + MOJO_ALLOW_UNUSED_LOCAL(rv); + assert(rv == 0); +} + +// static +void* Thread::ThreadRunTrampoline(void* arg) { + Thread* self = static_cast<Thread*>(arg); + self->Run(); + return nullptr; +} + +} // 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..f5461ee --- /dev/null +++ b/mojo/public/cpp/utility/lib/thread_local.h @@ -0,0 +1,54 @@ +// 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..ea7343e --- /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, nullptr) != 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..b8239cb --- /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 <windows.h> +#include <assert.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 |