1 // Copyright 2017-2018 ccls Authors
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #if defined(__unix__) || defined(__APPLE__)
5 #include "platform.hh"
6 
7 #include "utils.hh"
8 
9 #include <assert.h>
10 #include <limits.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
15 
16 #include <dirent.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <sys/resource.h>
22 #include <sys/stat.h>
23 #include <sys/types.h> // required for stat.h
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #ifdef __GLIBC__
27 #include <malloc.h>
28 #endif
29 
30 #include <llvm/ADT/SmallString.h>
31 #include <llvm/Support/Path.h>
32 
33 #include <atomic>
34 #include <condition_variable>
35 #include <mutex>
36 #include <string>
37 
38 namespace ccls {
39 namespace pipeline {
40 void threadEnter();
41 }
42 
normalizePath(llvm::StringRef path)43 std::string normalizePath(llvm::StringRef path) {
44   llvm::SmallString<256> p(path);
45   llvm::sys::path::remove_dots(p, true);
46   return {p.data(), p.size()};
47 }
48 
freeUnusedMemory()49 void freeUnusedMemory() {
50 #ifdef __GLIBC__
51   malloc_trim(4 * 1024 * 1024);
52 #endif
53 }
54 
traceMe()55 void traceMe() {
56   // If the environment variable is defined, wait for a debugger.
57   // In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
58   // after detaching.
59   const char *traceme = getenv("CCLS_TRACEME");
60   if (traceme)
61     raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
62 }
63 
spawnThread(void * (* fn)(void *),void * arg)64 void spawnThread(void *(*fn)(void *), void *arg) {
65   pthread_t thd;
66   pthread_attr_t attr;
67   struct rlimit rlim;
68   size_t stack_size = 4 * 1024 * 1024;
69   if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur != RLIM_INFINITY)
70     stack_size = rlim.rlim_cur;
71   pthread_attr_init(&attr);
72   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
73   pthread_attr_setstacksize(&attr, stack_size);
74   pipeline::threadEnter();
75   pthread_create(&thd, &attr, fn, arg);
76   pthread_attr_destroy(&attr);
77 }
78 } // namespace ccls
79 
80 #endif
81