Home | History | Annotate | Download | only in minidump_writer
      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 
     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 
    127 private:
    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