OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/gamepad_resource.h" | 5 #include "ppapi/proxy/gamepad_resource.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include "ppapi/c/ppb_gamepad.h" | 9 #include "base/threading/platform_thread.h" |
10 #include "ppapi/proxy/dispatch_reply_message.h" | 10 #include "ppapi/proxy/dispatch_reply_message.h" |
11 #include "ppapi/proxy/ppapi_messages.h" | 11 #include "ppapi/proxy/ppapi_messages.h" |
| 12 #include "ppapi/shared_impl/ppb_gamepad_shared.h" |
12 | 13 |
13 namespace ppapi { | 14 namespace ppapi { |
14 namespace proxy { | 15 namespace proxy { |
15 | 16 |
| 17 namespace { |
| 18 |
| 19 // This is the read logic from content/common/gamepad_seqlock.h |
| 20 base::subtle::Atomic32 ReadBegin(const base::subtle::Atomic32* sequence) { |
| 21 base::subtle::Atomic32 version; |
| 22 for (;;) { |
| 23 version = base::subtle::NoBarrier_Load(sequence); |
| 24 |
| 25 // If the counter is even, then the associated data might be in a |
| 26 // consistent state, so we can try to read. |
| 27 if ((version & 1) == 0) |
| 28 break; |
| 29 |
| 30 // Otherwise, the writer is in the middle of an update. Retry the read. |
| 31 base::PlatformThread::YieldCurrentThread(); |
| 32 } |
| 33 return version; |
| 34 } |
| 35 |
| 36 bool ReadRetry(const base::subtle::Atomic32* sequence, |
| 37 base::subtle::Atomic32 version) { |
| 38 // If the sequence number was updated then a read should be re-attempted. |
| 39 // -- Load fence, read membarrier |
| 40 return base::subtle::Release_Load(sequence) != version; |
| 41 } |
| 42 |
| 43 } // namespace |
| 44 |
16 GamepadResource::GamepadResource(Connection connection, PP_Instance instance) | 45 GamepadResource::GamepadResource(Connection connection, PP_Instance instance) |
17 : PluginResource(connection, instance), | 46 : PluginResource(connection, instance), |
18 buffer_(NULL) { | 47 buffer_(NULL) { |
| 48 memset(&last_read_, 0, sizeof(last_read_)); |
| 49 |
19 SendCreateToBrowser(PpapiHostMsg_Gamepad_Create()); | 50 SendCreateToBrowser(PpapiHostMsg_Gamepad_Create()); |
20 CallBrowser(PpapiHostMsg_Gamepad_RequestMemory()); | 51 CallBrowser(PpapiHostMsg_Gamepad_RequestMemory()); |
21 } | 52 } |
22 | 53 |
23 GamepadResource::~GamepadResource() { | 54 GamepadResource::~GamepadResource() { |
24 } | 55 } |
25 | 56 |
26 void GamepadResource::Sample(PP_GamepadsSampleData* data) { | 57 void GamepadResource::Sample(PP_GamepadsSampleData* data) { |
27 if (!buffer_) { | 58 if (!buffer_) { |
28 // Browser hasn't sent back our shared memory, give the plugin gamepad | 59 // Browser hasn't sent back our shared memory, give the plugin gamepad |
29 // data corresponding to "not connected". | 60 // data corresponding to "not connected". |
30 memset(data, 0, sizeof(PP_GamepadsSampleData)); | 61 memset(data, 0, sizeof(PP_GamepadsSampleData)); |
31 } else { | 62 return; |
32 memcpy(data, buffer_, sizeof(PP_GamepadsSampleData)); | |
33 } | 63 } |
| 64 |
| 65 // ========== |
| 66 // DANGER |
| 67 // ========== |
| 68 // |
| 69 // This logic is duplicated in the renderer as well. If you change it, that |
| 70 // also needs to be in sync. See gamepad_shared_memory_reader.cc. |
| 71 |
| 72 // Only try to read this many times before failing to avoid waiting here |
| 73 // very long in case of contention with the writer. |
| 74 const int kMaximumContentionCount = 10; |
| 75 int contention_count = -1; |
| 76 base::subtle::Atomic32 version; |
| 77 WebKitGamepads read_into; |
| 78 do { |
| 79 version = ReadBegin(&buffer_->sequence); |
| 80 memcpy(&read_into, &buffer_->buffer, sizeof(read_into)); |
| 81 ++contention_count; |
| 82 if (contention_count == kMaximumContentionCount) |
| 83 break; |
| 84 } while (ReadRetry(&buffer_->sequence, version)); |
| 85 |
| 86 // In the event of a read failure, just leave the last read data as-is (the |
| 87 // hardware thread is taking unusally long). |
| 88 if (contention_count < kMaximumContentionCount) |
| 89 ConvertWebKitGamepadData(read_into, &last_read_); |
| 90 |
| 91 memcpy(data, &last_read_, sizeof(PP_GamepadsSampleData)); |
34 } | 92 } |
35 | 93 |
36 void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params, | 94 void GamepadResource::OnReplyReceived(const ResourceMessageReplyParams& params, |
37 const IPC::Message& msg) { | 95 const IPC::Message& msg) { |
38 IPC_BEGIN_MESSAGE_MAP(GamepadResource, msg) | 96 IPC_BEGIN_MESSAGE_MAP(GamepadResource, msg) |
39 PPAPI_DISPATCH_RESOURCE_REPLY(PpapiPluginMsg_Gamepad_SendMemory, | 97 PPAPI_DISPATCH_RESOURCE_REPLY_0(PpapiPluginMsg_Gamepad_SendMemory, |
40 OnPluginMsgSendMemory) | 98 OnPluginMsgSendMemory) |
41 IPC_END_MESSAGE_MAP() | 99 IPC_END_MESSAGE_MAP() |
42 } | 100 } |
43 | 101 |
44 void GamepadResource::OnPluginMsgSendMemory( | 102 void GamepadResource::OnPluginMsgSendMemory( |
45 const ResourceMessageReplyParams& params, | 103 const ResourceMessageReplyParams& params) { |
46 base::SharedMemoryHandle shared_memory_handle) { | 104 // On failure, the handle will be null and the CHECK below will be tripped. |
47 /* TODO(brettw) implement this when we have shared gamepad code. It would be | 105 base::SharedMemoryHandle handle; |
48 something like this: | 106 params.GetSharedMemoryHandleAtIndex(0, &handle); |
49 shared_memory_.reset( | 107 |
50 new base::SharedMemory(shared_memory_handle, true)); | 108 shared_memory_.reset(new base::SharedMemory(handle, true)); |
51 CHECK(shared_memory_->Map(sizeof(GamepadHardwareBuffer))); | 109 CHECK(shared_memory_->Map(sizeof(ContentGamepadHardwareBuffer))); |
52 void *memory = shared_memory_->memory(); | 110 buffer_ = static_cast<const ContentGamepadHardwareBuffer*>( |
53 // Use the memory... | 111 shared_memory_->memory()); |
54 */ | |
55 } | 112 } |
56 | 113 |
57 } // namespace proxy | 114 } // namespace proxy |
58 } // namespace ppapi | 115 } // namespace ppapi |
OLD | NEW |