summaryrefslogtreecommitdiffstats
path: root/mojo/public/cpp/utility/lib
diff options
context:
space:
mode:
authorrockot <rockot@chromium.org>2015-11-12 17:33:59 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-13 01:34:47 +0000
commit85dce086001825a2faa4e75755a669f5e08a1cad (patch)
tree722de1d974f799b3d1ee1ca4c81bb8b0fa75a95d /mojo/public/cpp/utility/lib
parent415b73b1a400a994a86e6f29709aa0271e895dd5 (diff)
downloadchromium_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.cc52
-rw-r--r--mojo/public/cpp/utility/lib/run_loop.cc267
-rw-r--r--mojo/public/cpp/utility/lib/thread.cc64
-rw-r--r--mojo/public/cpp/utility/lib/thread_local.h54
-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, 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