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
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_EDK_SYSTEM_HANDLE_TABLE_H_
#define MOJO_EDK_SYSTEM_HANDLE_TABLE_H_
#include <utility>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "mojo/edk/system/system_impl_export.h"
#include "mojo/public/c/system/types.h"
namespace mojo {
namespace system {
class Core;
class Dispatcher;
class DispatcherTransport;
typedef std::vector<scoped_refptr<Dispatcher>> DispatcherVector;
// Test-only function (defined/used in embedder/test_embedder.cc). Declared here
// so it can be friended.
namespace internal {
bool ShutdownCheckNoLeaks(Core*);
}
// This class provides the (global) handle table (owned by |Core|), which maps
// (valid) |MojoHandle|s to |Dispatcher|s. This is abstracted so that, e.g.,
// caching may be added.
//
// This class is NOT thread-safe; locking is left to |Core| (since it may need
// to make several changes -- "atomically" or in rapid successsion, in which
// case the extra locking/unlocking would be unnecessary overhead).
class MOJO_SYSTEM_IMPL_EXPORT HandleTable {
public:
HandleTable();
~HandleTable();
// Gets the dispatcher for a given handle (which should not be
// |MOJO_HANDLE_INVALID|). Returns null if there's no dispatcher for the given
// handle.
// WARNING: For efficiency, this returns a dumb pointer. If you're going to
// use the result outside |Core|'s lock, you MUST take a reference (e.g., by
// storing the result inside a |scoped_refptr|).
Dispatcher* GetDispatcher(MojoHandle handle);
// On success, gets the dispatcher for a given handle (which should not be
// |MOJO_HANDLE_INVALID|) and removes it. (On failure, returns an appropriate
// result (and leaves |dispatcher| alone), namely
// |MOJO_RESULT_INVALID_ARGUMENT| if there's no dispatcher for the given
// handle or |MOJO_RESULT_BUSY| if the handle is marked as busy.)
MojoResult GetAndRemoveDispatcher(MojoHandle handle,
scoped_refptr<Dispatcher>* dispatcher);
// Adds a dispatcher (which must be valid), returning the handle for it.
// Returns |MOJO_HANDLE_INVALID| on failure (if the handle table is full).
MojoHandle AddDispatcher(const scoped_refptr<Dispatcher>& dispatcher);
// Adds a pair of dispatchers (which must be valid), return a pair of handles
// for them. On failure (if the handle table is full), the first (and second)
// handles will be |MOJO_HANDLE_INVALID|, and neither dispatcher will be
// added.
std::pair<MojoHandle, MojoHandle> AddDispatcherPair(
const scoped_refptr<Dispatcher>& dispatcher0,
const scoped_refptr<Dispatcher>& dispatcher1);
// Adds the given vector of dispatchers (of size at most
// |kMaxMessageNumHandles|). |handles| must point to an array of size at least
// |dispatchers.size()|. Unlike the other |AddDispatcher...()| functions, some
// of the dispatchers may be invalid (null). Returns true on success and false
// on failure (if the handle table is full), in which case it leaves
// |handles[...]| untouched (and all dispatchers unadded).
bool AddDispatcherVector(const DispatcherVector& dispatchers,
MojoHandle* handles);
// Tries to mark the given handles as busy and start transport on them (i.e.,
// take their dispatcher locks); |transports| must be sized to contain
// |num_handles| elements. On failure, returns them to their original
// (non-busy, unlocked state).
MojoResult MarkBusyAndStartTransport(
MojoHandle disallowed_handle,
const MojoHandle* handles,
uint32_t num_handles,
std::vector<DispatcherTransport>* transports);
// Remove the given handles, which must all be present and which should have
// previously been marked busy by |MarkBusyAndStartTransport()|.
void RemoveBusyHandles(const MojoHandle* handles, uint32_t num_handles);
// Restores the given handles, which must all be present and which should have
// previously been marked busy by |MarkBusyAndStartTransport()|, to a non-busy
// state.
void RestoreBusyHandles(const MojoHandle* handles, uint32_t num_handles);
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
// The |busy| member is used only to deal with functions (in particular
// |Core::WriteMessage()|) that want to hold on to a dispatcher and later
// remove it from the handle table, without holding on to the handle table
// lock.
//
// For example, if |Core::WriteMessage()| is called with a handle to be sent,
// (under the handle table lock) it must first check that that handle is not
// busy (if it is busy, then it fails with |MOJO_RESULT_BUSY|) and then marks
// it as busy. To avoid deadlock, it should also try to acquire the locks for
// all the dispatchers for the handles that it is sending (and fail with
// |MOJO_RESULT_BUSY| if the attempt fails). At this point, it can release the
// handle table lock.
//
// If |Core::Close()| is simultaneously called on that handle, it too checks
// if the handle is marked busy. If it is, it fails (with |MOJO_RESULT_BUSY|).
// This prevents |Core::WriteMessage()| from sending a handle that has been
// closed (or learning about this too late).
struct Entry {
Entry();
explicit Entry(const scoped_refptr<Dispatcher>& dispatcher);
~Entry();
scoped_refptr<Dispatcher> dispatcher;
bool busy;
};
typedef base::hash_map<MojoHandle, Entry> HandleToEntryMap;
// Adds the given dispatcher to the handle table, not doing any size checks.
MojoHandle AddDispatcherNoSizeCheck(
const scoped_refptr<Dispatcher>& dispatcher);
HandleToEntryMap handle_to_entry_map_;
MojoHandle next_handle_; // Invariant: never |MOJO_HANDLE_INVALID|.
DISALLOW_COPY_AND_ASSIGN(HandleTable);
};
} // namespace system
} // namespace mojo
#endif // MOJO_EDK_SYSTEM_HANDLE_TABLE_H_
|