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 DCHECK_LE(dispatchers.size(), std::numeric_limits<uint32_t>::max());
72 // If this insertion would cause handle overflow, we're out of handles.
73 if (next_available_handle_ + dispatchers.size() < next_available_handle_)
74 return false;
75
76 for (size_t i = 0; i < dispatchers.size(); ++i) {
77 MojoHandle handle = MOJO_HANDLE_INVALID;
78 if (dispatchers[i].dispatcher) {
79 handle = next_available_handle_++;
80 auto result = handles_.insert(
81 std::make_pair(handle, Entry(dispatchers[i].dispatcher)));
82 DCHECK(result.second);
83 }
84 handles[i] = handle;
85 }
86
87 return true;
88 }
89
GetDispatcher(MojoHandle handle) const90 scoped_refptr<Dispatcher> HandleTable::GetDispatcher(MojoHandle handle) const {
91 auto it = handles_.find(handle);
92 if (it == handles_.end())
93 return nullptr;
94 return it->second.dispatcher;
95 }
96
GetAndRemoveDispatcher(MojoHandle handle,scoped_refptr<Dispatcher> * dispatcher)97 MojoResult HandleTable::GetAndRemoveDispatcher(
98 MojoHandle handle,
99 scoped_refptr<Dispatcher>* dispatcher) {
100 auto it = handles_.find(handle);
101 if (it == handles_.end())
102 return MOJO_RESULT_INVALID_ARGUMENT;
103 if (it->second.busy)
104 return MOJO_RESULT_BUSY;
105
106 *dispatcher = std::move(it->second.dispatcher);
107 handles_.erase(it);
108 return MOJO_RESULT_OK;
109 }
110
BeginTransit(const MojoHandle * handles,size_t num_handles,std::vector<Dispatcher::DispatcherInTransit> * dispatchers)111 MojoResult HandleTable::BeginTransit(
112 const MojoHandle* handles,
113 size_t num_handles,
114 std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
115 dispatchers->reserve(dispatchers->size() + num_handles);
116 for (size_t i = 0; i < num_handles; ++i) {
117 auto it = handles_.find(handles[i]);
118 if (it == handles_.end())
119 return MOJO_RESULT_INVALID_ARGUMENT;
120 if (it->second.busy)
121 return MOJO_RESULT_BUSY;
122
123 Dispatcher::DispatcherInTransit d;
124 d.local_handle = handles[i];
125 d.dispatcher = it->second.dispatcher;
126 if (!d.dispatcher->BeginTransit())
127 return MOJO_RESULT_BUSY;
128 it->second.busy = true;
129 dispatchers->push_back(d);
130 }
131 return MOJO_RESULT_OK;
132 }
133
CompleteTransitAndClose(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers)134 void HandleTable::CompleteTransitAndClose(
135 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
136 for (const auto& dispatcher : dispatchers) {
137 auto it = handles_.find(dispatcher.local_handle);
138 DCHECK(it != handles_.end() && it->second.busy);
139 handles_.erase(it);
140 dispatcher.dispatcher->CompleteTransitAndClose();
141 }
142 }
143
CancelTransit(const std::vector<Dispatcher::DispatcherInTransit> & dispatchers)144 void HandleTable::CancelTransit(
145 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
146 for (const auto& dispatcher : dispatchers) {
147 auto it = handles_.find(dispatcher.local_handle);
148 DCHECK(it != handles_.end() && it->second.busy);
149 it->second.busy = false;
150 dispatcher.dispatcher->CancelTransit();
151 }
152 }
153
GetActiveHandlesForTest(std::vector<MojoHandle> * handles)154 void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
155 handles->clear();
156 for (const auto& entry : handles_)
157 handles->push_back(entry.first);
158 }
159
160 // MemoryDumpProvider implementation.
161 // bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
162 // base::trace_event::ProcessMemoryDump* pmd) {
163 // // Create entries for all relevant dispatcher types to ensure they are present
164 // // in the final dump.
165 // std::map<Dispatcher::Type, int> handle_count;
166 // handle_count[Dispatcher::Type::MESSAGE_PIPE];
167 // handle_count[Dispatcher::Type::DATA_PIPE_PRODUCER];
168 // handle_count[Dispatcher::Type::DATA_PIPE_CONSUMER];
169 // handle_count[Dispatcher::Type::SHARED_BUFFER];
170 // handle_count[Dispatcher::Type::WATCHER];
171 // handle_count[Dispatcher::Type::PLATFORM_HANDLE];
172 // handle_count[Dispatcher::Type::INVITATION];
173
174 // // Count the number of each dispatcher type.
175 // {
176 // base::AutoLock lock(GetLock());
177 // for (const auto& entry : handles_) {
178 // ++handle_count[entry.second.dispatcher->GetType()];
179 // }
180 // }
181
182 // for (const auto& entry : handle_count) {
183 // base::trace_event::MemoryAllocatorDump* inner_dump =
184 // pmd->CreateAllocatorDump(std::string("mojo/") +
185 // GetNameForDispatcherType(entry.first));
186 // inner_dump->AddScalar(
187 // base::trace_event::MemoryAllocatorDump::kNameObjectCount,
188 // base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
189 // }
190
191 // return true;
192 // }
193
Entry()194 HandleTable::Entry::Entry() {}
195
Entry(scoped_refptr<Dispatcher> dispatcher)196 HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
197 : dispatcher(std::move(dispatcher)) {}
198
199 HandleTable::Entry::Entry(const Entry& other) = default;
200
~Entry()201 HandleTable::Entry::~Entry() {}
202
203 } // namespace core
204 } // namespace mojo
205