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