1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/proxy/gamepad_resource.h"
10 #include "base/threading/platform_thread.h"
11 #include "ppapi/proxy/dispatch_reply_message.h"
12 #include "ppapi/proxy/ppapi_messages.h"
13 #include "ppapi/shared_impl/ppb_gamepad_shared.h"
20 // This is the read logic from content/common/gamepad_seqlock.h
21 base::subtle::Atomic32
ReadBegin(const base::subtle::Atomic32
* sequence
) {
22 base::subtle::Atomic32 version
;
24 version
= base::subtle::NoBarrier_Load(sequence
);
26 // If the counter is even, then the associated data might be in a
27 // consistent state, so we can try to read.
28 if ((version
& 1) == 0)
31 // Otherwise, the writer is in the middle of an update. Retry the read.
32 base::PlatformThread::YieldCurrentThread();
37 bool ReadRetry(const base::subtle::Atomic32
* sequence
,
38 base::subtle::Atomic32 version
) {
39 // If the sequence number was updated then a read should be re-attempted.
40 // -- Load fence, read membarrier
41 return base::subtle::Release_Load(sequence
) != version
;
46 GamepadResource::GamepadResource(Connection connection
, PP_Instance instance
)
47 : PluginResource(connection
, instance
),
49 memset(&last_read_
, 0, sizeof(last_read_
));
51 SendCreate(BROWSER
, PpapiHostMsg_Gamepad_Create());
52 Call
<PpapiPluginMsg_Gamepad_SendMemory
>(
54 PpapiHostMsg_Gamepad_RequestMemory(),
55 base::Bind(&GamepadResource::OnPluginMsgSendMemory
, this));
58 GamepadResource::~GamepadResource() {
61 thunk::PPB_Gamepad_API
* GamepadResource::AsPPB_Gamepad_API() {
65 void GamepadResource::Sample(PP_Instance
/* instance */,
66 PP_GamepadsSampleData
* data
) {
68 // Browser hasn't sent back our shared memory, give the plugin gamepad
69 // data corresponding to "not connected".
70 memset(data
, 0, sizeof(PP_GamepadsSampleData
));
78 // This logic is duplicated in the renderer as well. If you change it, that
79 // also needs to be in sync. See gamepad_shared_memory_reader.cc.
81 // Only try to read this many times before failing to avoid waiting here
82 // very long in case of contention with the writer.
83 const int kMaximumContentionCount
= 10;
84 int contention_count
= -1;
85 base::subtle::Atomic32 version
;
86 WebKitGamepads read_into
;
88 version
= ReadBegin(&buffer_
->sequence
);
89 memcpy(&read_into
, &buffer_
->buffer
, sizeof(read_into
));
91 if (contention_count
== kMaximumContentionCount
)
93 } while (ReadRetry(&buffer_
->sequence
, version
));
95 // In the event of a read failure, just leave the last read data as-is (the
96 // hardware thread is taking unusally long).
97 if (contention_count
< kMaximumContentionCount
)
98 ConvertWebKitGamepadData(read_into
, &last_read_
);
100 memcpy(data
, &last_read_
, sizeof(PP_GamepadsSampleData
));
103 void GamepadResource::OnPluginMsgSendMemory(
104 const ResourceMessageReplyParams
& params
) {
105 // On failure, the handle will be null and the CHECK below will be tripped.
106 base::SharedMemoryHandle handle
= base::SharedMemory::NULLHandle();
107 params
.TakeSharedMemoryHandleAtIndex(0, &handle
);
109 shared_memory_
.reset(new base::SharedMemory(handle
, true));
110 CHECK(shared_memory_
->Map(sizeof(ContentGamepadHardwareBuffer
)));
111 buffer_
= static_cast<const ContentGamepadHardwareBuffer
*>(
112 shared_memory_
->memory());