Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef MOJO_SYSTEM_MEMORY_H_ | 5 #ifndef MOJO_SYSTEM_MEMORY_H_ |
| 6 #define MOJO_SYSTEM_MEMORY_H_ | 6 #define MOJO_SYSTEM_MEMORY_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | |
| 10 #include <string.h> // For |memcpy()|. | |
| 9 | 11 |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/scoped_ptr.h" | |
| 10 #include "mojo/public/c/system/macros.h" | 14 #include "mojo/public/c/system/macros.h" |
| 11 #include "mojo/system/system_impl_export.h" | 15 #include "mojo/system/system_impl_export.h" |
| 12 | 16 |
| 13 namespace mojo { | 17 namespace mojo { |
| 14 namespace system { | 18 namespace system { |
| 15 | 19 |
| 16 namespace internal { | 20 namespace internal { |
| 17 | 21 |
| 22 // Removes |const| from |T| (available as |remove_const<T>::type|): | |
|
darin (slow to review)
2014/07/24 16:55:38
Add a TODO about removing these once we can assume
viettrungluu
2014/07/24 17:09:05
Done.
| |
| 23 template <typename T> struct remove_const { typedef T type; }; | |
| 24 template <typename T> struct remove_const<const T> { typedef T type; }; | |
| 25 | |
| 26 // Yields |(const) char| if |T| is |(const) void|, else |T|: | |
| 27 template <typename T> struct void_to_char { typedef T type; }; | |
|
darin (slow to review)
2014/07/24 16:55:38
Should this be VoidToChar? The lower_case name is
viettrungluu
2014/07/24 17:09:05
Done.
| |
| 28 template <> struct void_to_char<void> { typedef char type; }; | |
| 29 template <> struct void_to_char<const void> { typedef const char type; }; | |
| 30 | |
| 31 template <size_t size, size_t alignment> | |
| 32 void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer); | |
| 33 | |
| 34 template <size_t size, size_t alignment> | |
| 35 void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper( | |
| 36 const void* pointer, | |
| 37 size_t count); | |
| 38 | |
| 39 // TODO(vtl): Delete all the |Verify...()| things (and replace them with | |
| 40 // |Check...()|. | |
| 18 template <size_t size, size_t alignment> | 41 template <size_t size, size_t alignment> |
| 19 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer); | 42 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer); |
| 20 | 43 |
| 21 // Note: This is also used by options_validation.h. | 44 // Note: This is also used by options_validation.h. |
| 22 template <size_t size, size_t alignment> | 45 template <size_t size, size_t alignment> |
| 23 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper( | 46 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper( |
| 24 const void* pointer, | 47 const void* pointer, |
| 25 size_t count); | 48 size_t count); |
| 26 | 49 |
| 50 // Forward declarations so that they can be friended. | |
| 51 template <typename Type> class UserPointerReader; | |
| 52 template <typename Type> class UserPointerWriter; | |
| 53 template <typename Type> class UserPointerReaderWriter; | |
| 54 | |
| 27 } // namespace internal | 55 } // namespace internal |
| 28 | 56 |
| 29 // Verify (insofar as possible/necessary) that a |T| can be read from the user | 57 // Verify (insofar as possible/necessary) that a |T| can be read from the user |
| 30 // |pointer|. | 58 // |pointer|. |
| 31 template <typename T> | 59 template <typename T> |
| 32 bool VerifyUserPointer(const T* pointer) { | 60 bool VerifyUserPointer(const T* pointer) { |
| 33 return internal::VerifyUserPointerHelper<sizeof(T), MOJO_ALIGNOF(T)>(pointer); | 61 return internal::VerifyUserPointerHelper<sizeof(T), MOJO_ALIGNOF(T)>(pointer); |
| 34 } | 62 } |
| 35 | 63 |
| 36 // Verify (insofar as possible/necessary) that |count| |T|s can be read from the | 64 // Verify (insofar as possible/necessary) that |count| |T|s can be read from the |
| 37 // user |pointer|; |count| may be zero. (This is done carefully since |count * | 65 // user |pointer|; |count| may be zero. (This is done carefully since |count * |
| 38 // sizeof(T)| may overflow a |size_t|.) | 66 // sizeof(T)| may overflow a |size_t|.) |
| 39 template <typename T> | 67 template <typename T> |
| 40 bool VerifyUserPointerWithCount(const T* pointer, size_t count) { | 68 bool VerifyUserPointerWithCount(const T* pointer, size_t count) { |
| 41 return internal::VerifyUserPointerWithCountHelper<sizeof(T), | 69 return internal::VerifyUserPointerWithCountHelper<sizeof(T), |
| 42 MOJO_ALIGNOF(T)>(pointer, | 70 MOJO_ALIGNOF(T)>(pointer, |
| 43 count); | 71 count); |
| 44 } | 72 } |
| 45 | 73 |
| 46 // Verify that |size| bytes (which may be zero) can be read from the user | 74 // Verify that |size| bytes (which may be zero) can be read from the user |
| 47 // |pointer|, and that |pointer| has the specified |alignment| (if |size| is | 75 // |pointer|, and that |pointer| has the specified |alignment| (if |size| is |
| 48 // nonzero). | 76 // nonzero). |
| 49 template <size_t alignment> | 77 template <size_t alignment> |
| 50 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer, | 78 bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer, |
| 51 size_t size); | 79 size_t size); |
| 52 | 80 |
| 81 // Provides a convenient way to implicitly get null |UserPointer<Type>|s. | |
| 82 struct NullUserPointer {}; | |
| 83 | |
| 84 // Represents a user pointer to a single |Type| (which must be POD), for Mojo | |
| 85 // primitive parameters. | |
| 86 // | |
| 87 // Use a const |Type| for in parameters, and non-const |Type|s for out and | |
| 88 // in-out parameters (in which case the |Put()| method is available). | |
| 89 template <typename Type> | |
| 90 class UserPointer { | |
| 91 public: | |
| 92 // Instead of explicitly using these constructors, you can often use | |
| 93 // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common | |
| 94 // exception is when you have, e.g., a |char*| and want to get a | |
| 95 // |UserPointer<void>|.) | |
| 96 UserPointer() : pointer_(NULL) {} | |
| 97 explicit UserPointer(Type* pointer) : pointer_(pointer) {} | |
| 98 // Allow implicit conversion from the "null user pointer". | |
| 99 UserPointer(NullUserPointer) : pointer_(NULL) {} | |
| 100 ~UserPointer() {} | |
| 101 | |
| 102 // Allow assignment from the "null user pointer". | |
| 103 UserPointer<Type>& operator=(NullUserPointer) { | |
| 104 pointer_ = NULL; | |
| 105 return *this; | |
| 106 } | |
| 107 | |
| 108 // Allow conversion to a "non-const" |UserPointer|. | |
| 109 operator UserPointer<const Type>() const { | |
| 110 return UserPointer<const Type>(pointer_); | |
| 111 } | |
| 112 | |
| 113 bool IsNull() const { | |
| 114 return !pointer_; | |
| 115 } | |
| 116 | |
| 117 // We want to force a copy here, so return |Type| not |const Type&|. | |
| 118 Type Get() const { | |
| 119 internal::CheckUserPointerHelper<sizeof(Type), | |
| 120 MOJO_ALIGNOF(Type)>(pointer_); | |
| 121 return *pointer_; | |
| 122 } | |
| 123 | |
| 124 // Note: This |Put()| method is not valid when |T| is const, e.g., |const | |
| 125 // uint32_t|, but it's okay to include them so long as this template is only | |
| 126 // implicitly instantiated (see 14.7.1 of the C++11 standard) and not | |
| 127 // explicitly instantiated. (On implicit instantiation, only the declarations | |
| 128 // need be valid, not the definitions.) | |
| 129 // | |
| 130 // If |Type| is |void|, we "convert" it to |char|, so that it makes sense. | |
| 131 // (Otherwise, we'd need a suitable specialization to exclude |Put()|.) | |
| 132 // | |
| 133 // In C++11, we could do something like: | |
| 134 // template <typename _Type = Type> | |
| 135 // typename enable_if<!is_const<_Type>::value && | |
| 136 // !is_void<_Type>::value>::type Put( | |
| 137 // const _Type& value) { ... } | |
| 138 // (which obviously be correct), but C++03 doesn't allow default function | |
| 139 // template arguments. | |
| 140 void Put(const typename internal::void_to_char<Type>::type& value) { | |
| 141 internal::CheckUserPointerHelper<sizeof(Type), | |
| 142 MOJO_ALIGNOF(Type)>(pointer_); | |
| 143 *pointer_ = value; | |
| 144 } | |
| 145 | |
| 146 UserPointer At(size_t i) const { | |
| 147 return UserPointer(pointer_ + i); | |
| 148 } | |
| 149 | |
| 150 // TODO(vtl): This is temporary. Get rid of this. (We should pass | |
| 151 // |UserPointer<>|s along appropriately, or access data in a safe way | |
| 152 // everywhere.) | |
| 153 Type* GetPointerUnsafe() const { | |
| 154 return pointer_; | |
| 155 } | |
| 156 | |
| 157 // These provides safe (read-only/write-only/read-and-write) access to a | |
| 158 // |UserPointer<Type>| (probably pointing to an array) using just an ordinary | |
| 159 // pointer (obtained via |GetPointer()|). | |
| 160 // | |
| 161 // The memory returned by |GetPointer()| may be a copy of the original user | |
| 162 // memory, but should be modified only if the user is intended to eventually | |
| 163 // see the change.) If any changes are made, |Commit()| should be called to | |
| 164 // guarantee that the changes are written back to user memory (it may be | |
| 165 // called multiple times). | |
| 166 // | |
| 167 // Note: These classes are designed to allow fast, unsafe implementations (in | |
| 168 // which |GetPointer()| just returns the user pointer) if desired. Thus if | |
| 169 // |Commit()| is *not* called, changes may or may not be made visible to the | |
| 170 // user. | |
| 171 // | |
| 172 // Use these classes in the following way: | |
| 173 // | |
| 174 // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos, | |
| 175 // uint32_t num_foos) { | |
| 176 // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos); | |
| 177 // return PutFoosImpl(foos_reader.GetPointer(), num_foos); | |
| 178 // } | |
| 179 // | |
| 180 // MojoResult Core::GetFoos(UserPointer<uint32_t> foos, | |
| 181 // uint32_t num_foos) { | |
| 182 // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos); | |
| 183 // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos); | |
| 184 // foos_writer.Commit(); | |
| 185 // return rv; | |
| 186 // } | |
| 187 // | |
| 188 // TODO(vtl): Possibly, since we're not really being safe, we should just not | |
| 189 // copy for Release builds. | |
| 190 typedef internal::UserPointerReader<Type> Reader; | |
| 191 typedef internal::UserPointerWriter<Type> Writer; | |
| 192 typedef internal::UserPointerReaderWriter<Type> ReaderWriter; | |
| 193 | |
| 194 private: | |
| 195 friend class internal::UserPointerReader<Type>; | |
| 196 friend class internal::UserPointerWriter<Type>; | |
| 197 friend class internal::UserPointerReaderWriter<Type>; | |
| 198 | |
| 199 Type* pointer_; | |
| 200 // Allow copy and assignment. | |
| 201 }; | |
| 202 | |
| 203 // Provides a convenient way to make a |UserPointer<Type>|. | |
| 204 template <typename Type> | |
| 205 inline UserPointer<Type> MakeUserPointer(Type* pointer) { | |
| 206 return UserPointer<Type>(pointer); | |
| 207 } | |
| 208 | |
| 209 namespace internal { | |
|
darin (slow to review)
2014/07/24 16:55:38
hmm... do these really belong in the internal name
viettrungluu
2014/07/24 17:09:05
Yeah, I wasn't sure. Done, since you're probably r
| |
| 210 | |
| 211 // Implementation of |UserPointer<Type>::Reader|. | |
| 212 template <typename Type> | |
| 213 class UserPointerReader { | |
| 214 private: | |
| 215 typedef typename internal::remove_const<Type>::type TypeNoConst; | |
| 216 | |
| 217 public: | |
| 218 UserPointerReader(UserPointer<const Type> user_pointer, size_t count) { | |
| 219 Init(user_pointer.pointer_, count); | |
| 220 } | |
| 221 UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) { | |
| 222 Init(user_pointer.pointer_, count); | |
| 223 } | |
| 224 | |
| 225 const Type* GetPointer() const { return buffer_.get(); } | |
| 226 | |
| 227 private: | |
| 228 void Init(const Type* user_pointer, size_t count) { | |
| 229 internal::CheckUserPointerWithCountHelper< | |
| 230 sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer, count); | |
| 231 buffer_.reset(new TypeNoConst[count]); | |
| 232 memcpy(buffer_.get(), user_pointer, count * sizeof(Type)); | |
| 233 } | |
| 234 | |
| 235 scoped_ptr<TypeNoConst[]> buffer_; | |
| 236 | |
| 237 DISALLOW_COPY_AND_ASSIGN(UserPointerReader); | |
| 238 }; | |
| 239 | |
| 240 // Implementation of |UserPointer<Type>::Writer|. | |
| 241 template <typename Type> | |
| 242 class UserPointerWriter { | |
| 243 public: | |
| 244 UserPointerWriter(UserPointer<Type> user_pointer, size_t count) | |
| 245 : user_pointer_(user_pointer), | |
| 246 count_(count) { | |
| 247 buffer_.reset(new Type[count_]); | |
| 248 memset(buffer_.get(), 0, count_ * sizeof(Type)); | |
| 249 } | |
| 250 | |
| 251 Type* GetPointer() const { return buffer_.get(); } | |
| 252 | |
| 253 void Commit() { | |
| 254 internal::CheckUserPointerWithCountHelper< | |
| 255 sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); | |
| 256 memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); | |
| 257 } | |
| 258 | |
| 259 private: | |
| 260 UserPointer<Type> user_pointer_; | |
| 261 size_t count_; | |
| 262 scoped_ptr<Type[]> buffer_; | |
| 263 | |
| 264 DISALLOW_COPY_AND_ASSIGN(UserPointerWriter); | |
| 265 }; | |
| 266 | |
| 267 // Implementation of |UserPointer<Type>::ReaderWriter|. | |
| 268 template <typename Type> | |
| 269 class UserPointerReaderWriter { | |
| 270 public: | |
| 271 UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count) | |
| 272 : user_pointer_(user_pointer), | |
| 273 count_(count) { | |
| 274 internal::CheckUserPointerWithCountHelper< | |
| 275 sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); | |
| 276 buffer_.reset(new Type[count]); | |
| 277 memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type)); | |
| 278 } | |
| 279 | |
| 280 Type* GetPointer() const { return buffer_.get(); } | |
| 281 size_t GetCount() const { return count_; } | |
| 282 | |
| 283 void Commit() { | |
| 284 internal::CheckUserPointerWithCountHelper< | |
| 285 sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_); | |
| 286 memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); | |
| 287 } | |
| 288 | |
| 289 private: | |
| 290 UserPointer<Type> user_pointer_; | |
| 291 size_t count_; | |
| 292 scoped_ptr<Type[]> buffer_; | |
| 293 | |
| 294 DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter); | |
| 295 }; | |
| 296 | |
| 297 } // namespace internal | |
| 298 | |
| 299 // Represents a user pointer that will never be dereferenced by the system. The | |
| 300 // pointer value (i.e., the address) may be as a key for lookup, or may be a | |
| 301 // value that is only passed to the user at some point. | |
| 302 template <typename Type> | |
| 303 class UserPointerValue { | |
| 304 public: | |
| 305 UserPointerValue() : pointer_() {} | |
| 306 explicit UserPointerValue(Type* pointer) : pointer_(pointer) {} | |
| 307 ~UserPointerValue() {} | |
| 308 | |
| 309 // Returns the *value* of the pointer, which shouldn't be cast back to a | |
| 310 // pointer and dereferenced. | |
| 311 uintptr_t GetValue() const { | |
| 312 return reinterpret_cast<uintptr_t>(pointer_); | |
| 313 } | |
| 314 | |
| 315 private: | |
| 316 Type* pointer_; | |
| 317 // Allow copy and assignment. | |
| 318 }; | |
| 319 | |
| 320 // Provides a convenient way to make a |UserPointerValue<Type>|. | |
| 321 template <typename Type> | |
| 322 inline UserPointerValue<Type> MakeUserPointerValue(Type* pointer) { | |
| 323 return UserPointerValue<Type>(pointer); | |
| 324 } | |
| 325 | |
| 53 } // namespace system | 326 } // namespace system |
| 54 } // namespace mojo | 327 } // namespace mojo |
| 55 | 328 |
| 56 #endif // MOJO_SYSTEM_MEMORY_H_ | 329 #endif // MOJO_SYSTEM_MEMORY_H_ |
| OLD | NEW |