Utils.h (12543B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef Utils_h 6 #define Utils_h 7 8 #include <pthread.h> 9 #include <stdint.h> 10 #include <stddef.h> 11 #include <sys/mman.h> 12 #include <unistd.h> 13 #include "mozilla/Assertions.h" 14 #include "mozilla/Atomics.h" 15 16 /** 17 * On architectures that are little endian and that support unaligned reads, 18 * we can use direct type, but on others, we want to have a special class 19 * to handle conversion and alignment issues. 20 */ 21 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__)) 22 typedef uint16_t le_uint16; 23 typedef uint32_t le_uint32; 24 #else 25 26 /** 27 * Template that allows to find an unsigned int type from a (computed) bit size 28 */ 29 template <int s> 30 struct UInt {}; 31 template <> 32 struct UInt<16> { 33 typedef uint16_t Type; 34 }; 35 template <> 36 struct UInt<32> { 37 typedef uint32_t Type; 38 }; 39 40 /** 41 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing 42 * conversion from little endian and avoiding alignment issues. 43 */ 44 template <typename T> 45 class le_to_cpu { 46 public: 47 typedef typename UInt<16 * sizeof(T)>::Type Type; 48 49 operator Type() const { return (b << (sizeof(T) * 8)) | a; } 50 51 const le_to_cpu& operator=(const Type& v) { 52 a = v & ((1 << (sizeof(T) * 8)) - 1); 53 b = v >> (sizeof(T) * 8); 54 return *this; 55 } 56 57 le_to_cpu() {} 58 explicit le_to_cpu(const Type& v) { operator=(v); } 59 60 const le_to_cpu& operator+=(const Type& v) { 61 return operator=(operator Type() + v); 62 } 63 64 const le_to_cpu& operator++(int) { return operator=(operator Type() + 1); } 65 66 private: 67 T a, b; 68 }; 69 70 /** 71 * Type definitions 72 */ 73 typedef le_to_cpu<unsigned char> le_uint16; 74 typedef le_to_cpu<le_uint16> le_uint32; 75 #endif 76 77 struct AutoCloseFD { 78 const int fd; 79 80 MOZ_IMPLICIT AutoCloseFD(int fd) : fd(fd) {} 81 ~AutoCloseFD() { 82 if (fd != -1) close(fd); 83 } 84 operator int() const { return fd; } 85 }; 86 87 extern mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gPageSize; 88 89 /** 90 * Page alignment helpers 91 */ 92 static size_t PageSize() { 93 if (!gPageSize) { 94 gPageSize = sysconf(_SC_PAGESIZE); 95 } 96 97 return gPageSize; 98 } 99 100 static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment) { 101 return ptr & ~(alignment - 1); 102 } 103 104 template <typename T> 105 static inline T* AlignedPtr(T* ptr, size_t alignment) { 106 return reinterpret_cast<T*>( 107 AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); 108 } 109 110 template <typename T> 111 static inline T PageAlignedPtr(T ptr) { 112 return AlignedPtr(ptr, PageSize()); 113 } 114 115 static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment) { 116 return AlignedPtr(ptr + alignment - 1, alignment); 117 } 118 119 template <typename T> 120 static inline T* AlignedEndPtr(T* ptr, size_t alignment) { 121 return reinterpret_cast<T*>( 122 AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment)); 123 } 124 125 template <typename T> 126 static inline T PageAlignedEndPtr(T ptr) { 127 return AlignedEndPtr(ptr, PageSize()); 128 } 129 130 static inline size_t AlignedSize(size_t size, size_t alignment) { 131 return (size + alignment - 1) & ~(alignment - 1); 132 } 133 134 static inline size_t PageAlignedSize(size_t size) { 135 return AlignedSize(size, PageSize()); 136 } 137 138 static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment) { 139 return ptr % alignment == 0; 140 } 141 142 template <typename T> 143 static inline bool IsAlignedPtr(T* ptr, size_t alignment) { 144 return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment); 145 } 146 147 template <typename T> 148 static inline bool IsPageAlignedPtr(T ptr) { 149 return IsAlignedPtr(ptr, PageSize()); 150 } 151 152 static inline bool IsAlignedSize(size_t size, size_t alignment) { 153 return size % alignment == 0; 154 } 155 156 static inline bool IsPageAlignedSize(size_t size) { 157 return IsAlignedSize(size, PageSize()); 158 } 159 160 static inline size_t PageNumber(size_t size) { 161 return (size + PageSize() - 1) / PageSize(); 162 } 163 164 /** 165 * MemoryRange stores a pointer, size pair. 166 */ 167 class MemoryRange { 168 public: 169 MemoryRange(void* buf, size_t length) : buf(buf), length(length) {} 170 171 void Assign(void* b, size_t len) { 172 buf = b; 173 length = len; 174 } 175 176 void Assign(const MemoryRange& other) { 177 buf = other.buf; 178 length = other.length; 179 } 180 181 void* get() const { return buf; } 182 183 operator void*() const { return buf; } 184 185 operator unsigned char*() const { 186 return reinterpret_cast<unsigned char*>(buf); 187 } 188 189 bool operator==(void* ptr) const { return buf == ptr; } 190 191 bool operator==(unsigned char* ptr) const { return buf == ptr; } 192 193 void* operator+(off_t offset) const { 194 return reinterpret_cast<char*>(buf) + offset; 195 } 196 197 /** 198 * Returns whether the given address is within the mapped range 199 */ 200 bool Contains(void* ptr) const { 201 return (ptr >= buf) && (ptr < reinterpret_cast<char*>(buf) + length); 202 } 203 204 /** 205 * Returns the length of the mapped range 206 */ 207 size_t GetLength() const { return length; } 208 209 static MemoryRange mmap(void* addr, size_t length, int prot, int flags, 210 int fd, off_t offset) { 211 return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length); 212 } 213 214 private: 215 void* buf; 216 size_t length; 217 }; 218 219 /** 220 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as 221 * a simple void * or unsigned char *. 222 * 223 * It is defined as a derivative of a template that allows to use a 224 * different unmapping strategy. 225 */ 226 template <typename T> 227 class GenericMappedPtr : public MemoryRange { 228 public: 229 GenericMappedPtr(void* buf, size_t length) : MemoryRange(buf, length) {} 230 explicit GenericMappedPtr(const MemoryRange& other) : MemoryRange(other) {} 231 GenericMappedPtr() : MemoryRange(MAP_FAILED, 0) {} 232 233 void Assign(void* b, size_t len) { 234 if (get() != MAP_FAILED) static_cast<T*>(this)->munmap(get(), GetLength()); 235 MemoryRange::Assign(b, len); 236 } 237 238 void Assign(const MemoryRange& other) { 239 Assign(other.get(), other.GetLength()); 240 } 241 242 ~GenericMappedPtr() { 243 if (get() != MAP_FAILED) static_cast<T*>(this)->munmap(get(), GetLength()); 244 } 245 246 void release() { MemoryRange::Assign(MAP_FAILED, 0); } 247 }; 248 249 struct MappedPtr : public GenericMappedPtr<MappedPtr> { 250 MappedPtr(void* buf, size_t length) 251 : GenericMappedPtr<MappedPtr>(buf, length) {} 252 MOZ_IMPLICIT MappedPtr(const MemoryRange& other) 253 : GenericMappedPtr<MappedPtr>(other) {} 254 MappedPtr() : GenericMappedPtr<MappedPtr>() {} 255 256 private: 257 friend class GenericMappedPtr<MappedPtr>; 258 void munmap(void* buf, size_t length) { ::munmap(buf, length); } 259 }; 260 261 /** 262 * UnsizedArray is a way to access raw arrays of data in memory. 263 * 264 * struct S { ... }; 265 * UnsizedArray<S> a(buf); 266 * UnsizedArray<S> b; b.Init(buf); 267 * 268 * This is roughly equivalent to 269 * const S *a = reinterpret_cast<const S *>(buf); 270 * const S *b = nullptr; b = reinterpret_cast<const S *>(buf); 271 * 272 * An UnsizedArray has no known length, and it's up to the caller to make 273 * sure the accessed memory is mapped and makes sense. 274 */ 275 template <typename T> 276 class UnsizedArray { 277 public: 278 typedef size_t idx_t; 279 280 /** 281 * Constructors and Initializers 282 */ 283 UnsizedArray() : contents(nullptr) {} 284 explicit UnsizedArray(const void* buf) 285 : contents(reinterpret_cast<const T*>(buf)) {} 286 287 void Init(const void* buf) { 288 MOZ_ASSERT(contents == nullptr); 289 contents = reinterpret_cast<const T*>(buf); 290 } 291 292 /** 293 * Returns the nth element of the array 294 */ 295 const T& operator[](const idx_t index) const { 296 MOZ_ASSERT(contents); 297 return contents[index]; 298 } 299 300 operator const T*() const { return contents; } 301 /** 302 * Returns whether the array points somewhere 303 */ 304 explicit operator bool() const { return contents != nullptr; } 305 306 private: 307 const T* contents; 308 }; 309 310 /** 311 * Array, like UnsizedArray, is a way to access raw arrays of data in memory. 312 * Unlike UnsizedArray, it has a known length, and is enumerable with an 313 * iterator. 314 * 315 * struct S { ... }; 316 * Array<S> a(buf, len); 317 * UnsizedArray<S> b; b.Init(buf, len); 318 * 319 * In the above examples, len is the number of elements in the array. It is 320 * also possible to initialize an Array with the buffer size: 321 * 322 * Array<S> c; c.InitSize(buf, size); 323 * 324 * It is also possible to initialize an Array in two steps, only providing 325 * one data at a time: 326 * 327 * Array<S> d; 328 * d.Init(buf); 329 * d.Init(len); // or d.InitSize(size); 330 * 331 */ 332 template <typename T> 333 class Array : public UnsizedArray<T> { 334 public: 335 typedef typename UnsizedArray<T>::idx_t idx_t; 336 337 /** 338 * Constructors and Initializers 339 */ 340 Array() : UnsizedArray<T>(), length(0) {} 341 Array(const void* buf, const idx_t length) 342 : UnsizedArray<T>(buf), length(length) {} 343 344 void Init(const void* buf) { UnsizedArray<T>::Init(buf); } 345 346 void Init(const idx_t len) { 347 MOZ_ASSERT(length == 0); 348 length = len; 349 } 350 351 void InitSize(const idx_t size) { Init(size / sizeof(T)); } 352 353 void Init(const void* buf, const idx_t len) { 354 UnsizedArray<T>::Init(buf); 355 Init(len); 356 } 357 358 void InitSize(const void* buf, const idx_t size) { 359 UnsizedArray<T>::Init(buf); 360 InitSize(size); 361 } 362 363 /** 364 * Returns the nth element of the array 365 */ 366 const T& operator[](const idx_t index) const { 367 MOZ_ASSERT(index < length); 368 MOZ_ASSERT(operator bool()); 369 return UnsizedArray<T>::operator[](index); 370 } 371 372 /** 373 * Returns the number of elements in the array 374 */ 375 idx_t numElements() const { return length; } 376 377 /** 378 * Returns whether the array points somewhere and has at least one element. 379 */ 380 explicit operator bool() const { 381 return (length > 0) && UnsizedArray<T>::operator bool(); 382 } 383 384 /** 385 * Iterator for an Array. Use is similar to that of STL const_iterators: 386 * 387 * struct S { ... }; 388 * Array<S> a(buf, len); 389 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) { 390 * // Do something with *it. 391 * } 392 */ 393 class iterator { 394 public: 395 iterator() : item(nullptr) {} 396 397 const T& operator*() const { return *item; } 398 399 const T* operator->() const { return item; } 400 401 iterator& operator++() { 402 ++item; 403 return *this; 404 } 405 406 bool operator<(const iterator& other) const { return item < other.item; } 407 408 protected: 409 friend class Array<T>; 410 explicit iterator(const T& item) : item(&item) {} 411 412 private: 413 const T* item; 414 }; 415 416 /** 417 * Returns an iterator pointing at the beginning of the Array 418 */ 419 iterator begin() const { 420 if (length) return iterator(UnsizedArray<T>::operator[](0)); 421 return iterator(); 422 } 423 424 /** 425 * Returns an iterator pointing past the end of the Array 426 */ 427 iterator end() const { 428 if (length) return iterator(UnsizedArray<T>::operator[](length)); 429 return iterator(); 430 } 431 432 /** 433 * Reverse iterator for an Array. Use is similar to that of STL 434 * const_reverse_iterators: 435 * 436 * struct S { ... }; 437 * Array<S> a(buf, len); 438 * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) { 439 * // Do something with *it. 440 * } 441 */ 442 class reverse_iterator { 443 public: 444 reverse_iterator() : item(nullptr) {} 445 446 const T& operator*() const { 447 const T* tmp = item; 448 return *--tmp; 449 } 450 451 const T* operator->() const { return &operator*(); } 452 453 reverse_iterator& operator++() { 454 --item; 455 return *this; 456 } 457 458 bool operator<(const reverse_iterator& other) const { 459 return item > other.item; 460 } 461 462 protected: 463 friend class Array<T>; 464 explicit reverse_iterator(const T& item) : item(&item) {} 465 466 private: 467 const T* item; 468 }; 469 470 /** 471 * Returns a reverse iterator pointing at the end of the Array 472 */ 473 reverse_iterator rbegin() const { 474 if (length) return reverse_iterator(UnsizedArray<T>::operator[](length)); 475 return reverse_iterator(); 476 } 477 478 /** 479 * Returns a reverse iterator pointing past the beginning of the Array 480 */ 481 reverse_iterator rend() const { 482 if (length) return reverse_iterator(UnsizedArray<T>::operator[](0)); 483 return reverse_iterator(); 484 } 485 486 private: 487 idx_t length; 488 }; 489 490 /** 491 * Transforms a pointer-to-function to a pointer-to-object pointing at the 492 * same address. 493 */ 494 template <typename T> 495 void* FunctionPtr(T func) { 496 union { 497 void* ptr; 498 T func; 499 } f; 500 f.func = func; 501 return f.ptr; 502 } 503 504 class AutoLock { 505 public: 506 explicit AutoLock(pthread_mutex_t* mutex) : mutex(mutex) { 507 if (pthread_mutex_lock(mutex)) MOZ_CRASH("pthread_mutex_lock failed"); 508 } 509 ~AutoLock() { 510 if (pthread_mutex_unlock(mutex)) MOZ_CRASH("pthread_mutex_unlock failed"); 511 } 512 513 private: 514 pthread_mutex_t* mutex; 515 }; 516 517 #endif /* Utils_h */