Allow creating SharedMemory that can't be shared read-only.
[chromium-blink-merge.git] / ppapi / shared_impl / var_tracker.cc
blob7fabb80641cc7a12942180855f6bfe335985860e
1 // Copyright (c) 2012 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.
5 #include "ppapi/shared_impl/var_tracker.h"
7 #include <string.h>
9 #include <limits>
11 #include "base/logging.h"
12 #include "base/memory/shared_memory.h"
13 #include "ppapi/shared_impl/host_resource.h"
14 #include "ppapi/shared_impl/id_assignment.h"
15 #include "ppapi/shared_impl/proxy_lock.h"
16 #include "ppapi/shared_impl/resource_var.h"
17 #include "ppapi/shared_impl/var.h"
19 namespace ppapi {
21 VarTracker::VarInfo::VarInfo()
22 : var(), ref_count(0), track_with_no_reference_count(0) {}
24 VarTracker::VarInfo::VarInfo(Var* v, int input_ref_count)
25 : var(v), ref_count(input_ref_count), track_with_no_reference_count(0) {}
27 VarTracker::VarTracker(ThreadMode thread_mode) : last_var_id_(0) {
28 if (thread_mode == SINGLE_THREADED)
29 thread_checker_.reset(new base::ThreadChecker);
32 VarTracker::~VarTracker() {}
34 void VarTracker::CheckThreadingPreconditions() const {
35 DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
36 #ifndef NDEBUG
37 ProxyLock::AssertAcquired();
38 #endif
41 int32 VarTracker::AddVar(Var* var) {
42 CheckThreadingPreconditions();
44 return AddVarInternal(var, ADD_VAR_TAKE_ONE_REFERENCE);
47 Var* VarTracker::GetVar(int32 var_id) const {
48 CheckThreadingPreconditions();
50 VarMap::const_iterator result = live_vars_.find(var_id);
51 if (result == live_vars_.end())
52 return NULL;
53 return result->second.var.get();
56 Var* VarTracker::GetVar(const PP_Var& var) const {
57 CheckThreadingPreconditions();
59 if (!IsVarTypeRefcounted(var.type))
60 return NULL;
61 return GetVar(static_cast<int32>(var.value.as_id));
64 bool VarTracker::AddRefVar(int32 var_id) {
65 CheckThreadingPreconditions();
67 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
68 << var_id << " is not a PP_Var ID.";
69 VarMap::iterator found = live_vars_.find(var_id);
70 if (found == live_vars_.end()) {
71 NOTREACHED(); // Invalid var.
72 return false;
75 VarInfo& info = found->second;
76 if (info.ref_count == 0) {
77 // All live vars with no refcount should be tracked objects.
78 DCHECK(info.track_with_no_reference_count > 0);
79 DCHECK(info.var->GetType() == PP_VARTYPE_OBJECT);
81 TrackedObjectGettingOneRef(found);
84 // Basic refcount increment.
85 info.ref_count++;
86 return true;
89 bool VarTracker::AddRefVar(const PP_Var& var) {
90 CheckThreadingPreconditions();
92 if (!IsVarTypeRefcounted(var.type))
93 return true;
94 return AddRefVar(static_cast<int32>(var.value.as_id));
97 bool VarTracker::ReleaseVar(int32 var_id) {
98 CheckThreadingPreconditions();
100 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
101 << var_id << " is not a PP_Var ID.";
102 VarMap::iterator found = live_vars_.find(var_id);
103 if (found == live_vars_.end())
104 return false;
106 VarInfo& info = found->second;
107 if (info.ref_count == 0) {
108 NOTREACHED() << "Releasing an object with zero ref";
109 return false;
111 info.ref_count--;
113 if (info.ref_count == 0) {
114 // Hold a reference to the Var until it is erased so that we don't re-enter
115 // live_vars_.erase() during deletion.
116 // TODO(raymes): Make deletion of Vars iterative instead of recursive.
117 scoped_refptr<Var> var(info.var);
118 if (var->GetType() == PP_VARTYPE_OBJECT) {
119 // Objects have special requirements and may not necessarily be released
120 // when the refcount goes to 0.
121 ObjectGettingZeroRef(found);
122 } else {
123 // All other var types can just be released.
124 DCHECK(info.track_with_no_reference_count == 0);
125 var->ResetVarID();
126 live_vars_.erase(found);
129 return true;
132 bool VarTracker::ReleaseVar(const PP_Var& var) {
133 CheckThreadingPreconditions();
135 if (!IsVarTypeRefcounted(var.type))
136 return false;
137 return ReleaseVar(static_cast<int32>(var.value.as_id));
140 int32 VarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
141 // If the plugin manages to create millions of strings.
142 if (last_var_id_ == std::numeric_limits<int32>::max() >> kPPIdTypeBits)
143 return 0;
145 int32 new_id = MakeTypedId(++last_var_id_, PP_ID_TYPE_VAR);
146 std::pair<VarMap::iterator, bool> was_inserted =
147 live_vars_.insert(std::make_pair(
148 new_id, VarInfo(var, mode == ADD_VAR_TAKE_ONE_REFERENCE ? 1 : 0)));
149 // We should never insert an ID that already exists.
150 DCHECK(was_inserted.second);
152 return new_id;
155 VarTracker::VarMap::iterator VarTracker::GetLiveVar(int32 id) {
156 return live_vars_.find(id);
159 int VarTracker::GetRefCountForObject(const PP_Var& plugin_object) {
160 CheckThreadingPreconditions();
162 VarMap::iterator found = GetLiveVar(plugin_object);
163 if (found == live_vars_.end())
164 return -1;
165 return found->second.ref_count;
168 int VarTracker::GetTrackedWithNoReferenceCountForObject(
169 const PP_Var& plugin_object) {
170 CheckThreadingPreconditions();
172 VarMap::iterator found = GetLiveVar(plugin_object);
173 if (found == live_vars_.end())
174 return -1;
175 return found->second.track_with_no_reference_count;
178 // static
179 bool VarTracker::IsVarTypeRefcounted(PP_VarType type) {
180 return type >= PP_VARTYPE_STRING;
183 VarTracker::VarMap::iterator VarTracker::GetLiveVar(const PP_Var& var) {
184 return live_vars_.find(static_cast<int32>(var.value.as_id));
187 VarTracker::VarMap::const_iterator VarTracker::GetLiveVar(const PP_Var& var)
188 const {
189 return live_vars_.find(static_cast<int32>(var.value.as_id));
192 PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes) {
193 CheckThreadingPreconditions();
195 scoped_refptr<ArrayBufferVar> array_buffer(CreateArrayBuffer(size_in_bytes));
196 if (!array_buffer.get())
197 return PP_MakeNull();
198 return array_buffer->GetPPVar();
201 PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
202 const void* data) {
203 CheckThreadingPreconditions();
205 ArrayBufferVar* array_buffer = MakeArrayBufferVar(size_in_bytes, data);
206 return array_buffer ? array_buffer->GetPPVar() : PP_MakeNull();
209 ArrayBufferVar* VarTracker::MakeArrayBufferVar(uint32 size_in_bytes,
210 const void* data) {
211 CheckThreadingPreconditions();
213 ArrayBufferVar* array_buffer(CreateArrayBuffer(size_in_bytes));
214 if (!array_buffer)
215 return NULL;
216 memcpy(array_buffer->Map(), data, size_in_bytes);
217 return array_buffer;
220 PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
221 base::SharedMemoryHandle handle) {
222 CheckThreadingPreconditions();
224 scoped_refptr<ArrayBufferVar> array_buffer(
225 CreateShmArrayBuffer(size_in_bytes, handle));
226 if (!array_buffer.get())
227 return PP_MakeNull();
228 return array_buffer->GetPPVar();
231 PP_Var VarTracker::MakeResourcePPVar(PP_Resource pp_resource) {
232 CheckThreadingPreconditions();
234 ResourceVar* resource_var = MakeResourceVar(pp_resource);
235 return resource_var ? resource_var->GetPPVar() : PP_MakeNull();
238 std::vector<PP_Var> VarTracker::GetLiveVars() {
239 CheckThreadingPreconditions();
241 std::vector<PP_Var> var_vector;
242 var_vector.reserve(live_vars_.size());
243 for (VarMap::const_iterator iter = live_vars_.begin();
244 iter != live_vars_.end();
245 ++iter) {
246 var_vector.push_back(iter->second.var->GetPPVar());
248 return var_vector;
251 void VarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator obj) {
252 // Anybody using tracked objects should override this.
253 NOTREACHED();
256 void VarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
257 DeleteObjectInfoIfNecessary(iter);
260 bool VarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
261 if (iter->second.ref_count != 0 ||
262 iter->second.track_with_no_reference_count != 0)
263 return false; // Object still alive.
264 iter->second.var->ResetVarID();
265 live_vars_.erase(iter);
266 return true;
269 } // namespace ppapi