// Copyright 2017-2018 ccls Authors // SPDX-License-Identifier: Apache-2.0 #if defined(__unix__) || defined(__APPLE__) #include "platform.h" #include "utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // required for stat.h #include #include #ifdef __GLIBC__ #include #endif #include #include #include std::string NormalizePath(const std::string &path) { llvm::SmallString<256> P(path); llvm::sys::path::remove_dots(P, true); return {P.data(), P.size()}; } void FreeUnusedMemory() { #ifdef __GLIBC__ malloc_trim(4 * 1024 * 1024); #endif } void TraceMe() { // If the environment variable is defined, wait for a debugger. // In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue // after detaching. const char *traceme = getenv("CCLS_TRACEME"); if (traceme) raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP); } std::string GetExternalCommandOutput(const std::vector &command, std::string_view input) { int pin[2], pout[2]; if (pipe(pin) < 0) { perror("pipe(stdin)"); return ""; } if (pipe(pout) < 0) { perror("pipe(stdout)"); close(pin[0]); close(pin[1]); return ""; } pid_t child = fork(); if (child == 0) { dup2(pout[0], 0); dup2(pin[1], 1); close(pin[0]); close(pin[1]); close(pout[0]); close(pout[1]); auto argv = new char *[command.size() + 1]; for (size_t i = 0; i < command.size(); i++) argv[i] = const_cast(command[i].c_str()); argv[command.size()] = nullptr; execvp(argv[0], argv); _Exit(127); } close(pin[1]); close(pout[0]); // O_NONBLOCK is disabled, write(2) blocks until all bytes are written. (void)write(pout[1], input.data(), input.size()); close(pout[1]); std::string ret; char buf[4096]; ssize_t n; while ((n = read(pin[0], buf, sizeof buf)) > 0) ret.append(buf, n); close(pin[0]); waitpid(child, NULL, 0); return ret; } void SpawnThread(void *(*fn)(void *), void *arg) { pthread_t thd; pthread_attr_t attr; struct rlimit rlim; size_t stack_size = 4 * 1024 * 1024; if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur != RLIM_INFINITY) stack_size = rlim.rlim_cur; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&attr, stack_size); pthread_create(&thd, &attr, fn, arg); pthread_attr_destroy(&attr); } #endif