2018-08-21 05:27:52 +00:00
|
|
|
/* Copyright 2017-2018 ccls Authors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
==============================================================================*/
|
|
|
|
|
2017-12-17 20:40:21 +00:00
|
|
|
#if defined(__unix__) || defined(__APPLE__)
|
2017-03-04 01:45:20 +00:00
|
|
|
#include "platform.h"
|
|
|
|
|
2017-03-25 20:15:00 +00:00
|
|
|
#include "utils.h"
|
2017-03-04 01:45:20 +00:00
|
|
|
|
|
|
|
#include <assert.h>
|
2017-09-22 01:14:57 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2017-04-18 17:21:53 +00:00
|
|
|
#include <dirent.h>
|
2018-05-13 16:52:19 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2018-10-02 16:34:55 +00:00
|
|
|
#include <pthread.h>
|
2018-05-13 16:52:19 +00:00
|
|
|
#include <signal.h>
|
2018-10-02 16:34:55 +00:00
|
|
|
#include <sys/resource.h>
|
2017-04-20 16:47:24 +00:00
|
|
|
#include <sys/stat.h>
|
2018-08-09 17:08:14 +00:00
|
|
|
#include <sys/types.h> // required for stat.h
|
2018-02-20 00:19:57 +00:00
|
|
|
#include <sys/wait.h>
|
2018-08-09 17:08:14 +00:00
|
|
|
#include <unistd.h>
|
2018-05-13 16:52:19 +00:00
|
|
|
#ifdef __GLIBC__
|
2017-12-23 16:01:43 +00:00
|
|
|
#include <malloc.h>
|
2017-10-31 22:43:07 +00:00
|
|
|
#endif
|
|
|
|
|
2018-10-15 08:26:13 +00:00
|
|
|
#include <llvm/ADT/SmallString.h>
|
|
|
|
#include <llvm/Support/Path.h>
|
2017-11-30 18:40:42 +00:00
|
|
|
|
2018-10-15 08:26:13 +00:00
|
|
|
#include <string>
|
2017-11-30 18:40:42 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
std::string NormalizePath(const std::string &path) {
|
2018-10-15 08:26:13 +00:00
|
|
|
llvm::SmallString<256> P(path);
|
|
|
|
llvm::sys::path::remove_dots(P, true);
|
|
|
|
return {P.data(), P.size()};
|
2017-03-28 01:47:12 +00:00
|
|
|
}
|
|
|
|
|
2017-08-17 18:02:47 +00:00
|
|
|
void FreeUnusedMemory() {
|
2018-05-13 16:52:19 +00:00
|
|
|
#ifdef __GLIBC__
|
2018-09-23 19:10:40 +00:00
|
|
|
malloc_trim(4 * 1024 * 1024);
|
2017-10-31 22:43:07 +00:00
|
|
|
#endif
|
2017-08-17 18:02:47 +00:00
|
|
|
}
|
|
|
|
|
2018-01-07 07:42:42 +00:00
|
|
|
void TraceMe() {
|
|
|
|
// If the environment variable is defined, wait for a debugger.
|
2018-03-31 03:16:33 +00:00
|
|
|
// In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
|
2018-01-07 07:42:42 +00:00
|
|
|
// after detaching.
|
2018-08-09 17:08:14 +00:00
|
|
|
const char *traceme = getenv("CCLS_TRACEME");
|
2018-04-30 04:49:03 +00:00
|
|
|
if (traceme)
|
|
|
|
raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
|
2018-01-07 07:42:42 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
std::string GetExternalCommandOutput(const std::vector<std::string> &command,
|
2018-02-20 00:19:57 +00:00
|
|
|
std::string_view input) {
|
|
|
|
int pin[2], pout[2];
|
2018-04-02 03:55:10 +00:00
|
|
|
if (pipe(pin) < 0) {
|
|
|
|
perror("pipe(stdin)");
|
2018-02-20 01:19:50 +00:00
|
|
|
return "";
|
2018-04-02 03:55:10 +00:00
|
|
|
}
|
2018-02-20 01:19:50 +00:00
|
|
|
if (pipe(pout) < 0) {
|
2018-04-02 03:55:10 +00:00
|
|
|
perror("pipe(stdout)");
|
2018-02-20 01:19:50 +00:00
|
|
|
close(pin[0]);
|
|
|
|
close(pin[1]);
|
|
|
|
return "";
|
|
|
|
}
|
2018-02-20 00:19:57 +00:00
|
|
|
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]);
|
2018-08-09 17:08:14 +00:00
|
|
|
auto argv = new char *[command.size() + 1];
|
2018-02-20 00:19:57 +00:00
|
|
|
for (size_t i = 0; i < command.size(); i++)
|
2018-08-09 17:08:14 +00:00
|
|
|
argv[i] = const_cast<char *>(command[i].c_str());
|
2018-02-20 00:19:57 +00:00
|
|
|
argv[command.size()] = nullptr;
|
|
|
|
execvp(argv[0], argv);
|
|
|
|
_Exit(127);
|
|
|
|
}
|
|
|
|
close(pin[1]);
|
|
|
|
close(pout[0]);
|
2018-02-20 03:06:48 +00:00
|
|
|
// O_NONBLOCK is disabled, write(2) blocks until all bytes are written.
|
|
|
|
(void)write(pout[1], input.data(), input.size());
|
2018-02-20 00:19:57 +00:00
|
|
|
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);
|
2018-04-02 03:55:10 +00:00
|
|
|
close(pin[0]);
|
2018-02-20 00:19:57 +00:00
|
|
|
waitpid(child, NULL, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-10-02 16:34:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-03-21 17:06:22 +00:00
|
|
|
#endif
|