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