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