1 // Copyright (c) 2013, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #ifndef CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ 31 #define CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ 32 33 #include <stdint.h> 34 #include <assert.h> 35 #include <string.h> 36 37 #include "common/linux/linux_libc_support.h" 38 #include "third_party/lss/linux_syscall_support.h" 39 40 namespace google_breakpad { 41 42 // Helper class used to model a set of CPUs, as read from sysfs 43 // files like /sys/devices/system/cpu/present 44 // See See http://www.kernel.org/doc/Documentation/cputopology.txt 45 class CpuSet { 46 public: 47 // The maximum number of supported CPUs. 48 static const size_t kMaxCpus = 1024; 49 CpuSet()50 CpuSet() { 51 my_memset(mask_, 0, sizeof(mask_)); 52 } 53 54 // Parse a sysfs file to extract the corresponding CPU set. ParseSysFile(int fd)55 bool ParseSysFile(int fd) { 56 char buffer[512]; 57 int ret = sys_read(fd, buffer, sizeof(buffer)-1); 58 if (ret < 0) 59 return false; 60 61 buffer[ret] = '\0'; 62 63 // Expected format: comma-separated list of items, where each 64 // item can be a decimal integer, or two decimal integers separated 65 // by a dash. 66 // E.g.: 67 // 0 68 // 0,1,2,3 69 // 0-3 70 // 1,10-23 71 const char* p = buffer; 72 const char* p_end = p + ret; 73 while (p < p_end) { 74 // Skip leading space, if any 75 while (p < p_end && my_isspace(*p)) 76 p++; 77 78 // Find start and size of current item. 79 const char* item = p; 80 size_t item_len = static_cast<size_t>(p_end - p); 81 const char* item_next = 82 static_cast<const char*>(my_memchr(p, ',', item_len)); 83 if (item_next != NULL) { 84 p = item_next + 1; 85 item_len = static_cast<size_t>(item_next - item); 86 } else { 87 p = p_end; 88 item_next = p_end; 89 } 90 91 // Ignore trailing spaces. 92 while (item_next > item && my_isspace(item_next[-1])) 93 item_next--; 94 95 // skip empty items. 96 if (item_next == item) 97 continue; 98 99 // read first decimal value. 100 uintptr_t start = 0; 101 const char* next = my_read_decimal_ptr(&start, item); 102 uintptr_t end = start; 103 if (*next == '-') 104 my_read_decimal_ptr(&end, next+1); 105 106 while (start <= end) 107 SetBit(start++); 108 } 109 return true; 110 } 111 112 // Intersect this CPU set with another one. IntersectWith(const CpuSet & other)113 void IntersectWith(const CpuSet& other) { 114 for (size_t nn = 0; nn < kMaskWordCount; ++nn) 115 mask_[nn] &= other.mask_[nn]; 116 } 117 118 // Return the number of CPUs in this set. GetCount()119 int GetCount() { 120 int result = 0; 121 for (size_t nn = 0; nn < kMaskWordCount; ++nn) { 122 result += __builtin_popcount(mask_[nn]); 123 } 124 return result; 125 } 126 127 private: SetBit(uintptr_t index)128 void SetBit(uintptr_t index) { 129 size_t nn = static_cast<size_t>(index); 130 if (nn < kMaxCpus) 131 mask_[nn / kMaskWordBits] |= (1U << (nn % kMaskWordBits)); 132 } 133 134 typedef uint32_t MaskWordType; 135 static const size_t kMaskWordBits = 8*sizeof(MaskWordType); 136 static const size_t kMaskWordCount = 137 (kMaxCpus + kMaskWordBits - 1) / kMaskWordBits; 138 139 MaskWordType mask_[kMaskWordCount]; 140 }; 141 142 } // namespace google_breakpad 143 144 #endif // CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ 145