| Index: ppapi/proxy/gamepad_resource.cc
|
| diff --git a/ppapi/proxy/gamepad_resource.cc b/ppapi/proxy/gamepad_resource.cc
|
| index 21ee02d9de9fa1cce6f3dc6b4ce99885691e4a7d..3f6952a62014f171960e1da4a0b2e61641b2750c 100644
|
| --- a/ppapi/proxy/gamepad_resource.cc
|
| +++ b/ppapi/proxy/gamepad_resource.cc
|
| @@ -6,16 +6,47 @@
|
|
|
| #include <string.h>
|
|
|
| -#include "ppapi/c/ppb_gamepad.h"
|
| +#include "base/threading/platform_thread.h"
|
| #include "ppapi/proxy/dispatch_reply_message.h"
|
| #include "ppapi/proxy/ppapi_messages.h"
|
| +#include "ppapi/shared_impl/ppb_gamepad_shared.h"
|
|
|
| namespace ppapi {
|
| namespace proxy {
|
|
|
| +namespace {
|
| +
|
| +// This is the read logic from content/common/gamepad_seqlock.h
|
| +base::subtle::Atomic32 ReadBegin(const base::subtle::Atomic32* sequence) {
|
| + base::subtle::Atomic32 version;
|
| + for (;;) {
|
| + version = base::subtle::NoBarrier_Load(sequence);
|
| +
|
| + // If the counter is even, then the associated data might be in a
|
| + // consistent state, so we can try to read.
|
| + if ((version & 1) == 0)
|
| + break;
|
| +
|
| + // Otherwise, the writer is in the middle of an update. Retry the read.
|
| + base::PlatformThread::YieldCurrentThread();
|
| + }
|
| + return version;
|
| +}
|
| +
|
| +bool ReadRetry(const base::subtle::Atomic32* sequence,
|
| + base::subtle::Atomic32 version) {
|
| + // If the sequence number was updated then a read should be re-attempted.
|
| + // -- Load fence, read membarrier
|
| + return base::subtle::Release_Load(sequence) != version;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| GamepadResource::GamepadResource(Connection connection, PP_Instance instance)
|
| : PluginResource(connection, instance),
|
| buffer_(NULL) {
|
| + memset(&last_read_, 0, sizeof(last_read_));
|
| +
|
| SendCreateToBrowser(PpapiHostMsg_Gamepad_Create());
|
| CallBrowser(PpapiHostMsg_Gamepad_RequestMemory());
|
| }
|
| @@ -28,9 +59,36 @@ void GamepadResource::Sample(PP_GamepadsSampleData* data) {
|
| // Browser hasn't sent back our shared memory, give the plugin gamepad
|
| // data corresponding to "not connected".
|
| memset(data, 0, sizeof(PP_GamepadsSampleData));
|
| - } else {
|
| - memcpy(data, buffer_, sizeof(PP_GamepadsSampleData));
|
| + return;
|
| }
|
| +
|
| + // ==========
|
| + // DANGER
|
| + // ==========
|
| + //
|
| + // This logic is duplicated in the renderer as well. If you change it, that
|
| + // also needs to be in sync. See gamepad_shared_memory_reader.cc.
|
| +
|
| + // Only try to read this many times before failing to avoid waiting here
|
| + // very long in case of contention with the writer.
|
| + const int kMaximumContentionCount = 10;
|
| + int contention_count = -1;
|
| + base::subtle::Atomic32 version;
|
| + WebKitGamepads read_into;
|
| + do {
|
| + version = ReadBegin(&buffer_->sequence);
|
| + memcpy(&read_into, &buffer_->buffer, sizeof(read_into));
|
| + ++contention_count;
|
| + if (contention_count == kMaximumContentionCount)
|
| + break;
|
| + } while (ReadRetry(&buffer_->sequence, version));
|
| +
|
| + // In the event of a read failure, just leave the last read data as-is (the
|
| + // hardware thread is taking unusally long).
|
| + if (contention_count < kMaximumContentionCount)
|
| + ConvertWebKitGamepadData(read_into, &last_read_);
|
| +
|
| + memcpy(data, &last_read_, sizeof(PP_GamepadsSampleData));
|
| }
|
|
|
| void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params,
|
| @@ -44,14 +102,11 @@ void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params,
|
| void GamepadResource::OnPluginMsgSendMemory(
|
| const ResourceMessageReplyParams& params,
|
| base::SharedMemoryHandle shared_memory_handle) {
|
| - /* TODO(brettw) implement this when we have shared gamepad code. It would be
|
| - something like this:
|
| shared_memory_.reset(
|
| new base::SharedMemory(shared_memory_handle, true));
|
| - CHECK(shared_memory_->Map(sizeof(GamepadHardwareBuffer)));
|
| - void *memory = shared_memory_->memory();
|
| - // Use the memory...
|
| - */
|
| + CHECK(shared_memory_->Map(sizeof(ContentGamepadHardwareBuffer)));
|
| + buffer_ = static_cast<const ContentGamepadHardwareBuffer*>(
|
| + shared_memory_->memory());
|
| }
|
|
|
| } // namespace proxy
|
|
|