1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "utils.h"
18
19#include <inttypes.h>
20#include <pthread.h>
21#include <sys/stat.h>
22#include <sys/syscall.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h>
26
27#include <memory>
28
29#include "android-base/file.h"
30#include "android-base/stringprintf.h"
31#include "android-base/strings.h"
32
33#include "base/os.h"
34
35#if defined(__APPLE__)
36#include <crt_externs.h>
37#include <sys/syscall.h>
38#include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
39#endif
40
41#if defined(__linux__)
42#include <linux/unistd.h>
43#endif
44
45namespace art {
46
47using android::base::ReadFileToString;
48using android::base::StringAppendF;
49using android::base::StringPrintf;
50
51pid_t GetTid() {
52#if defined(__APPLE__)
53  uint64_t owner;
54  CHECK_PTHREAD_CALL(pthread_threadid_np, (nullptr, &owner), __FUNCTION__);  // Requires Mac OS 10.6
55  return owner;
56#elif defined(__BIONIC__)
57  return gettid();
58#else
59  return syscall(__NR_gettid);
60#endif
61}
62
63std::string GetThreadName(pid_t tid) {
64  std::string result;
65  // TODO: make this less Linux-specific.
66  if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) {
67    result.resize(result.size() - 1);  // Lose the trailing '\n'.
68  } else {
69    result = "<unknown>";
70  }
71  return result;
72}
73
74std::string PrettySize(int64_t byte_count) {
75  // The byte thresholds at which we display amounts.  A byte count is displayed
76  // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
77  static const int64_t kUnitThresholds[] = {
78    0,              // B up to...
79    3*1024,         // KB up to...
80    2*1024*1024,    // MB up to...
81    1024*1024*1024  // GB from here.
82  };
83  static const int64_t kBytesPerUnit[] = { 1, KB, MB, GB };
84  static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" };
85  const char* negative_str = "";
86  if (byte_count < 0) {
87    negative_str = "-";
88    byte_count = -byte_count;
89  }
90  int i = arraysize(kUnitThresholds);
91  while (--i > 0) {
92    if (byte_count >= kUnitThresholds[i]) {
93      break;
94    }
95  }
96  return StringPrintf("%s%" PRId64 "%s",
97                      negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]);
98}
99
100void Split(const std::string& s, char separator, std::vector<std::string>* result) {
101  const char* p = s.data();
102  const char* end = p + s.size();
103  while (p != end) {
104    if (*p == separator) {
105      ++p;
106    } else {
107      const char* start = p;
108      while (++p != end && *p != separator) {
109        // Skip to the next occurrence of the separator.
110      }
111      result->push_back(std::string(start, p - start));
112    }
113  }
114}
115
116void SetThreadName(const char* thread_name) {
117  int hasAt = 0;
118  int hasDot = 0;
119  const char* s = thread_name;
120  while (*s) {
121    if (*s == '.') {
122      hasDot = 1;
123    } else if (*s == '@') {
124      hasAt = 1;
125    }
126    s++;
127  }
128  int len = s - thread_name;
129  if (len < 15 || hasAt || !hasDot) {
130    s = thread_name;
131  } else {
132    s = thread_name + len - 15;
133  }
134#if defined(__linux__)
135  // pthread_setname_np fails rather than truncating long strings.
136  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.
137  strncpy(buf, s, sizeof(buf)-1);
138  buf[sizeof(buf)-1] = '\0';
139  errno = pthread_setname_np(pthread_self(), buf);
140  if (errno != 0) {
141    PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
142  }
143#else  // __APPLE__
144  pthread_setname_np(thread_name);
145#endif
146}
147
148void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) {
149  *utime = *stime = *task_cpu = 0;
150  std::string stats;
151  // TODO: make this less Linux-specific.
152  if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
153    return;
154  }
155  // Skip the command, which may contain spaces.
156  stats = stats.substr(stats.find(')') + 2);
157  // Extract the three fields we care about.
158  std::vector<std::string> fields;
159  Split(stats, ' ', &fields);
160  *state = fields[0][0];
161  *utime = strtoull(fields[11].c_str(), nullptr, 10);
162  *stime = strtoull(fields[12].c_str(), nullptr, 10);
163  *task_cpu = strtoull(fields[36].c_str(), nullptr, 10);
164}
165
166static void ParseStringAfterChar(const std::string& s,
167                                 char c,
168                                 std::string* parsed_value,
169                                 UsageFn Usage) {
170  std::string::size_type colon = s.find(c);
171  if (colon == std::string::npos) {
172    Usage("Missing char %c in option %s\n", c, s.c_str());
173  }
174  // Add one to remove the char we were trimming until.
175  *parsed_value = s.substr(colon + 1);
176}
177
178void ParseDouble(const std::string& option,
179                 char after_char,
180                 double min,
181                 double max,
182                 double* parsed_value,
183                 UsageFn Usage) {
184  std::string substring;
185  ParseStringAfterChar(option, after_char, &substring, Usage);
186  bool sane_val = true;
187  double value;
188  if ((false)) {
189    // TODO: this doesn't seem to work on the emulator.  b/15114595
190    std::stringstream iss(substring);
191    iss >> value;
192    // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
193    sane_val = iss.eof() && (value >= min) && (value <= max);
194  } else {
195    char* end = nullptr;
196    value = strtod(substring.c_str(), &end);
197    sane_val = *end == '\0' && value >= min && value <= max;
198  }
199  if (!sane_val) {
200    Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str());
201  }
202  *parsed_value = value;
203}
204
205void SleepForever() {
206  while (true) {
207    usleep(1000000);
208  }
209}
210
211}  // namespace art
212