summaryrefslogtreecommitdiffstats
path: root/libnetdata/libnetdata.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/libnetdata.c')
-rw-r--r--libnetdata/libnetdata.c215
1 files changed, 175 insertions, 40 deletions
diff --git a/libnetdata/libnetdata.c b/libnetdata/libnetdata.c
index cc04a97eb..f6b6b026a 100644
--- a/libnetdata/libnetdata.c
+++ b/libnetdata/libnetdata.c
@@ -21,6 +21,81 @@ int enable_ksm = 0;
volatile sig_atomic_t netdata_exit = 0;
const char *program_version = VERSION;
+#define MAX_JUDY_SIZE_TO_ARAL 24
+static bool judy_sizes_config[MAX_JUDY_SIZE_TO_ARAL + 1] = {
+ [3] = true,
+ [4] = true,
+ [5] = true,
+ [6] = true,
+ [7] = true,
+ [8] = true,
+ [10] = true,
+ [11] = true,
+ [15] = true,
+ [23] = true,
+};
+static ARAL *judy_sizes_aral[MAX_JUDY_SIZE_TO_ARAL + 1] = {};
+
+struct aral_statistics judy_sizes_aral_statistics = {};
+
+void aral_judy_init(void) {
+ for(size_t Words = 0; Words <= MAX_JUDY_SIZE_TO_ARAL; Words++)
+ if(judy_sizes_config[Words]) {
+ char buf[30+1];
+ snprintfz(buf, 30, "judy-%zu", Words * sizeof(Word_t));
+ judy_sizes_aral[Words] = aral_create(
+ buf,
+ Words * sizeof(Word_t),
+ 0,
+ 65536,
+ &judy_sizes_aral_statistics,
+ NULL, NULL, false, false);
+ }
+}
+
+size_t judy_aral_overhead(void) {
+ return aral_overhead_from_stats(&judy_sizes_aral_statistics);
+}
+
+size_t judy_aral_structures(void) {
+ return aral_structures_from_stats(&judy_sizes_aral_statistics);
+}
+
+static ARAL *judy_size_aral(Word_t Words) {
+ if(Words <= MAX_JUDY_SIZE_TO_ARAL && judy_sizes_aral[Words])
+ return judy_sizes_aral[Words];
+
+ return NULL;
+}
+
+inline Word_t JudyMalloc(Word_t Words) {
+ Word_t Addr;
+
+ ARAL *ar = judy_size_aral(Words);
+ if(ar)
+ Addr = (Word_t) aral_mallocz(ar);
+ else
+ Addr = (Word_t) mallocz(Words * sizeof(Word_t));
+
+ return(Addr);
+}
+
+inline void JudyFree(void * PWord, Word_t Words) {
+ ARAL *ar = judy_size_aral(Words);
+ if(ar)
+ aral_freez(ar, PWord);
+ else
+ freez(PWord);
+}
+
+Word_t JudyMallocVirtual(Word_t Words) {
+ return JudyMalloc(Words);
+}
+
+void JudyFreeVirtual(void * PWord, Word_t Words) {
+ JudyFree(PWord, Words);
+}
+
// ----------------------------------------------------------------------------
// memory allocation functions that handle failures
@@ -150,27 +225,6 @@ void posix_memfree(void *ptr) {
libc_free(ptr);
}
-Word_t JudyMalloc(Word_t Words) {
- Word_t Addr;
-
- Addr = (Word_t) mallocz(Words * sizeof(Word_t));
- return(Addr);
-}
-void JudyFree(void * PWord, Word_t Words) {
- (void)Words;
- freez(PWord);
-}
-Word_t JudyMallocVirtual(Word_t Words) {
- Word_t Addr;
-
- Addr = (Word_t) mallocz(Words * sizeof(Word_t));
- return(Addr);
-}
-void JudyFreeVirtual(void * PWord, Word_t Words) {
- (void)Words;
- freez(PWord);
-}
-
#define MALLOC_ALIGNMENT (sizeof(uintptr_t) * 2)
#define size_t_atomic_count(op, var, size) __atomic_## op ##_fetch(&(var), size, __ATOMIC_RELAXED)
#define size_t_atomic_bytes(op, var, size) __atomic_## op ##_fetch(&(var), ((size) % MALLOC_ALIGNMENT)?((size) + MALLOC_ALIGNMENT - ((size) % MALLOC_ALIGNMENT)):(size), __ATOMIC_RELAXED)
@@ -1176,7 +1230,7 @@ static int memory_file_open(const char *filename, size_t size) {
return fd;
}
-static inline int madvise_sequential(void *mem, size_t len) {
+inline int madvise_sequential(void *mem, size_t len) {
static int logger = 1;
int ret = madvise(mem, len, MADV_SEQUENTIAL);
@@ -1184,7 +1238,15 @@ static inline int madvise_sequential(void *mem, size_t len) {
return ret;
}
-static inline int madvise_dontfork(void *mem, size_t len) {
+inline int madvise_random(void *mem, size_t len) {
+ static int logger = 1;
+ int ret = madvise(mem, len, MADV_RANDOM);
+
+ if (ret != 0 && logger-- > 0) error("madvise(MADV_RANDOM) failed.");
+ return ret;
+}
+
+inline int madvise_dontfork(void *mem, size_t len) {
static int logger = 1;
int ret = madvise(mem, len, MADV_DONTFORK);
@@ -1192,7 +1254,7 @@ static inline int madvise_dontfork(void *mem, size_t len) {
return ret;
}
-static inline int madvise_willneed(void *mem, size_t len) {
+inline int madvise_willneed(void *mem, size_t len) {
static int logger = 1;
int ret = madvise(mem, len, MADV_WILLNEED);
@@ -1200,24 +1262,27 @@ static inline int madvise_willneed(void *mem, size_t len) {
return ret;
}
+inline int madvise_dontneed(void *mem, size_t len) {
+ static int logger = 1;
+ int ret = madvise(mem, len, MADV_DONTNEED);
+
+ if (ret != 0 && logger-- > 0) error("madvise(MADV_DONTNEED) failed.");
+ return ret;
+}
+
+inline int madvise_dontdump(void *mem __maybe_unused, size_t len __maybe_unused) {
#if __linux__
-static inline int madvise_dontdump(void *mem, size_t len) {
static int logger = 1;
int ret = madvise(mem, len, MADV_DONTDUMP);
if (ret != 0 && logger-- > 0) error("madvise(MADV_DONTDUMP) failed.");
return ret;
-}
#else
-static inline int madvise_dontdump(void *mem, size_t len) {
- UNUSED(mem);
- UNUSED(len);
-
return 0;
-}
#endif
+}
-static inline int madvise_mergeable(void *mem, size_t len) {
+inline int madvise_mergeable(void *mem __maybe_unused, size_t len __maybe_unused) {
#ifdef MADV_MERGEABLE
static int logger = 1;
int ret = madvise(mem, len, MADV_MERGEABLE);
@@ -1225,14 +1290,12 @@ static inline int madvise_mergeable(void *mem, size_t len) {
if (ret != 0 && logger-- > 0) error("madvise(MADV_MERGEABLE) failed.");
return ret;
#else
- UNUSED(mem);
- UNUSED(len);
-
return 0;
#endif
}
-void *netdata_mmap(const char *filename, size_t size, int flags, int ksm) {
+void *netdata_mmap(const char *filename, size_t size, int flags, int ksm, bool read_only, int *open_fd)
+{
// info("netdata_mmap('%s', %zu", filename, size);
// MAP_SHARED is used in memory mode map
@@ -1271,7 +1334,7 @@ void *netdata_mmap(const char *filename, size_t size, int flags, int ksm) {
fd_for_mmap = -1;
}
- mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd_for_mmap, 0);
+ mem = mmap(NULL, size, read_only ? PROT_READ : PROT_READ | PROT_WRITE, flags, fd_for_mmap, 0);
if (mem != MAP_FAILED) {
#ifdef NETDATA_TRACE_ALLOCATIONS
@@ -1288,15 +1351,20 @@ void *netdata_mmap(const char *filename, size_t size, int flags, int ksm) {
else info("Cannot seek to beginning of file '%s'.", filename);
}
- madvise_sequential(mem, size);
+ // madvise_sequential(mem, size);
madvise_dontfork(mem, size);
madvise_dontdump(mem, size);
- if(flags & MAP_SHARED) madvise_willneed(mem, size);
+ // if(flags & MAP_SHARED) madvise_willneed(mem, size);
if(ksm) madvise_mergeable(mem, size);
}
cleanup:
- if(fd != -1) close(fd);
+ if(fd != -1) {
+ if (open_fd)
+ *open_fd = fd;
+ else
+ close(fd);
+ }
if(mem == MAP_FAILED) return NULL;
errno = 0;
return mem;
@@ -1934,3 +2002,70 @@ bool run_command_and_copy_output_to_stdout(const char *command, int max_line_len
netdata_pclose(NULL, fp, pid);
return true;
}
+
+void for_each_open_fd(OPEN_FD_ACTION action, OPEN_FD_EXCLUDE excluded_fds){
+ int fd;
+
+ switch(action){
+ case OPEN_FD_ACTION_CLOSE:
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDIN)) (void)close(STDIN_FILENO);
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDOUT)) (void)close(STDOUT_FILENO);
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDERR)) (void)close(STDERR_FILENO);
+ break;
+ case OPEN_FD_ACTION_FD_CLOEXEC:
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDIN)) (void)fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC);
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDOUT)) (void)fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC);
+ if(!(excluded_fds & OPEN_FD_EXCLUDE_STDERR)) (void)fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC);
+ break;
+ default:
+ break; // do nothing
+ }
+
+#if defined(HAVE_CLOSE_RANGE)
+ if(close_range(STDERR_FILENO + 1, ~0U, (action == OPEN_FD_ACTION_FD_CLOEXEC ? CLOSE_RANGE_CLOEXEC : 0)) == 0) return;
+ error("close_range() failed, will try to close fds manually");
+#endif
+
+ DIR *dir = opendir("/proc/self/fd");
+ if (dir == NULL) {
+ struct rlimit rl;
+ int open_max = -1;
+
+ if(getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY) open_max = rl.rlim_max;
+#ifdef _SC_OPEN_MAX
+ else open_max = sysconf(_SC_OPEN_MAX);
+#endif
+
+ if (open_max == -1) open_max = 65535; // 65535 arbitrary default if everything else fails
+
+ for (fd = STDERR_FILENO + 1; fd < open_max; fd++) {
+ switch(action){
+ case OPEN_FD_ACTION_CLOSE:
+ if(fd_is_valid(fd)) (void)close(fd);
+ break;
+ case OPEN_FD_ACTION_FD_CLOEXEC:
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+ break;
+ default:
+ break; // do nothing
+ }
+ }
+ } else {
+ struct dirent *entry;
+ while ((entry = readdir(dir)) != NULL) {
+ fd = str2i(entry->d_name);
+ if(unlikely((fd == STDIN_FILENO ) || (fd == STDOUT_FILENO) || (fd == STDERR_FILENO) )) continue;
+ switch(action){
+ case OPEN_FD_ACTION_CLOSE:
+ if(fd_is_valid(fd)) (void)close(fd);
+ break;
+ case OPEN_FD_ACTION_FD_CLOEXEC:
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+ break;
+ default:
+ break; // do nothing
+ }
+ }
+ closedir(dir);
+ }
+}