mirror of
https://github.com/MaskRay/ccls.git
synced 2025-12-15 19:53:26 +00:00
noteBottomOfStack: Without this, checks against stack space within Clang don't work as Clang doesn't know where the stack begins. Needed per-thread, as early as possible. (on threads using Clang) Using Clang's desired stack size: Additionally increase stack size of pthreads to Clang's desired size. This is presently 8MB, and is used by Clang's stack management mechanisms to check* if close to stack exhaustion when determining if there's sufficient space (and warn or run on a new thread with more). (see runWithSufficientStackSpace) The constant is available in LLVM 7 onwards. * (abs(cur - bottom) > DesiredStackSize - threshold)
97 lines
2.2 KiB
C++
97 lines
2.2 KiB
C++
// Copyright 2017-2018 ccls Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
|
|
#include "platform.hh"
|
|
|
|
#include "utils.hh"
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h> // required for stat.h
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#ifdef __GLIBC__
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#include <clang/Basic/Stack.h>
|
|
|
|
#include <llvm/ADT/SmallString.h>
|
|
#include <llvm/Support/Path.h>
|
|
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
namespace ccls {
|
|
namespace pipeline {
|
|
void threadEnter();
|
|
}
|
|
|
|
std::string normalizePath(llvm::StringRef 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);
|
|
}
|
|
|
|
struct ThreadInfo {
|
|
void *(*fn)(void *);
|
|
void *arg;
|
|
};
|
|
|
|
void *threadWrapper(void *arg) {
|
|
ThreadInfo ti = *(ThreadInfo *)arg;
|
|
delete (ThreadInfo *)arg;
|
|
#if LLVM_VERSION_MAJOR >= 10 // rL369940
|
|
clang::noteBottomOfStack(); // per-thread, needed to avoid stack exhaustion
|
|
#endif
|
|
return ti.fn(ti.arg);
|
|
}
|
|
|
|
void spawnThread(void *(*fn)(void *), void *arg) {
|
|
pthread_t thd;
|
|
pthread_attr_t attr;
|
|
struct rlimit rlim;
|
|
size_t stack_size = clang::DesiredStackSize;
|
|
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);
|
|
pipeline::threadEnter();
|
|
pthread_create(&thd, &attr, threadWrapper, new ThreadInfo{fn, arg});
|
|
pthread_attr_destroy(&attr);
|
|
}
|
|
} // namespace ccls
|
|
|
|
#endif
|