Index: ui/gfx/shared_event.cc |
diff --git a/ui/gfx/shared_event.cc b/ui/gfx/shared_event.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b19d0329df127f934081e32bc2456e078f5aa9a4 |
--- /dev/null |
+++ b/ui/gfx/shared_event.cc |
@@ -0,0 +1,120 @@ |
+// Copyright 2016 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 "base/atomicops.h" |
+#include "base/macros.h" |
+#include "base/process/memory.h" |
+#include "base/time/time.h" |
+#include "ui/gfx/gfx_export.h" |
+#include "ui/gfx/shared_event.h" |
+ |
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+#include <linux/futex.h> |
+#include <stdint.h> |
+#include <sys/syscall.h> |
+#else |
+#include "base/threading/platform_thread.h" |
+#endif |
+ |
+namespace gfx { |
+namespace { |
+ |
+enum { NOT_SIGNALED = 0, WAITING, SIGNALED }; |
+ |
+constexpr size_t kSharedMemorySize = sizeof(int32_t); |
ericrk
2017/03/10 03:04:39
I'm curious about the size efficiency here. From m
reveman
2017/03/13 12:33:05
Correct. Each fence will end up using one page of
|
+ |
+} // namespace |
+ |
+SharedEvent::SharedEvent() { |
+ bool rv = shared_memory_.CreateAndMapAnonymous(kSharedMemorySize); |
+ CHECK(rv); |
+} |
+ |
+SharedEvent::SharedEvent(const SharedEventHandle& handle) |
+ : shared_memory_(handle, false) { |
+ bool rv = shared_memory_.Map(kSharedMemorySize); |
+ CHECK(rv); |
+} |
+ |
+// static |
+SharedEventHandle SharedEvent::CreateForProcess(base::ProcessHandle process) { |
+ base::SharedMemory shared_memory; |
+ if (!shared_memory.CreateAnonymous(kSharedMemorySize)) |
+ return SharedEventHandle(); |
+ base::SharedMemoryHandle handle; |
+ shared_memory.GiveToProcess(process, &handle); |
+ return handle; |
+} |
+ |
+// static |
+SharedEventHandle SharedEvent::DuplicateHandle( |
+ const SharedEventHandle& handle) { |
+ return base::SharedMemory::DuplicateHandle(handle); |
+} |
+ |
+void SharedEvent::Reset() { |
+ // Change state to un-signaled iff event is currently in signaled state. |
+ base::subtle::NoBarrier_CompareAndSwap(uaddr(), SIGNALED, NOT_SIGNALED); |
+} |
+ |
+void SharedEvent::Signal() { |
+ // Change state to signaled and return early unless waiters exist that need |
+ // to be woken up. |
+ if (base::subtle::Release_CompareAndSwap(uaddr(), NOT_SIGNALED, SIGNALED) != |
+ WAITING) |
+ return; |
+ |
+ // Unconditionally change state to signaled before waking up waiters. |
+ base::subtle::Release_Store(uaddr(), SIGNALED); |
+ |
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+ // Perform non-blocking futex operation that will wake up all waiters. |
+ int rv = syscall(SYS_futex, uaddr(), FUTEX_WAKE, INT_MAX, NULL, NULL, 0); |
+ PLOG_IF(ERROR, rv < 0) << "futex"; |
+#endif |
+} |
+ |
+bool SharedEvent::IsSignaled() { |
+ return base::subtle::Acquire_Load(uaddr()) == SIGNALED; |
+} |
+ |
+bool SharedEvent::Wait(const base::TimeDelta& max_time) { |
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+ struct timespec timeout = max_time.ToTimeSpec(); |
+#endif |
+ |
+ // Wait for signaled state by repeatadly attempting to enter waiting state |
+ // until it fails because current state is signaled. |
+ while (base::subtle::Acquire_CompareAndSwap(uaddr(), NOT_SIGNALED, WAITING) != |
+ SIGNALED) { |
+#if defined(OS_LINUX) || defined(OS_ANDROID) |
+ // Perform futex operation that will block until woken up or |timeout| has |
+ // expired. Note: If the futex value does not match waiting state, then the |
+ // call fails immediately with the error EAGAIN. |
+ if (syscall(SYS_futex, uaddr(), FUTEX_WAIT, WAITING, &timeout, NULL, 0)) { |
+ PLOG_IF(ERROR, errno != EAGAIN && errno != ETIMEDOUT) << "futex"; |
+ return false; |
+ } |
+ // Protect against spurious wake-ups by checking state again. Reset |
+ // timeout to prevent this function from blocking significantly longer |
+ // than |max_time|. |
+ timeout = {0}; |
+#else |
+ base::PlatformThread::YieldCurrentThread(); |
+ return false; |
+#endif |
+ } |
+ |
+ return true; |
+} |
+ |
+SharedEventHandle SharedEvent::GetHandle() const { |
+ return shared_memory_.handle(); |
+} |
+ |
+void SharedEvent::Close() { |
+ shared_memory_.Close(); |
+} |
+ |
+} // namespace gfx |