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 40namespace 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 45class CpuSet { 46public: 47 // The maximum number of supported CPUs. 48 static const size_t kMaxCpus = 1024; 49 50 CpuSet() { 51 my_memset(mask_, 0, sizeof(mask_)); 52 } 53 54 // Parse a sysfs file to extract the corresponding CPU set. 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. 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. 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 127private: 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