handle_table.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2014 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.
  4. #include "mojo/core/handle_table.h"
  5. #include <stdint.h>
  6. #include <limits>
  7. #include "base/cpu_reduction_experiment.h"
  8. #include "base/trace_event/memory_dump_manager.h"
  9. namespace mojo {
  10. namespace core {
  11. namespace {
  12. const char* GetNameForDispatcherType(Dispatcher::Type type) {
  13. switch (type) {
  14. case Dispatcher::Type::UNKNOWN:
  15. return "unknown";
  16. case Dispatcher::Type::MESSAGE_PIPE:
  17. return "message_pipe";
  18. case Dispatcher::Type::DATA_PIPE_PRODUCER:
  19. return "data_pipe_producer";
  20. case Dispatcher::Type::DATA_PIPE_CONSUMER:
  21. return "data_pipe_consumer";
  22. case Dispatcher::Type::SHARED_BUFFER:
  23. return "shared_buffer";
  24. case Dispatcher::Type::WATCHER:
  25. return "watcher";
  26. case Dispatcher::Type::PLATFORM_HANDLE:
  27. return "platform_handle";
  28. case Dispatcher::Type::INVITATION:
  29. return "invitation";
  30. }
  31. NOTREACHED();
  32. return "unknown";
  33. }
  34. } // namespace
  35. HandleTable::EntriesAccessor::EntriesAccessor() = default;
  36. HandleTable::EntriesAccessor::~EntriesAccessor() = default;
  37. bool HandleTable::EntriesAccessor::Add(const MojoHandle handle, Entry entry) {
  38. return handles_.emplace(handle, std::move(entry)).second;
  39. }
  40. const scoped_refptr<Dispatcher>* HandleTable::EntriesAccessor::GetDispatcher(
  41. const MojoHandle handle) {
  42. // TODO(crbug.com/1295441): Remove the if-block below.
  43. // This intentionally duplicates code in this function a bit, so that this
  44. // entire if-block can later be removed cleanly.
  45. if (!base::IsRunningCpuReductionExperiment()) {
  46. const auto iter = handles_.find(handle);
  47. return iter == handles_.end() ? nullptr : &iter->second.dispatcher;
  48. }
  49. if (last_read_handle_ != MOJO_HANDLE_INVALID && last_read_handle_ == handle) {
  50. return &last_read_dispatcher_;
  51. }
  52. const auto iter = handles_.find(handle);
  53. if (iter == handles_.end()) {
  54. return nullptr;
  55. }
  56. last_read_handle_ = handle;
  57. last_read_dispatcher_ = iter->second.dispatcher;
  58. return &last_read_dispatcher_;
  59. }
  60. HandleTable::Entry* HandleTable::EntriesAccessor::GetMutable(
  61. const MojoHandle handle) {
  62. const auto iter = handles_.find(handle);
  63. return iter == handles_.end() ? nullptr : &iter->second;
  64. }
  65. MojoResult HandleTable::EntriesAccessor::Remove(
  66. const MojoHandle handle,
  67. const HandleTable::EntriesAccessor::RemovalCondition removal_condition,
  68. scoped_refptr<Dispatcher>* dispatcher) {
  69. auto iter = handles_.find(handle);
  70. if (iter == handles_.end()) {
  71. return MOJO_RESULT_NOT_FOUND;
  72. }
  73. const bool is_busy = iter->second.busy;
  74. const bool remove_only_if_busy =
  75. removal_condition == RemovalCondition::kRemoveOnlyIfBusy;
  76. if (remove_only_if_busy == is_busy) {
  77. if (dispatcher != nullptr) {
  78. *dispatcher = iter->second.dispatcher;
  79. }
  80. if (iter->first == last_read_handle_) {
  81. last_read_handle_ = MOJO_HANDLE_INVALID;
  82. last_read_dispatcher_.reset();
  83. }
  84. handles_.erase(iter);
  85. }
  86. return is_busy ? MOJO_RESULT_BUSY : MOJO_RESULT_OK;
  87. }
  88. const std::unordered_map<MojoHandle, HandleTable::Entry>&
  89. HandleTable::EntriesAccessor::GetUnderlyingMap() const {
  90. return handles_;
  91. }
  92. HandleTable::HandleTable() = default;
  93. HandleTable::~HandleTable() = default;
  94. base::Lock& HandleTable::GetLock() {
  95. return lock_;
  96. }
  97. MojoHandle HandleTable::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
  98. // Oops, we're out of handles.
  99. if (next_available_handle_ == MOJO_HANDLE_INVALID)
  100. return MOJO_HANDLE_INVALID;
  101. MojoHandle handle = next_available_handle_++;
  102. const bool inserted = entries_.Add(handle, Entry(std::move(dispatcher)));
  103. DCHECK(inserted);
  104. return handle;
  105. }
  106. bool HandleTable::AddDispatchersFromTransit(
  107. const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
  108. MojoHandle* handles) {
  109. // Oops, we're out of handles.
  110. if (next_available_handle_ == MOJO_HANDLE_INVALID) {
  111. return false;
  112. }
  113. // MOJO_HANDLE_INVALID is zero.
  114. DCHECK_GE(next_available_handle_, 1u);
  115. // If this insertion would cause handle overflow, we're out of handles.
  116. const uintptr_t num_handles_available =
  117. std::numeric_limits<uintptr_t>::max() - next_available_handle_ + 1;
  118. if (num_handles_available < dispatchers.size()) {
  119. return false;
  120. }
  121. for (size_t i = 0; i < dispatchers.size(); ++i) {
  122. MojoHandle handle = MOJO_HANDLE_INVALID;
  123. if (dispatchers[i].dispatcher) {
  124. handle = next_available_handle_++;
  125. const bool inserted =
  126. entries_.Add(handle, Entry(dispatchers[i].dispatcher));
  127. DCHECK(inserted);
  128. }
  129. handles[i] = handle;
  130. }
  131. return true;
  132. }
  133. scoped_refptr<Dispatcher> HandleTable::GetDispatcher(MojoHandle handle) {
  134. const scoped_refptr<Dispatcher>* dispatcher = entries_.GetDispatcher(handle);
  135. return dispatcher == nullptr ? nullptr : *dispatcher;
  136. }
  137. MojoResult HandleTable::GetAndRemoveDispatcher(
  138. MojoHandle handle,
  139. scoped_refptr<Dispatcher>* dispatcher) {
  140. scoped_refptr<Dispatcher> removed_dispatcher;
  141. const MojoResult remove_result = entries_.Remove(
  142. handle, EntriesAccessor::RemovalCondition::kRemoveOnlyIfNotBusy,
  143. &removed_dispatcher);
  144. if (remove_result == MOJO_RESULT_NOT_FOUND) {
  145. return MOJO_RESULT_INVALID_ARGUMENT;
  146. }
  147. if (remove_result == MOJO_RESULT_BUSY) {
  148. return MOJO_RESULT_BUSY;
  149. }
  150. *dispatcher = std::move(removed_dispatcher);
  151. return MOJO_RESULT_OK;
  152. }
  153. MojoResult HandleTable::BeginTransit(
  154. const MojoHandle* handles,
  155. size_t num_handles,
  156. std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
  157. dispatchers->reserve(dispatchers->size() + num_handles);
  158. for (size_t i = 0; i < num_handles; ++i) {
  159. Entry* entry = entries_.GetMutable(handles[i]);
  160. if (entry == nullptr) {
  161. return MOJO_RESULT_INVALID_ARGUMENT;
  162. }
  163. if (entry->busy) {
  164. return MOJO_RESULT_BUSY;
  165. }
  166. Dispatcher::DispatcherInTransit d;
  167. d.local_handle = handles[i];
  168. d.dispatcher = entry->dispatcher;
  169. if (!d.dispatcher->BeginTransit())
  170. return MOJO_RESULT_BUSY;
  171. entry->busy = true;
  172. dispatchers->push_back(d);
  173. }
  174. return MOJO_RESULT_OK;
  175. }
  176. void HandleTable::CompleteTransitAndClose(
  177. const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
  178. for (const auto& dispatcher : dispatchers) {
  179. const MojoResult remove_result =
  180. entries_.Remove(dispatcher.local_handle,
  181. EntriesAccessor::RemovalCondition::kRemoveOnlyIfBusy,
  182. /*dispatcher=*/nullptr);
  183. DCHECK(remove_result == MOJO_RESULT_BUSY);
  184. dispatcher.dispatcher->CompleteTransitAndClose();
  185. }
  186. }
  187. void HandleTable::CancelTransit(
  188. const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
  189. for (const auto& dispatcher : dispatchers) {
  190. Entry* entry = entries_.GetMutable(dispatcher.local_handle);
  191. DCHECK(entry != nullptr && entry->busy);
  192. entry->busy = false;
  193. dispatcher.dispatcher->CancelTransit();
  194. }
  195. }
  196. void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
  197. handles->clear();
  198. for (const auto& entry : entries_.GetUnderlyingMap())
  199. handles->push_back(entry.first);
  200. }
  201. // MemoryDumpProvider implementation.
  202. bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
  203. base::trace_event::ProcessMemoryDump* pmd) {
  204. // Create entries for all relevant dispatcher types to ensure they are present
  205. // in the final dump.
  206. std::map<Dispatcher::Type, int> handle_count;
  207. handle_count[Dispatcher::Type::MESSAGE_PIPE];
  208. handle_count[Dispatcher::Type::DATA_PIPE_PRODUCER];
  209. handle_count[Dispatcher::Type::DATA_PIPE_CONSUMER];
  210. handle_count[Dispatcher::Type::SHARED_BUFFER];
  211. handle_count[Dispatcher::Type::WATCHER];
  212. handle_count[Dispatcher::Type::PLATFORM_HANDLE];
  213. handle_count[Dispatcher::Type::INVITATION];
  214. // Count the number of each dispatcher type.
  215. {
  216. base::AutoLock lock(GetLock());
  217. for (const auto& entry : entries_.GetUnderlyingMap()) {
  218. ++handle_count[entry.second.dispatcher->GetType()];
  219. }
  220. }
  221. for (const auto& entry : handle_count) {
  222. base::trace_event::MemoryAllocatorDump* inner_dump =
  223. pmd->CreateAllocatorDump(std::string("mojo/") +
  224. GetNameForDispatcherType(entry.first));
  225. inner_dump->AddScalar(
  226. base::trace_event::MemoryAllocatorDump::kNameObjectCount,
  227. base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
  228. }
  229. return true;
  230. }
  231. HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
  232. : dispatcher(std::move(dispatcher)) {}
  233. HandleTable::Entry::~Entry() = default;
  234. HandleTable::Entry::Entry(const Entry& entry) = default;
  235. } // namespace core
  236. } // namespace mojo