1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
mojo / core / handle_table.h [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_CORE_HANDLE_TABLE_H_
#define MOJO_CORE_HANDLE_TABLE_H_
#include <stdint.h>
#include <unordered_map>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
#include "mojo/core/dispatcher.h"
#include "mojo/core/system_impl_export.h"
#include "mojo/public/c/system/types.h"
namespace mojo {
namespace core {
class MOJO_SYSTEM_IMPL_EXPORT HandleTable
: public base::trace_event::MemoryDumpProvider {
public:
HandleTable();
HandleTable(const HandleTable&) = delete;
HandleTable& operator=(const HandleTable&) = delete;
~HandleTable() override;
// HandleTable is thread-hostile. All access should be gated by GetLock().
base::Lock& GetLock();
MojoHandle AddDispatcher(scoped_refptr<Dispatcher> dispatcher);
// Inserts multiple dispatchers received from message transit, populating
// |handles| with their newly allocated handles. Returns |true| on success.
bool AddDispatchersFromTransit(
const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
MojoHandle* handles);
scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
MojoResult GetAndRemoveDispatcher(MojoHandle,
scoped_refptr<Dispatcher>* dispatcher);
// Marks handles as busy and populates |dispatchers|. Returns MOJO_RESULT_BUSY
// if any of the handles are already in transit; MOJO_RESULT_INVALID_ARGUMENT
// if any of the handles are invalid; or MOJO_RESULT_OK if successful.
MojoResult BeginTransit(
const MojoHandle* handles,
size_t num_handles,
std::vector<Dispatcher::DispatcherInTransit>* dispatchers);
void CompleteTransitAndClose(
const std::vector<Dispatcher::DispatcherInTransit>& dispatchers);
void CancelTransit(
const std::vector<Dispatcher::DispatcherInTransit>& dispatchers);
void GetActiveHandlesForTest(std::vector<MojoHandle>* handles);
private:
FRIEND_TEST_ALL_PREFIXES(HandleTableTest, OnMemoryDump);
// MemoryDumpProvider implementation.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
struct Entry {
explicit Entry(scoped_refptr<Dispatcher> dispatcher);
~Entry();
Entry(const Entry& entry);
Entry& operator=(const Entry&) = delete;
const scoped_refptr<Dispatcher> dispatcher;
bool busy = false;
};
// A helper class for storing dispatchers that caches the last fetched
// dispatcher. This is an optimization for the common case that the same
// dispatcher is fetched repeatedly. Please see https://crbug.com/1295449 for
// more details.
class EntriesAccessor {
public:
EntriesAccessor();
~EntriesAccessor();
// Returns whether an Entry was inserted.
bool Add(MojoHandle handle, Entry entry);
// Returns nullptr if a dispatcher is not found.
const scoped_refptr<Dispatcher>* GetDispatcher(MojoHandle handle);
// Returns nullptr if an entry is not found.
Entry* GetMutable(MojoHandle handle);
// See `Remove` below.
enum RemovalCondition { kRemoveOnlyIfBusy, kRemoveOnlyIfNotBusy };
// Returns whether an entry was found, and if found, `MOJO_RESULT_BUSY` if
// `Entry.busy` is true and `MOJO_RESULT_OK` if `Entry.busy` is false. If an
// entry is not found, `MOJO_RESULT_NOT_FOUND` is returned.
//
// If an entry is found, and if `removal_condition` matches `Entry.busy`, it
// is removed from storage and -- if `dispatcher` is not nullptr -- the
// corresponding dispatcher is returned in `dispatcher`. Otherwise,
// `dispatcher` is left unchanged.
MojoResult Remove(MojoHandle handle,
RemovalCondition removal_condition,
scoped_refptr<Dispatcher>* dispatcher);
const std::unordered_map<MojoHandle, Entry>& GetUnderlyingMap() const;
private:
std::unordered_map<MojoHandle, Entry> handles_;
scoped_refptr<Dispatcher> last_read_dispatcher_;
MojoHandle last_read_handle_ = MOJO_HANDLE_INVALID;
};
EntriesAccessor entries_;
base::Lock lock_;
uintptr_t next_available_handle_ = 1;
};
} // namespace core
} // namespace mojo
#endif // MOJO_CORE_HANDLE_TABLE_H_