1695b41eeSopenharmony_ci// Copyright 2011 Google Inc. All Rights Reserved. 2695b41eeSopenharmony_ci// 3695b41eeSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4695b41eeSopenharmony_ci// you may not use this file except in compliance with the License. 5695b41eeSopenharmony_ci// You may obtain a copy of the License at 6695b41eeSopenharmony_ci// 7695b41eeSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8695b41eeSopenharmony_ci// 9695b41eeSopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10695b41eeSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11695b41eeSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12695b41eeSopenharmony_ci// See the License for the specific language governing permissions and 13695b41eeSopenharmony_ci// limitations under the License. 14695b41eeSopenharmony_ci 15695b41eeSopenharmony_ci#include "util.h" 16695b41eeSopenharmony_ci 17695b41eeSopenharmony_ci#ifdef __CYGWIN__ 18695b41eeSopenharmony_ci#include <windows.h> 19695b41eeSopenharmony_ci#include <io.h> 20695b41eeSopenharmony_ci#elif defined( _WIN32) 21695b41eeSopenharmony_ci#include <windows.h> 22695b41eeSopenharmony_ci#include <io.h> 23695b41eeSopenharmony_ci#include <share.h> 24695b41eeSopenharmony_ci#endif 25695b41eeSopenharmony_ci 26695b41eeSopenharmony_ci#include <assert.h> 27695b41eeSopenharmony_ci#include <errno.h> 28695b41eeSopenharmony_ci#include <fcntl.h> 29695b41eeSopenharmony_ci#include <stdarg.h> 30695b41eeSopenharmony_ci#include <stdio.h> 31695b41eeSopenharmony_ci#include <stdlib.h> 32695b41eeSopenharmony_ci#include <string.h> 33695b41eeSopenharmony_ci#include <sys/stat.h> 34695b41eeSopenharmony_ci#include <sys/types.h> 35695b41eeSopenharmony_ci 36695b41eeSopenharmony_ci#ifndef _WIN32 37695b41eeSopenharmony_ci#include <unistd.h> 38695b41eeSopenharmony_ci#include <sys/time.h> 39695b41eeSopenharmony_ci#endif 40695b41eeSopenharmony_ci 41695b41eeSopenharmony_ci#include <vector> 42695b41eeSopenharmony_ci 43695b41eeSopenharmony_ci#if defined(__APPLE__) || defined(__FreeBSD__) 44695b41eeSopenharmony_ci#include <sys/sysctl.h> 45695b41eeSopenharmony_ci#elif defined(__SVR4) && defined(__sun) 46695b41eeSopenharmony_ci#include <unistd.h> 47695b41eeSopenharmony_ci#include <sys/loadavg.h> 48695b41eeSopenharmony_ci#elif defined(_AIX) && !defined(__PASE__) 49695b41eeSopenharmony_ci#include <libperfstat.h> 50695b41eeSopenharmony_ci#elif defined(linux) || defined(__GLIBC__) 51695b41eeSopenharmony_ci#include <sys/sysinfo.h> 52695b41eeSopenharmony_ci#include <fstream> 53695b41eeSopenharmony_ci#include <map> 54695b41eeSopenharmony_ci#include "string_piece_util.h" 55695b41eeSopenharmony_ci#endif 56695b41eeSopenharmony_ci 57695b41eeSopenharmony_ci#if defined(__FreeBSD__) 58695b41eeSopenharmony_ci#include <sys/cpuset.h> 59695b41eeSopenharmony_ci#endif 60695b41eeSopenharmony_ci 61695b41eeSopenharmony_ci#include "edit_distance.h" 62695b41eeSopenharmony_ci 63695b41eeSopenharmony_ciusing namespace std; 64695b41eeSopenharmony_ci 65695b41eeSopenharmony_civoid Fatal(const char* msg, ...) { 66695b41eeSopenharmony_ci va_list ap; 67695b41eeSopenharmony_ci fprintf(stderr, "ninja: fatal: "); 68695b41eeSopenharmony_ci va_start(ap, msg); 69695b41eeSopenharmony_ci vfprintf(stderr, msg, ap); 70695b41eeSopenharmony_ci va_end(ap); 71695b41eeSopenharmony_ci fprintf(stderr, "\n"); 72695b41eeSopenharmony_ci#ifdef _WIN32 73695b41eeSopenharmony_ci // On Windows, some tools may inject extra threads. 74695b41eeSopenharmony_ci // exit() may block on locks held by those threads, so forcibly exit. 75695b41eeSopenharmony_ci fflush(stderr); 76695b41eeSopenharmony_ci fflush(stdout); 77695b41eeSopenharmony_ci ExitProcess(1); 78695b41eeSopenharmony_ci#else 79695b41eeSopenharmony_ci exit(1); 80695b41eeSopenharmony_ci#endif 81695b41eeSopenharmony_ci} 82695b41eeSopenharmony_ci 83695b41eeSopenharmony_civoid Warning(const char* msg, va_list ap) { 84695b41eeSopenharmony_ci fprintf(stderr, "ninja: warning: "); 85695b41eeSopenharmony_ci vfprintf(stderr, msg, ap); 86695b41eeSopenharmony_ci fprintf(stderr, "\n"); 87695b41eeSopenharmony_ci} 88695b41eeSopenharmony_ci 89695b41eeSopenharmony_civoid Warning(const char* msg, ...) { 90695b41eeSopenharmony_ci va_list ap; 91695b41eeSopenharmony_ci va_start(ap, msg); 92695b41eeSopenharmony_ci Warning(msg, ap); 93695b41eeSopenharmony_ci va_end(ap); 94695b41eeSopenharmony_ci} 95695b41eeSopenharmony_ci 96695b41eeSopenharmony_civoid Error(const char* msg, va_list ap) { 97695b41eeSopenharmony_ci fprintf(stderr, "ninja: error: "); 98695b41eeSopenharmony_ci vfprintf(stderr, msg, ap); 99695b41eeSopenharmony_ci fprintf(stderr, "\n"); 100695b41eeSopenharmony_ci} 101695b41eeSopenharmony_ci 102695b41eeSopenharmony_civoid Error(const char* msg, ...) { 103695b41eeSopenharmony_ci va_list ap; 104695b41eeSopenharmony_ci va_start(ap, msg); 105695b41eeSopenharmony_ci Error(msg, ap); 106695b41eeSopenharmony_ci va_end(ap); 107695b41eeSopenharmony_ci} 108695b41eeSopenharmony_ci 109695b41eeSopenharmony_civoid Info(const char* msg, va_list ap) { 110695b41eeSopenharmony_ci fprintf(stdout, "ninja: "); 111695b41eeSopenharmony_ci vfprintf(stdout, msg, ap); 112695b41eeSopenharmony_ci fprintf(stdout, "\n"); 113695b41eeSopenharmony_ci} 114695b41eeSopenharmony_ci 115695b41eeSopenharmony_civoid Info(const char* msg, ...) { 116695b41eeSopenharmony_ci va_list ap; 117695b41eeSopenharmony_ci va_start(ap, msg); 118695b41eeSopenharmony_ci Info(msg, ap); 119695b41eeSopenharmony_ci va_end(ap); 120695b41eeSopenharmony_ci} 121695b41eeSopenharmony_ci 122695b41eeSopenharmony_civoid CanonicalizePath(string* path, uint64_t* slash_bits) { 123695b41eeSopenharmony_ci size_t len = path->size(); 124695b41eeSopenharmony_ci char* str = 0; 125695b41eeSopenharmony_ci if (len > 0) 126695b41eeSopenharmony_ci str = &(*path)[0]; 127695b41eeSopenharmony_ci CanonicalizePath(str, &len, slash_bits); 128695b41eeSopenharmony_ci path->resize(len); 129695b41eeSopenharmony_ci} 130695b41eeSopenharmony_ci 131695b41eeSopenharmony_cistatic bool IsPathSeparator(char c) { 132695b41eeSopenharmony_ci#ifdef _WIN32 133695b41eeSopenharmony_ci return c == '/' || c == '\\'; 134695b41eeSopenharmony_ci#else 135695b41eeSopenharmony_ci return c == '/'; 136695b41eeSopenharmony_ci#endif 137695b41eeSopenharmony_ci} 138695b41eeSopenharmony_ci 139695b41eeSopenharmony_civoid CanonicalizePath(char* path, size_t* len, uint64_t* slash_bits) { 140695b41eeSopenharmony_ci // WARNING: this function is performance-critical; please benchmark 141695b41eeSopenharmony_ci // any changes you make to it. 142695b41eeSopenharmony_ci if (*len == 0) { 143695b41eeSopenharmony_ci return; 144695b41eeSopenharmony_ci } 145695b41eeSopenharmony_ci 146695b41eeSopenharmony_ci char* start = path; 147695b41eeSopenharmony_ci char* dst = start; 148695b41eeSopenharmony_ci char* dst_start = dst; 149695b41eeSopenharmony_ci const char* src = start; 150695b41eeSopenharmony_ci const char* end = start + *len; 151695b41eeSopenharmony_ci const char* src_next; 152695b41eeSopenharmony_ci 153695b41eeSopenharmony_ci // For absolute paths, skip the leading directory separator 154695b41eeSopenharmony_ci // as this one should never be removed from the result. 155695b41eeSopenharmony_ci if (IsPathSeparator(*src)) { 156695b41eeSopenharmony_ci#ifdef _WIN32 157695b41eeSopenharmony_ci // Windows network path starts with // 158695b41eeSopenharmony_ci if (src + 2 <= end && IsPathSeparator(src[1])) { 159695b41eeSopenharmony_ci src += 2; 160695b41eeSopenharmony_ci dst += 2; 161695b41eeSopenharmony_ci } else { 162695b41eeSopenharmony_ci ++src; 163695b41eeSopenharmony_ci ++dst; 164695b41eeSopenharmony_ci } 165695b41eeSopenharmony_ci#else 166695b41eeSopenharmony_ci ++src; 167695b41eeSopenharmony_ci ++dst; 168695b41eeSopenharmony_ci#endif 169695b41eeSopenharmony_ci dst_start = dst; 170695b41eeSopenharmony_ci } else { 171695b41eeSopenharmony_ci // For relative paths, skip any leading ../ as these are quite common 172695b41eeSopenharmony_ci // to reference source files in build plans, and doing this here makes 173695b41eeSopenharmony_ci // the loop work below faster in general. 174695b41eeSopenharmony_ci while (src + 3 <= end && src[0] == '.' && src[1] == '.' && 175695b41eeSopenharmony_ci IsPathSeparator(src[2])) { 176695b41eeSopenharmony_ci src += 3; 177695b41eeSopenharmony_ci dst += 3; 178695b41eeSopenharmony_ci } 179695b41eeSopenharmony_ci } 180695b41eeSopenharmony_ci 181695b41eeSopenharmony_ci // Loop over all components of the paths _except_ the last one, in 182695b41eeSopenharmony_ci // order to simplify the loop's code and make it faster. 183695b41eeSopenharmony_ci int component_count = 0; 184695b41eeSopenharmony_ci char* dst0 = dst; 185695b41eeSopenharmony_ci for (; src < end; src = src_next) { 186695b41eeSopenharmony_ci#ifndef _WIN32 187695b41eeSopenharmony_ci // Use memchr() for faster lookups thanks to optimized C library 188695b41eeSopenharmony_ci // implementation. `hyperfine canon_perftest` shows a significant 189695b41eeSopenharmony_ci // difference (e,g, 484ms vs 437ms). 190695b41eeSopenharmony_ci const char* next_sep = 191695b41eeSopenharmony_ci static_cast<const char*>(::memchr(src, '/', end - src)); 192695b41eeSopenharmony_ci if (!next_sep) { 193695b41eeSopenharmony_ci // This is the last component, will be handled out of the loop. 194695b41eeSopenharmony_ci break; 195695b41eeSopenharmony_ci } 196695b41eeSopenharmony_ci#else 197695b41eeSopenharmony_ci // Need to check for both '/' and '\\' so do not use memchr(). 198695b41eeSopenharmony_ci // Cannot use strpbrk() because end[0] can be \0 or something else! 199695b41eeSopenharmony_ci const char* next_sep = src; 200695b41eeSopenharmony_ci while (next_sep != end && !IsPathSeparator(*next_sep)) 201695b41eeSopenharmony_ci ++next_sep; 202695b41eeSopenharmony_ci if (next_sep == end) { 203695b41eeSopenharmony_ci // This is the last component, will be handled out of the loop. 204695b41eeSopenharmony_ci break; 205695b41eeSopenharmony_ci } 206695b41eeSopenharmony_ci#endif 207695b41eeSopenharmony_ci // Position for next loop iteration. 208695b41eeSopenharmony_ci src_next = next_sep + 1; 209695b41eeSopenharmony_ci // Length of the component, excluding trailing directory. 210695b41eeSopenharmony_ci size_t component_len = next_sep - src; 211695b41eeSopenharmony_ci 212695b41eeSopenharmony_ci if (component_len <= 2) { 213695b41eeSopenharmony_ci if (component_len == 0) { 214695b41eeSopenharmony_ci continue; // Ignore empty component, e.g. 'foo//bar' -> 'foo/bar'. 215695b41eeSopenharmony_ci } 216695b41eeSopenharmony_ci if (src[0] == '.') { 217695b41eeSopenharmony_ci if (component_len == 1) { 218695b41eeSopenharmony_ci continue; // Ignore '.' component, e.g. './foo' -> 'foo'. 219695b41eeSopenharmony_ci } else if (src[1] == '.') { 220695b41eeSopenharmony_ci // Process the '..' component if found. Back up if possible. 221695b41eeSopenharmony_ci if (component_count > 0) { 222695b41eeSopenharmony_ci // Move back to start of previous component. 223695b41eeSopenharmony_ci --component_count; 224695b41eeSopenharmony_ci while (--dst > dst0 && !IsPathSeparator(dst[-1])) { 225695b41eeSopenharmony_ci // nothing to do here, decrement happens before condition check. 226695b41eeSopenharmony_ci } 227695b41eeSopenharmony_ci } else { 228695b41eeSopenharmony_ci dst[0] = '.'; 229695b41eeSopenharmony_ci dst[1] = '.'; 230695b41eeSopenharmony_ci dst[2] = src[2]; 231695b41eeSopenharmony_ci dst += 3; 232695b41eeSopenharmony_ci } 233695b41eeSopenharmony_ci continue; 234695b41eeSopenharmony_ci } 235695b41eeSopenharmony_ci } 236695b41eeSopenharmony_ci } 237695b41eeSopenharmony_ci ++component_count; 238695b41eeSopenharmony_ci 239695b41eeSopenharmony_ci // Copy or skip component, including trailing directory separator. 240695b41eeSopenharmony_ci if (dst != src) { 241695b41eeSopenharmony_ci ::memmove(dst, src, src_next - src); 242695b41eeSopenharmony_ci } 243695b41eeSopenharmony_ci dst += src_next - src; 244695b41eeSopenharmony_ci } 245695b41eeSopenharmony_ci 246695b41eeSopenharmony_ci // Handling the last component that does not have a trailing separator. 247695b41eeSopenharmony_ci // The logic here is _slightly_ different since there is no trailing 248695b41eeSopenharmony_ci // directory separator. 249695b41eeSopenharmony_ci size_t component_len = end - src; 250695b41eeSopenharmony_ci do { 251695b41eeSopenharmony_ci if (component_len == 0) 252695b41eeSopenharmony_ci break; // Ignore empty component (e.g. 'foo//' -> 'foo/') 253695b41eeSopenharmony_ci if (src[0] == '.') { 254695b41eeSopenharmony_ci if (component_len == 1) 255695b41eeSopenharmony_ci break; // Ignore trailing '.' (e.g. 'foo/.' -> 'foo/') 256695b41eeSopenharmony_ci if (component_len == 2 && src[1] == '.') { 257695b41eeSopenharmony_ci // Handle '..'. Back up if possible. 258695b41eeSopenharmony_ci if (component_count > 0) { 259695b41eeSopenharmony_ci while (--dst > dst0 && !IsPathSeparator(dst[-1])) { 260695b41eeSopenharmony_ci // nothing to do here, decrement happens before condition check. 261695b41eeSopenharmony_ci } 262695b41eeSopenharmony_ci } else { 263695b41eeSopenharmony_ci dst[0] = '.'; 264695b41eeSopenharmony_ci dst[1] = '.'; 265695b41eeSopenharmony_ci dst += 2; 266695b41eeSopenharmony_ci // No separator to add here. 267695b41eeSopenharmony_ci } 268695b41eeSopenharmony_ci break; 269695b41eeSopenharmony_ci } 270695b41eeSopenharmony_ci } 271695b41eeSopenharmony_ci // Skip or copy last component, no trailing separator. 272695b41eeSopenharmony_ci if (dst != src) { 273695b41eeSopenharmony_ci ::memmove(dst, src, component_len); 274695b41eeSopenharmony_ci } 275695b41eeSopenharmony_ci dst += component_len; 276695b41eeSopenharmony_ci } while (0); 277695b41eeSopenharmony_ci 278695b41eeSopenharmony_ci // Remove trailing path separator if any, but keep the initial 279695b41eeSopenharmony_ci // path separator(s) if there was one (or two on Windows). 280695b41eeSopenharmony_ci if (dst > dst_start && IsPathSeparator(dst[-1])) 281695b41eeSopenharmony_ci dst--; 282695b41eeSopenharmony_ci 283695b41eeSopenharmony_ci if (dst == start) { 284695b41eeSopenharmony_ci // Handle special cases like "aa/.." -> "." 285695b41eeSopenharmony_ci *dst++ = '.'; 286695b41eeSopenharmony_ci } 287695b41eeSopenharmony_ci 288695b41eeSopenharmony_ci *len = dst - start; // dst points after the trailing char here. 289695b41eeSopenharmony_ci#ifdef _WIN32 290695b41eeSopenharmony_ci uint64_t bits = 0; 291695b41eeSopenharmony_ci uint64_t bits_mask = 1; 292695b41eeSopenharmony_ci 293695b41eeSopenharmony_ci for (char* c = start; c < start + *len; ++c) { 294695b41eeSopenharmony_ci switch (*c) { 295695b41eeSopenharmony_ci case '\\': 296695b41eeSopenharmony_ci bits |= bits_mask; 297695b41eeSopenharmony_ci *c = '/'; 298695b41eeSopenharmony_ci NINJA_FALLTHROUGH; 299695b41eeSopenharmony_ci case '/': 300695b41eeSopenharmony_ci bits_mask <<= 1; 301695b41eeSopenharmony_ci } 302695b41eeSopenharmony_ci } 303695b41eeSopenharmony_ci 304695b41eeSopenharmony_ci *slash_bits = bits; 305695b41eeSopenharmony_ci#else 306695b41eeSopenharmony_ci *slash_bits = 0; 307695b41eeSopenharmony_ci#endif 308695b41eeSopenharmony_ci} 309695b41eeSopenharmony_ci 310695b41eeSopenharmony_cistatic inline bool IsKnownShellSafeCharacter(char ch) { 311695b41eeSopenharmony_ci if ('A' <= ch && ch <= 'Z') return true; 312695b41eeSopenharmony_ci if ('a' <= ch && ch <= 'z') return true; 313695b41eeSopenharmony_ci if ('0' <= ch && ch <= '9') return true; 314695b41eeSopenharmony_ci 315695b41eeSopenharmony_ci switch (ch) { 316695b41eeSopenharmony_ci case '_': 317695b41eeSopenharmony_ci case '+': 318695b41eeSopenharmony_ci case '-': 319695b41eeSopenharmony_ci case '.': 320695b41eeSopenharmony_ci case '/': 321695b41eeSopenharmony_ci return true; 322695b41eeSopenharmony_ci default: 323695b41eeSopenharmony_ci return false; 324695b41eeSopenharmony_ci } 325695b41eeSopenharmony_ci} 326695b41eeSopenharmony_ci 327695b41eeSopenharmony_cistatic inline bool IsKnownWin32SafeCharacter(char ch) { 328695b41eeSopenharmony_ci switch (ch) { 329695b41eeSopenharmony_ci case ' ': 330695b41eeSopenharmony_ci case '"': 331695b41eeSopenharmony_ci return false; 332695b41eeSopenharmony_ci default: 333695b41eeSopenharmony_ci return true; 334695b41eeSopenharmony_ci } 335695b41eeSopenharmony_ci} 336695b41eeSopenharmony_ci 337695b41eeSopenharmony_cistatic inline bool StringNeedsShellEscaping(const string& input) { 338695b41eeSopenharmony_ci for (size_t i = 0; i < input.size(); ++i) { 339695b41eeSopenharmony_ci if (!IsKnownShellSafeCharacter(input[i])) return true; 340695b41eeSopenharmony_ci } 341695b41eeSopenharmony_ci return false; 342695b41eeSopenharmony_ci} 343695b41eeSopenharmony_ci 344695b41eeSopenharmony_cistatic inline bool StringNeedsWin32Escaping(const string& input) { 345695b41eeSopenharmony_ci for (size_t i = 0; i < input.size(); ++i) { 346695b41eeSopenharmony_ci if (!IsKnownWin32SafeCharacter(input[i])) return true; 347695b41eeSopenharmony_ci } 348695b41eeSopenharmony_ci return false; 349695b41eeSopenharmony_ci} 350695b41eeSopenharmony_ci 351695b41eeSopenharmony_civoid GetShellEscapedString(const string& input, string* result) { 352695b41eeSopenharmony_ci assert(result); 353695b41eeSopenharmony_ci 354695b41eeSopenharmony_ci if (!StringNeedsShellEscaping(input)) { 355695b41eeSopenharmony_ci result->append(input); 356695b41eeSopenharmony_ci return; 357695b41eeSopenharmony_ci } 358695b41eeSopenharmony_ci 359695b41eeSopenharmony_ci const char kQuote = '\''; 360695b41eeSopenharmony_ci const char kEscapeSequence[] = "'\\'"; 361695b41eeSopenharmony_ci 362695b41eeSopenharmony_ci result->push_back(kQuote); 363695b41eeSopenharmony_ci 364695b41eeSopenharmony_ci string::const_iterator span_begin = input.begin(); 365695b41eeSopenharmony_ci for (string::const_iterator it = input.begin(), end = input.end(); it != end; 366695b41eeSopenharmony_ci ++it) { 367695b41eeSopenharmony_ci if (*it == kQuote) { 368695b41eeSopenharmony_ci result->append(span_begin, it); 369695b41eeSopenharmony_ci result->append(kEscapeSequence); 370695b41eeSopenharmony_ci span_begin = it; 371695b41eeSopenharmony_ci } 372695b41eeSopenharmony_ci } 373695b41eeSopenharmony_ci result->append(span_begin, input.end()); 374695b41eeSopenharmony_ci result->push_back(kQuote); 375695b41eeSopenharmony_ci} 376695b41eeSopenharmony_ci 377695b41eeSopenharmony_ci 378695b41eeSopenharmony_civoid GetWin32EscapedString(const string& input, string* result) { 379695b41eeSopenharmony_ci assert(result); 380695b41eeSopenharmony_ci if (!StringNeedsWin32Escaping(input)) { 381695b41eeSopenharmony_ci result->append(input); 382695b41eeSopenharmony_ci return; 383695b41eeSopenharmony_ci } 384695b41eeSopenharmony_ci 385695b41eeSopenharmony_ci const char kQuote = '"'; 386695b41eeSopenharmony_ci const char kBackslash = '\\'; 387695b41eeSopenharmony_ci 388695b41eeSopenharmony_ci result->push_back(kQuote); 389695b41eeSopenharmony_ci size_t consecutive_backslash_count = 0; 390695b41eeSopenharmony_ci string::const_iterator span_begin = input.begin(); 391695b41eeSopenharmony_ci for (string::const_iterator it = input.begin(), end = input.end(); it != end; 392695b41eeSopenharmony_ci ++it) { 393695b41eeSopenharmony_ci switch (*it) { 394695b41eeSopenharmony_ci case kBackslash: 395695b41eeSopenharmony_ci ++consecutive_backslash_count; 396695b41eeSopenharmony_ci break; 397695b41eeSopenharmony_ci case kQuote: 398695b41eeSopenharmony_ci result->append(span_begin, it); 399695b41eeSopenharmony_ci result->append(consecutive_backslash_count + 1, kBackslash); 400695b41eeSopenharmony_ci span_begin = it; 401695b41eeSopenharmony_ci consecutive_backslash_count = 0; 402695b41eeSopenharmony_ci break; 403695b41eeSopenharmony_ci default: 404695b41eeSopenharmony_ci consecutive_backslash_count = 0; 405695b41eeSopenharmony_ci break; 406695b41eeSopenharmony_ci } 407695b41eeSopenharmony_ci } 408695b41eeSopenharmony_ci result->append(span_begin, input.end()); 409695b41eeSopenharmony_ci result->append(consecutive_backslash_count, kBackslash); 410695b41eeSopenharmony_ci result->push_back(kQuote); 411695b41eeSopenharmony_ci} 412695b41eeSopenharmony_ci 413695b41eeSopenharmony_ciint ReadFile(const string& path, string* contents, string* err) { 414695b41eeSopenharmony_ci#ifdef _WIN32 415695b41eeSopenharmony_ci // This makes a ninja run on a set of 1500 manifest files about 4% faster 416695b41eeSopenharmony_ci // than using the generic fopen code below. 417695b41eeSopenharmony_ci err->clear(); 418695b41eeSopenharmony_ci HANDLE f = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, 419695b41eeSopenharmony_ci OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 420695b41eeSopenharmony_ci if (f == INVALID_HANDLE_VALUE) { 421695b41eeSopenharmony_ci err->assign(GetLastErrorString()); 422695b41eeSopenharmony_ci return -ENOENT; 423695b41eeSopenharmony_ci } 424695b41eeSopenharmony_ci 425695b41eeSopenharmony_ci for (;;) { 426695b41eeSopenharmony_ci DWORD len; 427695b41eeSopenharmony_ci char buf[64 << 10]; 428695b41eeSopenharmony_ci if (!::ReadFile(f, buf, sizeof(buf), &len, NULL)) { 429695b41eeSopenharmony_ci err->assign(GetLastErrorString()); 430695b41eeSopenharmony_ci contents->clear(); 431695b41eeSopenharmony_ci ::CloseHandle(f); 432695b41eeSopenharmony_ci return -EIO; 433695b41eeSopenharmony_ci } 434695b41eeSopenharmony_ci if (len == 0) 435695b41eeSopenharmony_ci break; 436695b41eeSopenharmony_ci contents->append(buf, len); 437695b41eeSopenharmony_ci } 438695b41eeSopenharmony_ci ::CloseHandle(f); 439695b41eeSopenharmony_ci return 0; 440695b41eeSopenharmony_ci#else 441695b41eeSopenharmony_ci FILE* f = fopen(path.c_str(), "rb"); 442695b41eeSopenharmony_ci if (!f) { 443695b41eeSopenharmony_ci err->assign(strerror(errno)); 444695b41eeSopenharmony_ci return -errno; 445695b41eeSopenharmony_ci } 446695b41eeSopenharmony_ci 447695b41eeSopenharmony_ci#ifdef __USE_LARGEFILE64 448695b41eeSopenharmony_ci struct stat64 st; 449695b41eeSopenharmony_ci if (fstat64(fileno(f), &st) < 0) { 450695b41eeSopenharmony_ci#else 451695b41eeSopenharmony_ci struct stat st; 452695b41eeSopenharmony_ci if (fstat(fileno(f), &st) < 0) { 453695b41eeSopenharmony_ci#endif 454695b41eeSopenharmony_ci err->assign(strerror(errno)); 455695b41eeSopenharmony_ci fclose(f); 456695b41eeSopenharmony_ci return -errno; 457695b41eeSopenharmony_ci } 458695b41eeSopenharmony_ci 459695b41eeSopenharmony_ci // +1 is for the resize in ManifestParser::Load 460695b41eeSopenharmony_ci contents->reserve(st.st_size + 1); 461695b41eeSopenharmony_ci 462695b41eeSopenharmony_ci char buf[64 << 10]; 463695b41eeSopenharmony_ci size_t len; 464695b41eeSopenharmony_ci while (!feof(f) && (len = fread(buf, 1, sizeof(buf), f)) > 0) { 465695b41eeSopenharmony_ci contents->append(buf, len); 466695b41eeSopenharmony_ci } 467695b41eeSopenharmony_ci if (ferror(f)) { 468695b41eeSopenharmony_ci err->assign(strerror(errno)); // XXX errno? 469695b41eeSopenharmony_ci contents->clear(); 470695b41eeSopenharmony_ci fclose(f); 471695b41eeSopenharmony_ci return -errno; 472695b41eeSopenharmony_ci } 473695b41eeSopenharmony_ci fclose(f); 474695b41eeSopenharmony_ci return 0; 475695b41eeSopenharmony_ci#endif 476695b41eeSopenharmony_ci} 477695b41eeSopenharmony_ci 478695b41eeSopenharmony_civoid SetCloseOnExec(int fd) { 479695b41eeSopenharmony_ci#ifndef _WIN32 480695b41eeSopenharmony_ci int flags = fcntl(fd, F_GETFD); 481695b41eeSopenharmony_ci if (flags < 0) { 482695b41eeSopenharmony_ci perror("fcntl(F_GETFD)"); 483695b41eeSopenharmony_ci } else { 484695b41eeSopenharmony_ci if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) 485695b41eeSopenharmony_ci perror("fcntl(F_SETFD)"); 486695b41eeSopenharmony_ci } 487695b41eeSopenharmony_ci#else 488695b41eeSopenharmony_ci HANDLE hd = (HANDLE) _get_osfhandle(fd); 489695b41eeSopenharmony_ci if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) { 490695b41eeSopenharmony_ci fprintf(stderr, "SetHandleInformation(): %s", GetLastErrorString().c_str()); 491695b41eeSopenharmony_ci } 492695b41eeSopenharmony_ci#endif // ! _WIN32 493695b41eeSopenharmony_ci} 494695b41eeSopenharmony_ci 495695b41eeSopenharmony_ci 496695b41eeSopenharmony_ciconst char* SpellcheckStringV(const string& text, 497695b41eeSopenharmony_ci const vector<const char*>& words) { 498695b41eeSopenharmony_ci const bool kAllowReplacements = true; 499695b41eeSopenharmony_ci const int kMaxValidEditDistance = 3; 500695b41eeSopenharmony_ci 501695b41eeSopenharmony_ci int min_distance = kMaxValidEditDistance + 1; 502695b41eeSopenharmony_ci const char* result = NULL; 503695b41eeSopenharmony_ci for (vector<const char*>::const_iterator i = words.begin(); 504695b41eeSopenharmony_ci i != words.end(); ++i) { 505695b41eeSopenharmony_ci int distance = EditDistance(*i, text, kAllowReplacements, 506695b41eeSopenharmony_ci kMaxValidEditDistance); 507695b41eeSopenharmony_ci if (distance < min_distance) { 508695b41eeSopenharmony_ci min_distance = distance; 509695b41eeSopenharmony_ci result = *i; 510695b41eeSopenharmony_ci } 511695b41eeSopenharmony_ci } 512695b41eeSopenharmony_ci return result; 513695b41eeSopenharmony_ci} 514695b41eeSopenharmony_ci 515695b41eeSopenharmony_ciconst char* SpellcheckString(const char* text, ...) { 516695b41eeSopenharmony_ci // Note: This takes a const char* instead of a string& because using 517695b41eeSopenharmony_ci // va_start() with a reference parameter is undefined behavior. 518695b41eeSopenharmony_ci va_list ap; 519695b41eeSopenharmony_ci va_start(ap, text); 520695b41eeSopenharmony_ci vector<const char*> words; 521695b41eeSopenharmony_ci const char* word; 522695b41eeSopenharmony_ci while ((word = va_arg(ap, const char*))) 523695b41eeSopenharmony_ci words.push_back(word); 524695b41eeSopenharmony_ci va_end(ap); 525695b41eeSopenharmony_ci return SpellcheckStringV(text, words); 526695b41eeSopenharmony_ci} 527695b41eeSopenharmony_ci 528695b41eeSopenharmony_ci#ifdef _WIN32 529695b41eeSopenharmony_cistring GetLastErrorString() { 530695b41eeSopenharmony_ci DWORD err = GetLastError(); 531695b41eeSopenharmony_ci 532695b41eeSopenharmony_ci char* msg_buf; 533695b41eeSopenharmony_ci FormatMessageA( 534695b41eeSopenharmony_ci FORMAT_MESSAGE_ALLOCATE_BUFFER | 535695b41eeSopenharmony_ci FORMAT_MESSAGE_FROM_SYSTEM | 536695b41eeSopenharmony_ci FORMAT_MESSAGE_IGNORE_INSERTS, 537695b41eeSopenharmony_ci NULL, 538695b41eeSopenharmony_ci err, 539695b41eeSopenharmony_ci MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), 540695b41eeSopenharmony_ci (char*)&msg_buf, 541695b41eeSopenharmony_ci 0, 542695b41eeSopenharmony_ci NULL); 543695b41eeSopenharmony_ci 544695b41eeSopenharmony_ci if (msg_buf == nullptr) { 545695b41eeSopenharmony_ci char fallback_msg[128] = {0}; 546695b41eeSopenharmony_ci snprintf(fallback_msg, sizeof(fallback_msg), "GetLastError() = %d", err); 547695b41eeSopenharmony_ci return fallback_msg; 548695b41eeSopenharmony_ci } 549695b41eeSopenharmony_ci 550695b41eeSopenharmony_ci string msg = msg_buf; 551695b41eeSopenharmony_ci LocalFree(msg_buf); 552695b41eeSopenharmony_ci return msg; 553695b41eeSopenharmony_ci} 554695b41eeSopenharmony_ci 555695b41eeSopenharmony_civoid Win32Fatal(const char* function, const char* hint) { 556695b41eeSopenharmony_ci if (hint) { 557695b41eeSopenharmony_ci Fatal("%s: %s (%s)", function, GetLastErrorString().c_str(), hint); 558695b41eeSopenharmony_ci } else { 559695b41eeSopenharmony_ci Fatal("%s: %s", function, GetLastErrorString().c_str()); 560695b41eeSopenharmony_ci } 561695b41eeSopenharmony_ci} 562695b41eeSopenharmony_ci#endif 563695b41eeSopenharmony_ci 564695b41eeSopenharmony_cibool islatinalpha(int c) { 565695b41eeSopenharmony_ci // isalpha() is locale-dependent. 566695b41eeSopenharmony_ci return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); 567695b41eeSopenharmony_ci} 568695b41eeSopenharmony_ci 569695b41eeSopenharmony_cistring StripAnsiEscapeCodes(const string& in) { 570695b41eeSopenharmony_ci string stripped; 571695b41eeSopenharmony_ci stripped.reserve(in.size()); 572695b41eeSopenharmony_ci 573695b41eeSopenharmony_ci for (size_t i = 0; i < in.size(); ++i) { 574695b41eeSopenharmony_ci if (in[i] != '\33') { 575695b41eeSopenharmony_ci // Not an escape code. 576695b41eeSopenharmony_ci stripped.push_back(in[i]); 577695b41eeSopenharmony_ci continue; 578695b41eeSopenharmony_ci } 579695b41eeSopenharmony_ci 580695b41eeSopenharmony_ci // Only strip CSIs for now. 581695b41eeSopenharmony_ci if (i + 1 >= in.size()) break; 582695b41eeSopenharmony_ci if (in[i + 1] != '[') continue; // Not a CSI. 583695b41eeSopenharmony_ci i += 2; 584695b41eeSopenharmony_ci 585695b41eeSopenharmony_ci // Skip everything up to and including the next [a-zA-Z]. 586695b41eeSopenharmony_ci while (i < in.size() && !islatinalpha(in[i])) 587695b41eeSopenharmony_ci ++i; 588695b41eeSopenharmony_ci } 589695b41eeSopenharmony_ci return stripped; 590695b41eeSopenharmony_ci} 591695b41eeSopenharmony_ci 592695b41eeSopenharmony_ci#if defined(linux) || defined(__GLIBC__) 593695b41eeSopenharmony_cistd::pair<int64_t, bool> readCount(const std::string& path) { 594695b41eeSopenharmony_ci std::ifstream file(path.c_str()); 595695b41eeSopenharmony_ci if (!file.is_open()) 596695b41eeSopenharmony_ci return std::make_pair(0, false); 597695b41eeSopenharmony_ci int64_t n = 0; 598695b41eeSopenharmony_ci file >> n; 599695b41eeSopenharmony_ci if (file.good()) 600695b41eeSopenharmony_ci return std::make_pair(n, true); 601695b41eeSopenharmony_ci return std::make_pair(0, false); 602695b41eeSopenharmony_ci} 603695b41eeSopenharmony_ci 604695b41eeSopenharmony_cistruct MountPoint { 605695b41eeSopenharmony_ci int mountId; 606695b41eeSopenharmony_ci int parentId; 607695b41eeSopenharmony_ci StringPiece deviceId; 608695b41eeSopenharmony_ci StringPiece root; 609695b41eeSopenharmony_ci StringPiece mountPoint; 610695b41eeSopenharmony_ci vector<StringPiece> options; 611695b41eeSopenharmony_ci vector<StringPiece> optionalFields; 612695b41eeSopenharmony_ci StringPiece fsType; 613695b41eeSopenharmony_ci StringPiece mountSource; 614695b41eeSopenharmony_ci vector<StringPiece> superOptions; 615695b41eeSopenharmony_ci bool parse(const string& line) { 616695b41eeSopenharmony_ci vector<StringPiece> pieces = SplitStringPiece(line, ' '); 617695b41eeSopenharmony_ci if (pieces.size() < 10) 618695b41eeSopenharmony_ci return false; 619695b41eeSopenharmony_ci size_t optionalStart = 0; 620695b41eeSopenharmony_ci for (size_t i = 6; i < pieces.size(); i++) { 621695b41eeSopenharmony_ci if (pieces[i] == "-") { 622695b41eeSopenharmony_ci optionalStart = i + 1; 623695b41eeSopenharmony_ci break; 624695b41eeSopenharmony_ci } 625695b41eeSopenharmony_ci } 626695b41eeSopenharmony_ci if (optionalStart == 0) 627695b41eeSopenharmony_ci return false; 628695b41eeSopenharmony_ci if (optionalStart + 3 != pieces.size()) 629695b41eeSopenharmony_ci return false; 630695b41eeSopenharmony_ci mountId = atoi(pieces[0].AsString().c_str()); 631695b41eeSopenharmony_ci parentId = atoi(pieces[1].AsString().c_str()); 632695b41eeSopenharmony_ci deviceId = pieces[2]; 633695b41eeSopenharmony_ci root = pieces[3]; 634695b41eeSopenharmony_ci mountPoint = pieces[4]; 635695b41eeSopenharmony_ci options = SplitStringPiece(pieces[5], ','); 636695b41eeSopenharmony_ci optionalFields = 637695b41eeSopenharmony_ci vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]); 638695b41eeSopenharmony_ci fsType = pieces[optionalStart]; 639695b41eeSopenharmony_ci mountSource = pieces[optionalStart + 1]; 640695b41eeSopenharmony_ci superOptions = SplitStringPiece(pieces[optionalStart + 2], ','); 641695b41eeSopenharmony_ci return true; 642695b41eeSopenharmony_ci } 643695b41eeSopenharmony_ci string translate(string& path) const { 644695b41eeSopenharmony_ci // path must be sub dir of root 645695b41eeSopenharmony_ci if (path.compare(0, root.len_, root.str_, root.len_) != 0) { 646695b41eeSopenharmony_ci return string(); 647695b41eeSopenharmony_ci } 648695b41eeSopenharmony_ci path.erase(0, root.len_); 649695b41eeSopenharmony_ci if (path == ".." || (path.length() > 2 && path.compare(0, 3, "../") == 0)) { 650695b41eeSopenharmony_ci return string(); 651695b41eeSopenharmony_ci } 652695b41eeSopenharmony_ci return mountPoint.AsString() + "/" + path; 653695b41eeSopenharmony_ci } 654695b41eeSopenharmony_ci}; 655695b41eeSopenharmony_ci 656695b41eeSopenharmony_cistruct CGroupSubSys { 657695b41eeSopenharmony_ci int id; 658695b41eeSopenharmony_ci string name; 659695b41eeSopenharmony_ci vector<string> subsystems; 660695b41eeSopenharmony_ci bool parse(string& line) { 661695b41eeSopenharmony_ci size_t first = line.find(':'); 662695b41eeSopenharmony_ci if (first == string::npos) 663695b41eeSopenharmony_ci return false; 664695b41eeSopenharmony_ci line[first] = '\0'; 665695b41eeSopenharmony_ci size_t second = line.find(':', first + 1); 666695b41eeSopenharmony_ci if (second == string::npos) 667695b41eeSopenharmony_ci return false; 668695b41eeSopenharmony_ci line[second] = '\0'; 669695b41eeSopenharmony_ci id = atoi(line.c_str()); 670695b41eeSopenharmony_ci name = line.substr(second + 1); 671695b41eeSopenharmony_ci vector<StringPiece> pieces = 672695b41eeSopenharmony_ci SplitStringPiece(StringPiece(line.c_str() + first + 1), ','); 673695b41eeSopenharmony_ci for (size_t i = 0; i < pieces.size(); i++) { 674695b41eeSopenharmony_ci subsystems.push_back(pieces[i].AsString()); 675695b41eeSopenharmony_ci } 676695b41eeSopenharmony_ci return true; 677695b41eeSopenharmony_ci } 678695b41eeSopenharmony_ci}; 679695b41eeSopenharmony_ci 680695b41eeSopenharmony_cimap<string, string> ParseMountInfo(map<string, CGroupSubSys>& subsystems) { 681695b41eeSopenharmony_ci map<string, string> cgroups; 682695b41eeSopenharmony_ci ifstream mountinfo("/proc/self/mountinfo"); 683695b41eeSopenharmony_ci if (!mountinfo.is_open()) 684695b41eeSopenharmony_ci return cgroups; 685695b41eeSopenharmony_ci while (!mountinfo.eof()) { 686695b41eeSopenharmony_ci string line; 687695b41eeSopenharmony_ci getline(mountinfo, line); 688695b41eeSopenharmony_ci MountPoint mp; 689695b41eeSopenharmony_ci if (!mp.parse(line)) 690695b41eeSopenharmony_ci continue; 691695b41eeSopenharmony_ci if (mp.fsType != "cgroup") 692695b41eeSopenharmony_ci continue; 693695b41eeSopenharmony_ci for (size_t i = 0; i < mp.superOptions.size(); i++) { 694695b41eeSopenharmony_ci string opt = mp.superOptions[i].AsString(); 695695b41eeSopenharmony_ci map<string, CGroupSubSys>::iterator subsys = subsystems.find(opt); 696695b41eeSopenharmony_ci if (subsys == subsystems.end()) 697695b41eeSopenharmony_ci continue; 698695b41eeSopenharmony_ci string newPath = mp.translate(subsys->second.name); 699695b41eeSopenharmony_ci if (!newPath.empty()) 700695b41eeSopenharmony_ci cgroups.insert(make_pair(opt, newPath)); 701695b41eeSopenharmony_ci } 702695b41eeSopenharmony_ci } 703695b41eeSopenharmony_ci return cgroups; 704695b41eeSopenharmony_ci} 705695b41eeSopenharmony_ci 706695b41eeSopenharmony_cimap<string, CGroupSubSys> ParseSelfCGroup() { 707695b41eeSopenharmony_ci map<string, CGroupSubSys> cgroups; 708695b41eeSopenharmony_ci ifstream cgroup("/proc/self/cgroup"); 709695b41eeSopenharmony_ci if (!cgroup.is_open()) 710695b41eeSopenharmony_ci return cgroups; 711695b41eeSopenharmony_ci string line; 712695b41eeSopenharmony_ci while (!cgroup.eof()) { 713695b41eeSopenharmony_ci getline(cgroup, line); 714695b41eeSopenharmony_ci CGroupSubSys subsys; 715695b41eeSopenharmony_ci if (!subsys.parse(line)) 716695b41eeSopenharmony_ci continue; 717695b41eeSopenharmony_ci for (size_t i = 0; i < subsys.subsystems.size(); i++) { 718695b41eeSopenharmony_ci cgroups.insert(make_pair(subsys.subsystems[i], subsys)); 719695b41eeSopenharmony_ci } 720695b41eeSopenharmony_ci } 721695b41eeSopenharmony_ci return cgroups; 722695b41eeSopenharmony_ci} 723695b41eeSopenharmony_ci 724695b41eeSopenharmony_ciint ParseCPUFromCGroup() { 725695b41eeSopenharmony_ci map<string, CGroupSubSys> subsystems = ParseSelfCGroup(); 726695b41eeSopenharmony_ci map<string, string> cgroups = ParseMountInfo(subsystems); 727695b41eeSopenharmony_ci map<string, string>::iterator cpu = cgroups.find("cpu"); 728695b41eeSopenharmony_ci if (cpu == cgroups.end()) 729695b41eeSopenharmony_ci return -1; 730695b41eeSopenharmony_ci std::pair<int64_t, bool> quota = readCount(cpu->second + "/cpu.cfs_quota_us"); 731695b41eeSopenharmony_ci if (!quota.second || quota.first == -1) 732695b41eeSopenharmony_ci return -1; 733695b41eeSopenharmony_ci std::pair<int64_t, bool> period = 734695b41eeSopenharmony_ci readCount(cpu->second + "/cpu.cfs_period_us"); 735695b41eeSopenharmony_ci if (!period.second) 736695b41eeSopenharmony_ci return -1; 737695b41eeSopenharmony_ci if (period.first == 0) 738695b41eeSopenharmony_ci return -1; 739695b41eeSopenharmony_ci return quota.first / period.first; 740695b41eeSopenharmony_ci} 741695b41eeSopenharmony_ci#endif 742695b41eeSopenharmony_ci 743695b41eeSopenharmony_ciint GetProcessorCount() { 744695b41eeSopenharmony_ci#ifdef _WIN32 745695b41eeSopenharmony_ci DWORD cpuCount = 0; 746695b41eeSopenharmony_ci#ifndef _WIN64 747695b41eeSopenharmony_ci // Need to use GetLogicalProcessorInformationEx to get real core count on 748695b41eeSopenharmony_ci // machines with >64 cores. See https://stackoverflow.com/a/31209344/21475 749695b41eeSopenharmony_ci DWORD len = 0; 750695b41eeSopenharmony_ci if (!GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &len) 751695b41eeSopenharmony_ci && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 752695b41eeSopenharmony_ci std::vector<char> buf(len); 753695b41eeSopenharmony_ci int cores = 0; 754695b41eeSopenharmony_ci if (GetLogicalProcessorInformationEx(RelationProcessorCore, 755695b41eeSopenharmony_ci reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>( 756695b41eeSopenharmony_ci buf.data()), &len)) { 757695b41eeSopenharmony_ci for (DWORD i = 0; i < len; ) { 758695b41eeSopenharmony_ci auto info = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>( 759695b41eeSopenharmony_ci buf.data() + i); 760695b41eeSopenharmony_ci if (info->Relationship == RelationProcessorCore && 761695b41eeSopenharmony_ci info->Processor.GroupCount == 1) { 762695b41eeSopenharmony_ci for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask; 763695b41eeSopenharmony_ci core_mask; core_mask >>= 1) { 764695b41eeSopenharmony_ci cores += (core_mask & 1); 765695b41eeSopenharmony_ci } 766695b41eeSopenharmony_ci } 767695b41eeSopenharmony_ci i += info->Size; 768695b41eeSopenharmony_ci } 769695b41eeSopenharmony_ci if (cores != 0) { 770695b41eeSopenharmony_ci cpuCount = cores; 771695b41eeSopenharmony_ci } 772695b41eeSopenharmony_ci } 773695b41eeSopenharmony_ci } 774695b41eeSopenharmony_ci#endif 775695b41eeSopenharmony_ci if (cpuCount == 0) { 776695b41eeSopenharmony_ci cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); 777695b41eeSopenharmony_ci } 778695b41eeSopenharmony_ci JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info; 779695b41eeSopenharmony_ci // reference: 780695b41eeSopenharmony_ci // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_cpu_rate_control_information 781695b41eeSopenharmony_ci if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info, 782695b41eeSopenharmony_ci sizeof(info), NULL)) { 783695b41eeSopenharmony_ci if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | 784695b41eeSopenharmony_ci JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) { 785695b41eeSopenharmony_ci return cpuCount * info.CpuRate / 10000; 786695b41eeSopenharmony_ci } 787695b41eeSopenharmony_ci } 788695b41eeSopenharmony_ci return cpuCount; 789695b41eeSopenharmony_ci#else 790695b41eeSopenharmony_ci int cgroupCount = -1; 791695b41eeSopenharmony_ci int schedCount = -1; 792695b41eeSopenharmony_ci#if defined(linux) || defined(__GLIBC__) 793695b41eeSopenharmony_ci cgroupCount = ParseCPUFromCGroup(); 794695b41eeSopenharmony_ci#endif 795695b41eeSopenharmony_ci // The number of exposed processors might not represent the actual number of 796695b41eeSopenharmony_ci // processors threads can run on. This happens when a CPU set limitation is 797695b41eeSopenharmony_ci // active, see https://github.com/ninja-build/ninja/issues/1278 798695b41eeSopenharmony_ci#if defined(__FreeBSD__) 799695b41eeSopenharmony_ci cpuset_t mask; 800695b41eeSopenharmony_ci CPU_ZERO(&mask); 801695b41eeSopenharmony_ci if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), 802695b41eeSopenharmony_ci &mask) == 0) { 803695b41eeSopenharmony_ci return CPU_COUNT(&mask); 804695b41eeSopenharmony_ci } 805695b41eeSopenharmony_ci#elif defined(CPU_COUNT) 806695b41eeSopenharmony_ci cpu_set_t set; 807695b41eeSopenharmony_ci if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) { 808695b41eeSopenharmony_ci schedCount = CPU_COUNT(&set); 809695b41eeSopenharmony_ci } 810695b41eeSopenharmony_ci#endif 811695b41eeSopenharmony_ci if (cgroupCount >= 0 && schedCount >= 0) return std::min(cgroupCount, schedCount); 812695b41eeSopenharmony_ci if (cgroupCount < 0 && schedCount < 0) return sysconf(_SC_NPROCESSORS_ONLN); 813695b41eeSopenharmony_ci return std::max(cgroupCount, schedCount); 814695b41eeSopenharmony_ci#endif 815695b41eeSopenharmony_ci} 816695b41eeSopenharmony_ci 817695b41eeSopenharmony_ci#if defined(_WIN32) || defined(__CYGWIN__) 818695b41eeSopenharmony_cistatic double CalculateProcessorLoad(uint64_t idle_ticks, uint64_t total_ticks) 819695b41eeSopenharmony_ci{ 820695b41eeSopenharmony_ci static uint64_t previous_idle_ticks = 0; 821695b41eeSopenharmony_ci static uint64_t previous_total_ticks = 0; 822695b41eeSopenharmony_ci static double previous_load = -0.0; 823695b41eeSopenharmony_ci 824695b41eeSopenharmony_ci uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks; 825695b41eeSopenharmony_ci uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks; 826695b41eeSopenharmony_ci 827695b41eeSopenharmony_ci bool first_call = (previous_total_ticks == 0); 828695b41eeSopenharmony_ci bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0); 829695b41eeSopenharmony_ci 830695b41eeSopenharmony_ci double load; 831695b41eeSopenharmony_ci if (first_call || ticks_not_updated_since_last_call) { 832695b41eeSopenharmony_ci load = previous_load; 833695b41eeSopenharmony_ci } else { 834695b41eeSopenharmony_ci // Calculate load. 835695b41eeSopenharmony_ci double idle_to_total_ratio = 836695b41eeSopenharmony_ci ((double)idle_ticks_since_last_time) / total_ticks_since_last_time; 837695b41eeSopenharmony_ci double load_since_last_call = 1.0 - idle_to_total_ratio; 838695b41eeSopenharmony_ci 839695b41eeSopenharmony_ci // Filter/smooth result when possible. 840695b41eeSopenharmony_ci if(previous_load > 0) { 841695b41eeSopenharmony_ci load = 0.9 * previous_load + 0.1 * load_since_last_call; 842695b41eeSopenharmony_ci } else { 843695b41eeSopenharmony_ci load = load_since_last_call; 844695b41eeSopenharmony_ci } 845695b41eeSopenharmony_ci } 846695b41eeSopenharmony_ci 847695b41eeSopenharmony_ci previous_load = load; 848695b41eeSopenharmony_ci previous_total_ticks = total_ticks; 849695b41eeSopenharmony_ci previous_idle_ticks = idle_ticks; 850695b41eeSopenharmony_ci 851695b41eeSopenharmony_ci return load; 852695b41eeSopenharmony_ci} 853695b41eeSopenharmony_ci 854695b41eeSopenharmony_cistatic uint64_t FileTimeToTickCount(const FILETIME & ft) 855695b41eeSopenharmony_ci{ 856695b41eeSopenharmony_ci uint64_t high = (((uint64_t)(ft.dwHighDateTime)) << 32); 857695b41eeSopenharmony_ci uint64_t low = ft.dwLowDateTime; 858695b41eeSopenharmony_ci return (high | low); 859695b41eeSopenharmony_ci} 860695b41eeSopenharmony_ci 861695b41eeSopenharmony_cidouble GetLoadAverage() { 862695b41eeSopenharmony_ci FILETIME idle_time, kernel_time, user_time; 863695b41eeSopenharmony_ci BOOL get_system_time_succeeded = 864695b41eeSopenharmony_ci GetSystemTimes(&idle_time, &kernel_time, &user_time); 865695b41eeSopenharmony_ci 866695b41eeSopenharmony_ci double posix_compatible_load; 867695b41eeSopenharmony_ci if (get_system_time_succeeded) { 868695b41eeSopenharmony_ci uint64_t idle_ticks = FileTimeToTickCount(idle_time); 869695b41eeSopenharmony_ci 870695b41eeSopenharmony_ci // kernel_time from GetSystemTimes already includes idle_time. 871695b41eeSopenharmony_ci uint64_t total_ticks = 872695b41eeSopenharmony_ci FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time); 873695b41eeSopenharmony_ci 874695b41eeSopenharmony_ci double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks); 875695b41eeSopenharmony_ci posix_compatible_load = processor_load * GetProcessorCount(); 876695b41eeSopenharmony_ci 877695b41eeSopenharmony_ci } else { 878695b41eeSopenharmony_ci posix_compatible_load = -0.0; 879695b41eeSopenharmony_ci } 880695b41eeSopenharmony_ci 881695b41eeSopenharmony_ci return posix_compatible_load; 882695b41eeSopenharmony_ci} 883695b41eeSopenharmony_ci#elif defined(__PASE__) 884695b41eeSopenharmony_cidouble GetLoadAverage() { 885695b41eeSopenharmony_ci return -0.0f; 886695b41eeSopenharmony_ci} 887695b41eeSopenharmony_ci#elif defined(_AIX) 888695b41eeSopenharmony_cidouble GetLoadAverage() { 889695b41eeSopenharmony_ci perfstat_cpu_total_t cpu_stats; 890695b41eeSopenharmony_ci if (perfstat_cpu_total(NULL, &cpu_stats, sizeof(cpu_stats), 1) < 0) { 891695b41eeSopenharmony_ci return -0.0f; 892695b41eeSopenharmony_ci } 893695b41eeSopenharmony_ci 894695b41eeSopenharmony_ci // Calculation taken from comment in libperfstats.h 895695b41eeSopenharmony_ci return double(cpu_stats.loadavg[0]) / double(1 << SBITS); 896695b41eeSopenharmony_ci} 897695b41eeSopenharmony_ci#elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29) 898695b41eeSopenharmony_cidouble GetLoadAverage() { 899695b41eeSopenharmony_ci struct sysinfo si; 900695b41eeSopenharmony_ci if (sysinfo(&si) != 0) 901695b41eeSopenharmony_ci return -0.0f; 902695b41eeSopenharmony_ci return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0]; 903695b41eeSopenharmony_ci} 904695b41eeSopenharmony_ci#elif defined(__HAIKU__) 905695b41eeSopenharmony_cidouble GetLoadAverage() { 906695b41eeSopenharmony_ci return -0.0f; 907695b41eeSopenharmony_ci} 908695b41eeSopenharmony_ci#else 909695b41eeSopenharmony_cidouble GetLoadAverage() { 910695b41eeSopenharmony_ci double loadavg[3] = { 0.0f, 0.0f, 0.0f }; 911695b41eeSopenharmony_ci if (getloadavg(loadavg, 3) < 0) { 912695b41eeSopenharmony_ci // Maybe we should return an error here or the availability of 913695b41eeSopenharmony_ci // getloadavg(3) should be checked when ninja is configured. 914695b41eeSopenharmony_ci return -0.0f; 915695b41eeSopenharmony_ci } 916695b41eeSopenharmony_ci return loadavg[0]; 917695b41eeSopenharmony_ci} 918695b41eeSopenharmony_ci#endif // _WIN32 919695b41eeSopenharmony_ci 920695b41eeSopenharmony_cistring ElideMiddle(const string& str, size_t width) { 921695b41eeSopenharmony_ci switch (width) { 922695b41eeSopenharmony_ci case 0: return ""; 923695b41eeSopenharmony_ci case 1: return "."; 924695b41eeSopenharmony_ci case 2: return ".."; 925695b41eeSopenharmony_ci case 3: return "..."; 926695b41eeSopenharmony_ci } 927695b41eeSopenharmony_ci const int kMargin = 3; // Space for "...". 928695b41eeSopenharmony_ci string result = str; 929695b41eeSopenharmony_ci if (result.size() > width) { 930695b41eeSopenharmony_ci size_t elide_size = (width - kMargin) / 2; 931695b41eeSopenharmony_ci result = result.substr(0, elide_size) 932695b41eeSopenharmony_ci + "..." 933695b41eeSopenharmony_ci + result.substr(result.size() - elide_size, elide_size); 934695b41eeSopenharmony_ci } 935695b41eeSopenharmony_ci return result; 936695b41eeSopenharmony_ci} 937695b41eeSopenharmony_ci 938695b41eeSopenharmony_cibool Truncate(const string& path, size_t size, string* err) { 939695b41eeSopenharmony_ci#ifdef _WIN32 940695b41eeSopenharmony_ci int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO, 941695b41eeSopenharmony_ci _S_IREAD | _S_IWRITE); 942695b41eeSopenharmony_ci int success = _chsize(fh, size); 943695b41eeSopenharmony_ci _close(fh); 944695b41eeSopenharmony_ci#else 945695b41eeSopenharmony_ci int success = truncate(path.c_str(), size); 946695b41eeSopenharmony_ci#endif 947695b41eeSopenharmony_ci // Both truncate() and _chsize() return 0 on success and set errno and return 948695b41eeSopenharmony_ci // -1 on failure. 949695b41eeSopenharmony_ci if (success < 0) { 950695b41eeSopenharmony_ci *err = strerror(errno); 951695b41eeSopenharmony_ci return false; 952695b41eeSopenharmony_ci } 953695b41eeSopenharmony_ci return true; 954695b41eeSopenharmony_ci} 955