summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata')
-rw-r--r--libnetdata/Makefile.am1
-rw-r--r--libnetdata/completion/Makefile.am4
-rw-r--r--libnetdata/completion/completion.c34
-rw-r--r--libnetdata/completion/completion.h22
-rw-r--r--libnetdata/ebpf/ebpf.c273
-rw-r--r--libnetdata/ebpf/ebpf.h132
-rw-r--r--libnetdata/libnetdata.c1
-rw-r--r--libnetdata/libnetdata.h7
-rw-r--r--libnetdata/log/log.c677
-rw-r--r--libnetdata/os.c19
-rw-r--r--libnetdata/os.h22
11 files changed, 734 insertions, 458 deletions
diff --git a/libnetdata/Makefile.am b/libnetdata/Makefile.am
index 598b72f5..e787801c 100644
--- a/libnetdata/Makefile.am
+++ b/libnetdata/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS = \
avl \
buffer \
clocks \
+ completion \
config \
dictionary \
ebpf \
diff --git a/libnetdata/completion/Makefile.am b/libnetdata/completion/Makefile.am
new file mode 100644
index 00000000..babdcf0d
--- /dev/null
+++ b/libnetdata/completion/Makefile.am
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/libnetdata/completion/completion.c b/libnetdata/completion/completion.c
new file mode 100644
index 00000000..77818f40
--- /dev/null
+++ b/libnetdata/completion/completion.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "completion.h"
+
+void completion_init(struct completion *p)
+{
+ p->completed = 0;
+ fatal_assert(0 == uv_cond_init(&p->cond));
+ fatal_assert(0 == uv_mutex_init(&p->mutex));
+}
+
+void completion_destroy(struct completion *p)
+{
+ uv_cond_destroy(&p->cond);
+ uv_mutex_destroy(&p->mutex);
+}
+
+void completion_wait_for(struct completion *p)
+{
+ uv_mutex_lock(&p->mutex);
+ while (0 == p->completed) {
+ uv_cond_wait(&p->cond, &p->mutex);
+ }
+ fatal_assert(1 == p->completed);
+ uv_mutex_unlock(&p->mutex);
+}
+
+void completion_mark_complete(struct completion *p)
+{
+ uv_mutex_lock(&p->mutex);
+ p->completed = 1;
+ uv_mutex_unlock(&p->mutex);
+ uv_cond_broadcast(&p->cond);
+}
diff --git a/libnetdata/completion/completion.h b/libnetdata/completion/completion.h
new file mode 100644
index 00000000..667360a4
--- /dev/null
+++ b/libnetdata/completion/completion.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_COMPLETION_H
+#define NETDATA_COMPLETION_H
+
+#include "../libnetdata.h"
+
+struct completion {
+ uv_mutex_t mutex;
+ uv_cond_t cond;
+ volatile unsigned completed;
+};
+
+void completion_init(struct completion *p);
+
+void completion_destroy(struct completion *p);
+
+void completion_wait_for(struct completion *p);
+
+void completion_mark_complete(struct completion *p);
+
+#endif /* NETDATA_COMPLETION_H */
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c
index 1ccaa7b4..ca40492f 100644
--- a/libnetdata/ebpf/ebpf.c
+++ b/libnetdata/ebpf/ebpf.c
@@ -110,9 +110,23 @@ int ebpf_get_kernel_version()
*move++ = *version++;
*move = '\0';
- return ((int)(str2l(major) * 65536) + (int)(str2l(minor) * 256) + (int)str2l(patch));
+ // This new rule is fixing kernel version according the formula:
+ // KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
+ // that was extracted from /usr/include/linux/version.h
+ int ipatch = (int)str2l(patch);
+ if (ipatch > 255)
+ ipatch = 255;
+
+ return ((int)(str2l(major) * 65536) + (int)(str2l(minor) * 256) + ipatch);
}
+/**
+ * Get RH release
+ *
+ * Read Red Hat release from /etc/redhat-release
+ *
+ * @return It returns RH release on success and -1 otherwise
+ */
int get_redhat_release()
{
char buffer[VERSION_STRING_LEN + 1];
@@ -249,64 +263,189 @@ int has_condition_to_run(int version)
//----------------------------------------------------------------------------------------------------------------------
-char *ebpf_kernel_suffix(int version, int isrh)
+/**
+ * Kernel Name
+ *
+ * Select kernel name used by eBPF programs
+ *
+ * Netdata delivers for users eBPF programs with specific suffixes that represent the kernels they were
+ * compiled, when we load the eBPF program, the suffix must be the nereast possible of the kernel running.
+ *
+ * @param selector select the kernel version.
+ *
+ * @return It returns the string to load kernel.
+ */
+static char *ebpf_select_kernel_name(uint32_t selector)
{
- if (isrh) {
- if (version >= NETDATA_EBPF_KERNEL_4_11)
- return "4.18";
- else
- return "3.10";
- } else {
- if (version >= NETDATA_EBPF_KERNEL_5_11)
- return "5.11";
- else if (version >= NETDATA_EBPF_KERNEL_5_10)
- return "5.10";
- else if (version >= NETDATA_EBPF_KERNEL_4_17)
- return "5.4";
- else if (version >= NETDATA_EBPF_KERNEL_4_15)
- return "4.16";
- else if (version >= NETDATA_EBPF_KERNEL_4_11)
- return "4.14";
+ static char *kernel_names[] = { NETDATA_IDX_STR_V3_10, NETDATA_IDX_STR_V4_14, NETDATA_IDX_STR_V4_16,
+ NETDATA_IDX_STR_V4_18, NETDATA_IDX_STR_V5_4, NETDATA_IDX_STR_V5_10,
+ NETDATA_IDX_STR_V5_11, NETDATA_IDX_STR_V5_15
+ };
+
+ return kernel_names[selector];
+}
+
+/**
+ * Select Max Index
+ *
+ * Select last index that will be tested on host.
+ *
+ * @param is_rhf is Red Hat fammily?
+ * @param kver the kernel version
+ *
+ * @return it returns the index to access kernel string.
+ */
+static int ebpf_select_max_index(int is_rhf, uint32_t kver)
+{
+ if (is_rhf > 0) { // Is Red Hat family
+ if (kver >= NETDATA_EBPF_KERNEL_4_11)
+ return NETDATA_IDX_V4_18;
+ } else { // Kernels from kernel.org
+ if (kver >= NETDATA_EBPF_KERNEL_5_15)
+ return NETDATA_IDX_V5_15;
+ else if (kver >= NETDATA_EBPF_KERNEL_5_11)
+ return NETDATA_IDX_V5_11;
+ else if (kver >= NETDATA_EBPF_KERNEL_5_10)
+ return NETDATA_IDX_V5_10;
+ else if (kver >= NETDATA_EBPF_KERNEL_4_17)
+ return NETDATA_IDX_V5_4;
+ else if (kver >= NETDATA_EBPF_KERNEL_4_15)
+ return NETDATA_IDX_V4_16;
+ else if (kver >= NETDATA_EBPF_KERNEL_4_11)
+ return NETDATA_IDX_V4_14;
}
- return NULL;
+ return NETDATA_IDX_V3_10;
+}
+
+/**
+ * Select Index
+ *
+ * Select index to load data.
+ *
+ * @param kernels is the variable with kernel versions.
+ * @param is_rhf is Red Hat fammily?
+ * param kver the kernel version
+ */
+static uint32_t ebpf_select_index(uint32_t kernels, int is_rhf, uint32_t kver)
+{
+ uint32_t start = ebpf_select_max_index(is_rhf, kver);
+ uint32_t idx;
+
+ for (idx = start; idx; idx--) {
+ if (kernels & 1 << idx)
+ break;
+ }
+
+ return idx;
+}
+
+/**
+ * Mount Name
+ *
+ * Mount name of eBPF program to be loaded.
+ *
+ * Netdata eBPF programs has the following format:
+ *
+ * Tnetdata_ebpf_N.V.o
+ *
+ * where:
+ * T - Is the eBPF type. When starts with 'p', this means we are only adding probes,
+ * and when they start with 'r' we are using retprobes.
+ * N - The eBPF program name.
+ * V - The kernel version in string format.
+ *
+ * @param out the vector where the name will be stored
+ * @param path
+ * @param len the size of the out vector.
+ * @param kver the kernel version
+ * @param name the eBPF program name.
+ * @param is_return is return or entry ?
+ */
+static void ebpf_mount_name(char *out, size_t len, char *path, uint32_t kver, const char *name, int is_return)
+{
+ char *version = ebpf_select_kernel_name(kver);
+ snprintfz(out, len, "%s/ebpf.d/%cnetdata_ebpf_%s.%s.o",
+ path,
+ (is_return) ? 'r' : 'p',
+ name,
+ version);
}
//----------------------------------------------------------------------------------------------------------------------
/**
- * Update Kernel
+ * Statistics from targets
*
- * Update string used to load eBPF programs
+ * Count the information from targets.
*
- * @param ks vector to store the value
- * @param length available length to store kernel
- * @param isrh Is a Red Hat distribution?
- * @param version the kernel version
+ * @param report the output structure
+ * @param targets vector with information about the eBPF plugin.
*/
-void ebpf_update_kernel(char *ks, size_t length, int isrh, int version)
+static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets_t *targets)
{
- char *kernel = ebpf_kernel_suffix(version, (isrh < 0) ? 0 : 1);
- size_t len = strlen(kernel);
- if (len > length)
- len = length - 1;
- strncpyz(ks, kernel, len);
- ks[len] = '\0';
+ if (!targets) {
+ report->probes = report->tracepoints = report->trampolines = 0;
+ return;
+ }
+
+ int i = 0;
+ while (targets[i].name) {
+ switch (targets[i].mode) {
+ case EBPF_LOAD_PROBE: {
+ report->probes++;
+ break;
+ }
+ case EBPF_LOAD_RETPROBE: {
+ report->retprobes++;
+ break;
+ }
+ case EBPF_LOAD_TRACEPOINT: {
+ report->tracepoints++;
+ break;
+ }
+ case EBPF_LOAD_TRAMPOLINE: {
+ report->trampolines++;
+ break;
+ }
+ }
+
+ i++;
+ }
}
-static int select_file(char *name, const char *program, size_t length, int mode, char *kernel_string)
+/**
+ * Update General stats
+ *
+ * Update eBPF plugin statistics that has relationship with the thread.
+ *
+ * This function must be called with mutex associated to charts is locked.
+ *
+ * @param report the output structure
+ * @param em the structure with information about how the module/thread is working.
+ */
+void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
{
- int ret = -1;
- if (!mode)
- ret = snprintf(name, length, "rnetdata_ebpf_%s.%s.o", program, kernel_string);
- else if (mode == 1)
- ret = snprintf(name, length, "dnetdata_ebpf_%s.%s.o", program, kernel_string);
- else if (mode == 2)
- ret = snprintf(name, length, "pnetdata_ebpf_%s.%s.o", program, kernel_string);
+ report->threads++;
- return ret;
+ // It is not necessary to report more information.
+ if (!em->enabled)
+ return;
+
+ report->running++;
+
+ // In theory the `else if` is useless, because when this function is called, the module should not stay in
+ // EBPF_LOAD_PLAY_DICE. We have this additional condition to detect errors from developers.
+ if (em->load == EBPF_LOAD_LEGACY)
+ report->legacy++;
+ else if (em->load == EBPF_LOAD_CORE)
+ report->core++;
+
+ ebpf_stats_targets(report, em->targets);
}
+//----------------------------------------------------------------------------------------------------------------------
+
void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em)
{
pid->user_input = em->pid_map_size;
@@ -375,18 +514,21 @@ static struct bpf_link **ebpf_attach_programs(struct bpf_object *obj, size_t len
struct bpf_link **links = callocz(length , sizeof(struct bpf_link *));
size_t i = 0;
struct bpf_program *prog;
+ ebpf_specify_name_t *w;
bpf_object__for_each_program(prog, obj)
{
- links[i] = bpf_program__attach(prog);
- if (libbpf_get_error(links[i]) && names) {
+ if (names) {
const char *name = bpf_program__name(prog);
- ebpf_specify_name_t *w = ebpf_find_names(names, name);
- if (w) {
- enum bpf_prog_type type = bpf_program__get_type(prog);
- if (type == BPF_PROG_TYPE_KPROBE)
- links[i] = bpf_program__attach_kprobe(prog, w->retprobe, w->optional);
- }
- }
+ w = ebpf_find_names(names, name);
+ } else
+ w = NULL;
+
+ if (w) {
+ enum bpf_prog_type type = bpf_program__get_type(prog);
+ if (type == BPF_PROG_TYPE_KPROBE)
+ links[i] = bpf_program__attach_kprobe(prog, w->retprobe, w->optional);
+ } else
+ links[i] = bpf_program__attach(prog);
if (libbpf_get_error(links[i])) {
links[i] = NULL;
@@ -449,17 +591,28 @@ static void ebpf_update_controller(ebpf_module_t *em, struct bpf_object *obj)
}
}
-struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *kernel_string,
+/**
+ * Load Program
+ *
+ * Load eBPF program into kernel
+ *
+ * @param plugins_dir directory where binary are stored
+ * @param em structure with information about eBPF program we will load.
+ * @param kver the kernel version according /usr/include/linux/version.h
+ * @param is_rhf is a kernel from Red Hat Family?
+ * @param obj structure where we will store object loaded.
+ *
+ * @return it returns a link for each target we associated an eBPF program.
+ */
+struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kver, int is_rhf,
struct bpf_object **obj)
{
char lpath[4096];
- char lname[128];
- int test = select_file(lname, em->thread_name, (size_t)127, em->mode, kernel_string);
- if (test < 0 || test > 127)
- return NULL;
+ uint32_t idx = ebpf_select_index(em->kernels, is_rhf, kver);
+
+ ebpf_mount_name(lpath, 4095, plugins_dir, idx, em->thread_name, em->mode);
- snprintf(lpath, 4096, "%s/ebpf.d/%s", plugins_dir, lname);
*obj = bpf_object__open_file(lpath, NULL);
if (libbpf_get_error(obj)) {
error("Cannot open BPF object %s", lpath);
@@ -480,10 +633,14 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *
size_t count_programs = ebpf_count_programs(*obj);
+#ifdef NETDATA_INTERNAL_CHECKS
+ info("eBPF program %s loaded with success!", lpath);
+#endif
+
return ebpf_attach_programs(*obj, count_programs, em->names);
}
-static char *ebpf_update_name(char *search)
+char *ebpf_find_symbol(char *search)
{
char filename[FILENAME_MAX + 1];
char *ret = NULL;
@@ -521,7 +678,7 @@ void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em)
size_t i = 0;
while (opt[i].program_name) {
opt[i].retprobe = (mode == MODE_RETURN);
- opt[i].optional = ebpf_update_name(opt[i].function_to_attach);
+ opt[i].optional = ebpf_find_symbol(opt[i].function_to_attach);
i++;
}
diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h
index 73128f52..12529967 100644
--- a/libnetdata/ebpf/ebpf.h
+++ b/libnetdata/ebpf/ebpf.h
@@ -23,14 +23,6 @@
#define EBPF_CFG_CGROUP "cgroups"
/**
- * The next magic number is got doing the following math:
- * 294960 = 4*65536 + 11*256 + 0
- *
- * For more details, please, read /usr/include/linux/version.h
- */
-#define NETDATA_MINIMUM_EBPF_KERNEL 264960
-
-/**
* The RedHat magic number was got doing:
*
* 1797 = 7*256 + 5
@@ -46,46 +38,63 @@
#define NETDATA_RH_8 2048
/**
- * Kernel 5.11
+ * Kernel Version
*
- * 330240 = 5*65536 + 11*256
- */
-#define NETDATA_EBPF_KERNEL_5_11 330496
-
-/**
- * Kernel 5.10
+ * Kernel versions are calculated using the following formula:
*
- * 330240 = 5*65536 + 10*256
- */
-#define NETDATA_EBPF_KERNEL_5_10 330240
-
-/**
- * Kernel 5.0
+ * VERSION = LINUX_VERSION_MAJOR*65536 + LINUX_VERSION_PATCHLEVEL*256 + LINUX_VERSION_SUBLEVEL
*
- * 327680 = 5*65536 +256*0
- */
-#define NETDATA_EBPF_KERNEL_5_0 327680
-
-/**
- * Kernel 4.17
+ * Where LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, and LINUX_VERSION_SUBLEVEL are extracted
+ * from /usr/include/linux/version.h.
*
- * 266496 = 4*65536 + 17*256
- */
-#define NETDATA_EBPF_KERNEL_4_17 266496
-
-/**
- * Kernel 4.15
+ * LINUX_VERSION_SUBLEVEL has the maximum value 255, but linux can have more SUBLEVELS.
*
- * 265984 = 4*65536 + 15*256
*/
-#define NETDATA_EBPF_KERNEL_4_15 265984
+enum netdata_ebpf_kernel_versions {
+ NETDATA_EBPF_KERNEL_4_11 = 264960, // 264960 = 4 * 65536 + 15 * 256
+ NETDATA_EBPF_KERNEL_4_15 = 265984, // 265984 = 4 * 65536 + 15 * 256
+ NETDATA_EBPF_KERNEL_4_17 = 266496, // 266496 = 4 * 65536 + 17 * 256
+ NETDATA_EBPF_KERNEL_5_0 = 327680, // 327680 = 5 * 65536 + 0 * 256
+ NETDATA_EBPF_KERNEL_5_10 = 330240, // 330240 = 5 * 65536 + 10 * 256
+ NETDATA_EBPF_KERNEL_5_11 = 330496, // 330240 = 5 * 65536 + 11 * 256
+ NETDATA_EBPF_KERNEL_5_15 = 331520 // 331520 = 5 * 65536 + 15 * 256
+};
+
+enum netdata_kernel_flag {
+ NETDATA_V3_10 = 1 << 0,
+ NETDATA_V4_14 = 1 << 1,
+ NETDATA_V4_16 = 1 << 2,
+ NETDATA_V4_18 = 1 << 3,
+ NETDATA_V5_4 = 1 << 4,
+ NETDATA_V5_10 = 1 << 5,
+ NETDATA_V5_11 = 1 << 6,
+ NETDATA_V5_15 = 1 << 7
+};
+
+enum netdata_kernel_idx {
+ NETDATA_IDX_V3_10,
+ NETDATA_IDX_V4_14,
+ NETDATA_IDX_V4_16,
+ NETDATA_IDX_V4_18,
+ NETDATA_IDX_V5_4 ,
+ NETDATA_IDX_V5_10,
+ NETDATA_IDX_V5_11,
+ NETDATA_IDX_V5_15
+};
+
+#define NETDATA_IDX_STR_V3_10 "3.10"
+#define NETDATA_IDX_STR_V4_14 "4.14"
+#define NETDATA_IDX_STR_V4_16 "4.16"
+#define NETDATA_IDX_STR_V4_18 "4.18"
+#define NETDATA_IDX_STR_V5_4 "5.4"
+#define NETDATA_IDX_STR_V5_10 "5.10"
+#define NETDATA_IDX_STR_V5_11 "5.11"
+#define NETDATA_IDX_STR_V5_15 "5.15"
/**
- * Kernel 4.11
- *
- * 264960 = 4*65536 + 15*256
+ * Minimum value has relationship with libbpf support.
*/
-#define NETDATA_EBPF_KERNEL_4_11 264960
+#define NETDATA_MINIMUM_EBPF_KERNEL NETDATA_EBPF_KERNEL_4_11
#define VERSION_STRING_LEN 256
#define EBPF_KERNEL_REJECT_LIST_FILE "ebpf_kernel_reject_list.txt"
@@ -148,6 +157,39 @@ typedef struct ebpf_specify_name {
bool retprobe;
} ebpf_specify_name_t;
+typedef enum netdata_ebpf_load_mode {
+ EBPF_LOAD_LEGACY, // Select legacy mode, this means we will load binaries
+ EBPF_LOAD_CORE, // When CO-RE is used, it is necessary to use the souce code
+
+ EBPF_LOAD_PLAY_DICE // Take a look on environment and choose the best option
+} netdata_ebpf_load_mode_t;
+
+typedef enum netdata_ebpf_program_loaded {
+ EBPF_LOAD_PROBE, // Attach probes on targets
+ EBPF_LOAD_RETPROBE, // Attach retprobes on targets
+ EBPF_LOAD_TRACEPOINT, // This stores log given description about the errors raised
+ EBPF_LOAD_TRAMPOLINE, // This attaches kprobe when the function is called
+} netdata_ebpf_program_loaded_t;
+
+typedef struct netdata_ebpf_targets {
+ char *name;
+ netdata_ebpf_program_loaded_t mode;
+} netdata_ebpf_targets_t;
+
+typedef struct ebpf_plugin_stats {
+ // Load options
+ uint32_t legacy; // Legacy codes
+ uint32_t core; // CO-RE codes, this means we are using source code compiled.
+
+ uint32_t threads; // Total number of threads
+ uint32_t running; // total number of threads running
+
+ uint32_t probes; // Number of kprobes loaded
+ uint32_t retprobes; // Number of kretprobes loaded
+ uint32_t tracepoints; // Number of tracepoints used
+ uint32_t trampolines; // Number of trampolines used
+} ebpf_plugin_stats_t;
+
typedef struct ebpf_module {
const char *thread_name;
const char *config_name;
@@ -166,25 +208,27 @@ typedef struct ebpf_module {
uint32_t pid_map_size;
struct config *cfg;
const char *config_file;
+ uint64_t kernels;
+ netdata_ebpf_load_mode_t load;
+ netdata_ebpf_targets_t *targets;
} ebpf_module_t;
extern int ebpf_get_kernel_version();
extern int get_redhat_release();
extern int has_condition_to_run(int version);
extern char *ebpf_kernel_suffix(int version, int isrh);
-extern void ebpf_update_kernel(char *ks, size_t length, int isrh, int version);
-extern struct bpf_link **ebpf_load_program(char *plugins_dir,
- ebpf_module_t *em,
- char *kernel_string,
- struct bpf_object **obj);
+extern struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kver, int is_rhf,
+ struct bpf_object **obj);
extern void ebpf_mount_config_name(char *filename, size_t length, char *path, const char *config);
extern int ebpf_load_config(struct config *config, char *filename);
extern void ebpf_update_module(ebpf_module_t *em);
extern void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em);
+extern char *ebpf_find_symbol(char *search);
extern void ebpf_load_addresses(ebpf_addresses_t *fa, int fd);
extern void ebpf_fill_algorithms(int *algorithms, size_t length, int algorithm);
extern char **ebpf_fill_histogram_dimension(size_t maximum);
+extern void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em);
// Histogram
#define NETDATA_EBPF_HIST_MAX_BINS 24UL
diff --git a/libnetdata/libnetdata.c b/libnetdata/libnetdata.c
index eb6fce74..18d02240 100644
--- a/libnetdata/libnetdata.c
+++ b/libnetdata/libnetdata.c
@@ -14,7 +14,6 @@ struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 };
int enable_ksm = 1;
volatile sig_atomic_t netdata_exit = 0;
-const char *os_type = NETDATA_OS_TYPE;
const char *program_version = VERSION;
// ----------------------------------------------------------------------------
diff --git a/libnetdata/libnetdata.h b/libnetdata/libnetdata.h
index b49ab21a..809cefa0 100644
--- a/libnetdata/libnetdata.h
+++ b/libnetdata/libnetdata.h
@@ -274,7 +274,6 @@ extern int verify_netdata_host_prefix();
extern int recursively_delete_dir(const char *path, const char *reason);
extern volatile sig_atomic_t netdata_exit;
-extern const char *os_type;
extern const char *program_version;
@@ -303,9 +302,14 @@ extern char *find_and_replace(const char *src, const char *find, const char *rep
#define KILOBITS_IN_A_MEGABIT 1000
/* misc. */
+
#define UNUSED(x) (void)(x)
#define error_report(x, args...) do { errno = 0; error(x, ##args); } while(0)
+// Taken from linux kernel
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
+
extern void netdata_cleanup_and_exit(int ret) NORETURN;
extern void send_statistics(const char *action, const char *action_result, const char *action_data);
extern char *netdata_configured_host_prefix;
@@ -318,6 +322,7 @@ extern char *netdata_configured_host_prefix;
#include "avl/avl.h"
#include "inlined.h"
#include "clocks/clocks.h"
+#include "completion/completion.h"
#include "popen/popen.h"
#include "simple_pattern/simple_pattern.h"
#ifdef ENABLE_HTTPS
diff --git a/libnetdata/log/log.c b/libnetdata/log/log.c
index 95d3d98d..90581269 100644
--- a/libnetdata/log/log.c
+++ b/libnetdata/log/log.c
@@ -24,10 +24,10 @@ const char *facility_log = NULL;
// Log facility(https://tools.ietf.org/html/rfc5424)
//
// The facilities accepted in the Netdata are in according with the following
-// header files for their respective operate system:
-// sys/syslog.h (Linux )
-// sys/sys/syslog.h (FreeBSD)
-// bsd/sys/syslog.h (darwin-xnu)
+// header files for their respective operating system:
+// sys/syslog.h (Linux )
+// sys/sys/syslog.h (FreeBSD)
+// bsd/sys/syslog.h (darwin-xnu)
#define LOG_AUTH_KEY "auth"
#define LOG_AUTHPRIV_KEY "authpriv"
@@ -71,229 +71,229 @@ const char *facility_log = NULL;
static int log_facility_id(const char *facility_name)
{
- static int
- hash_auth = 0,
- hash_authpriv = 0,
+ static int
+ hash_auth = 0,
+ hash_authpriv = 0,
#ifdef __FreeBSD__
- hash_console = 0,
+ hash_console = 0,
#endif
- hash_cron = 0,
- hash_daemon = 0,
- hash_ftp = 0,
+ hash_cron = 0,
+ hash_daemon = 0,
+ hash_ftp = 0,
#ifdef __APPLE__
- hash_install = 0,
+ hash_install = 0,
#endif
- hash_kern = 0,
- hash_lpr = 0,
- hash_mail = 0,
-// hash_mark = 0,
+ hash_kern = 0,
+ hash_lpr = 0,
+ hash_mail = 0,
+// hash_mark = 0,
#ifdef __APPLE__
- hash_netinfo = 0,
- hash_ras = 0,
- hash_remoteauth = 0,
+ hash_netinfo = 0,
+ hash_ras = 0,
+ hash_remoteauth = 0,
#endif
- hash_news = 0,
+ hash_news = 0,
#ifdef __FreeBSD__
- hash_ntp = 0,
+ hash_ntp = 0,
#endif
- hash_security = 0,
- hash_syslog = 0,
- hash_user = 0,
- hash_uucp = 0,
+ hash_security = 0,
+ hash_syslog = 0,
+ hash_user = 0,
+ hash_uucp = 0,
#ifdef __APPLE__
- hash_launchd = 0,
+ hash_launchd = 0,
#endif
- hash_local0 = 0,
- hash_local1 = 0,
- hash_local2 = 0,
- hash_local3 = 0,
- hash_local4 = 0,
- hash_local5 = 0,
- hash_local6 = 0,
- hash_local7 = 0;
-
- if(unlikely(!hash_auth))
- {
- hash_auth = simple_hash(LOG_AUTH_KEY);
- hash_authpriv = simple_hash(LOG_AUTHPRIV_KEY);
+ hash_local0 = 0,
+ hash_local1 = 0,
+ hash_local2 = 0,
+ hash_local3 = 0,
+ hash_local4 = 0,
+ hash_local5 = 0,
+ hash_local6 = 0,
+ hash_local7 = 0;
+
+ if(unlikely(!hash_auth))
+ {
+ hash_auth = simple_hash(LOG_AUTH_KEY);
+ hash_authpriv = simple_hash(LOG_AUTHPRIV_KEY);
#ifdef __FreeBSD__
- hash_console = simple_hash(LOG_CONSOLE_KEY);
+ hash_console = simple_hash(LOG_CONSOLE_KEY);
#endif
- hash_cron = simple_hash(LOG_CRON_KEY);
- hash_daemon = simple_hash(LOG_DAEMON_KEY);
- hash_ftp = simple_hash(LOG_FTP_KEY);
+ hash_cron = simple_hash(LOG_CRON_KEY);
+ hash_daemon = simple_hash(LOG_DAEMON_KEY);
+ hash_ftp = simple_hash(LOG_FTP_KEY);
#ifdef __APPLE__
- hash_install = simple_hash(LOG_INSTALL_KEY);
+ hash_install = simple_hash(LOG_INSTALL_KEY);
#endif
- hash_kern = simple_hash(LOG_KERN_KEY);
- hash_lpr = simple_hash(LOG_LPR_KEY);
- hash_mail = simple_hash(LOG_MAIL_KEY);
-// hash_mark = simple_uhash();
+ hash_kern = simple_hash(LOG_KERN_KEY);
+ hash_lpr = simple_hash(LOG_LPR_KEY);
+ hash_mail = simple_hash(LOG_MAIL_KEY);
+// hash_mark = simple_uhash();
#ifdef __APPLE__
- hash_netinfo = simple_hash(LOG_NETINFO_KEY);
- hash_ras = simple_hash(LOG_RAS_KEY);
- hash_remoteauth = simple_hash(LOG_REMOTEAUTH_KEY);
+ hash_netinfo = simple_hash(LOG_NETINFO_KEY);
+ hash_ras = simple_hash(LOG_RAS_KEY);
+ hash_remoteauth = simple_hash(LOG_REMOTEAUTH_KEY);
#endif
- hash_news = simple_hash(LOG_NEWS_KEY);
+ hash_news = simple_hash(LOG_NEWS_KEY);
#ifdef __FreeBSD__
- hash_ntp = simple_hash(LOG_NTP_KEY);
+ hash_ntp = simple_hash(LOG_NTP_KEY);
#endif
- hash_security = simple_hash(LOG_SECURITY_KEY);
- hash_syslog = simple_hash(LOG_SYSLOG_KEY);
- hash_user = simple_hash(LOG_USER_KEY);
- hash_uucp = simple_hash(LOG_UUCP_KEY);
+ hash_security = simple_hash(LOG_SECURITY_KEY);
+ hash_syslog = simple_hash(LOG_SYSLOG_KEY);
+ hash_user = simple_hash(LOG_USER_KEY);
+ hash_uucp = simple_hash(LOG_UUCP_KEY);
#ifdef __APPLE__
- hash_launchd = simple_hash(LOG_LAUNCHD_KEY);
+ hash_launchd = simple_hash(LOG_LAUNCHD_KEY);
#endif
- hash_local0 = simple_hash(LOG_LOCAL0_KEY);
- hash_local1 = simple_hash(LOG_LOCAL1_KEY);
- hash_local2 = simple_hash(LOG_LOCAL2_KEY);
- hash_local3 = simple_hash(LOG_LOCAL3_KEY);
- hash_local4 = simple_hash(LOG_LOCAL4_KEY);
- hash_local5 = simple_hash(LOG_LOCAL5_KEY);
- hash_local6 = simple_hash(LOG_LOCAL6_KEY);
- hash_local7 = simple_hash(LOG_LOCAL7_KEY);
- }
-
- int hash = simple_hash(facility_name);
- if ( hash == hash_auth )
- {
- return LOG_AUTH;
- }
- else if ( hash == hash_authpriv )
- {
- return LOG_AUTHPRIV;
- }
+ hash_local0 = simple_hash(LOG_LOCAL0_KEY);
+ hash_local1 = simple_hash(LOG_LOCAL1_KEY);
+ hash_local2 = simple_hash(LOG_LOCAL2_KEY);
+ hash_local3 = simple_hash(LOG_LOCAL3_KEY);
+ hash_local4 = simple_hash(LOG_LOCAL4_KEY);
+ hash_local5 = simple_hash(LOG_LOCAL5_KEY);
+ hash_local6 = simple_hash(LOG_LOCAL6_KEY);
+ hash_local7 = simple_hash(LOG_LOCAL7_KEY);
+ }
+
+ int hash = simple_hash(facility_name);
+ if ( hash == hash_auth )
+ {
+ return LOG_AUTH;
+ }
+ else if ( hash == hash_authpriv )
+ {
+ return LOG_AUTHPRIV;
+ }
#ifdef __FreeBSD__
- else if ( hash == hash_console )
- {
- return LOG_CONSOLE;
- }
+ else if ( hash == hash_console )
+ {
+ return LOG_CONSOLE;
+ }
#endif
- else if ( hash == hash_cron )
- {
- return LOG_CRON;
- }
- else if ( hash == hash_daemon )
- {
- return LOG_DAEMON;
- }
- else if ( hash == hash_ftp )
- {
- return LOG_FTP;
- }
+ else if ( hash == hash_cron )
+ {
+ return LOG_CRON;
+ }
+ else if ( hash == hash_daemon )
+ {
+ return LOG_DAEMON;
+ }
+ else if ( hash == hash_ftp )
+ {
+ return LOG_FTP;
+ }
#ifdef __APPLE__
- else if ( hash == hash_install )
- {
- return LOG_INSTALL;
- }
+ else if ( hash == hash_install )
+ {
+ return LOG_INSTALL;
+ }
#endif
- else if ( hash == hash_kern )
- {
- return LOG_KERN;
- }
- else if ( hash == hash_lpr )
- {
- return LOG_LPR;
- }
- else if ( hash == hash_mail )
- {
- return LOG_MAIL;
- }
- /*
- else if ( hash == hash_mark )
- {
- //this is internal for all OS
- return INTERNAL_MARK;
- }
- */
+ else if ( hash == hash_kern )
+ {
+ return LOG_KERN;
+ }
+ else if ( hash == hash_lpr )
+ {
+ return LOG_LPR;
+ }
+ else if ( hash == hash_mail )
+ {
+ return LOG_MAIL;
+ }
+ /*
+ else if ( hash == hash_mark )
+ {
+ //this is internal for all OS
+ return INTERNAL_MARK;
+ }
+ */
#ifdef __APPLE__
- else if ( hash == hash_netinfo )
- {
- return LOG_NETINFO;
- }
- else if ( hash == hash_ras )
- {
- return LOG_RAS;
- }
- else if ( hash == hash_remoteauth )
- {
- return LOG_REMOTEAUTH;
- }
+ else if ( hash == hash_netinfo )
+ {
+ return LOG_NETINFO;
+ }
+ else if ( hash == hash_ras )
+ {
+ return LOG_RAS;
+ }
+ else if ( hash == hash_remoteauth )
+ {
+ return LOG_REMOTEAUTH;
+ }
#endif
- else if ( hash == hash_news )
- {
- return LOG_NEWS;
- }
+ else if ( hash == hash_news )
+ {
+ return LOG_NEWS;
+ }
#ifdef __FreeBSD__
- else if ( hash == hash_ntp )
- {
- return LOG_NTP;
- }
+ else if ( hash == hash_ntp )
+ {
+ return LOG_NTP;
+ }
#endif
- else if ( hash == hash_security )
- {
- //FreeBSD is the unique that does not consider
- //this facility deprecated. We are keeping
- //it for other OS while they are kept in their headers.
+ else if ( hash == hash_security )
+ {
+ //FreeBSD is the unique that does not consider
+ //this facility deprecated. We are keeping
+ //it for other OS while they are kept in their headers.
#ifdef __FreeBSD__
- return LOG_SECURITY;
+ return LOG_SECURITY;
#else
- return LOG_AUTH;
+ return LOG_AUTH;
#endif
- }
- else if ( hash == hash_syslog )
- {
- return LOG_SYSLOG;
- }
- else if ( hash == hash_user )
- {
- return LOG_USER;
- }
- else if ( hash == hash_uucp )
- {
- return LOG_UUCP;
- }
- else if ( hash == hash_local0 )
- {
- return LOG_LOCAL0;
- }
- else if ( hash == hash_local1 )
- {
- return LOG_LOCAL1;
- }
- else if ( hash == hash_local2 )
- {
- return LOG_LOCAL2;
- }
- else if ( hash == hash_local3 )
- {
- return LOG_LOCAL3;
- }
- else if ( hash == hash_local4 )
- {
- return LOG_LOCAL4;
- }
- else if ( hash == hash_local5 )
- {
- return LOG_LOCAL5;
- }
- else if ( hash == hash_local6 )
- {
- return LOG_LOCAL6;
- }
- else if ( hash == hash_local7 )
- {
- return LOG_LOCAL7;
- }
+ }
+ else if ( hash == hash_syslog )
+ {
+ return LOG_SYSLOG;
+ }
+ else if ( hash == hash_user )
+ {
+ return LOG_USER;
+ }
+ else if ( hash == hash_uucp )
+ {
+ return LOG_UUCP;
+ }
+ else if ( hash == hash_local0 )
+ {
+ return LOG_LOCAL0;
+ }
+ else if ( hash == hash_local1 )
+ {
+ return LOG_LOCAL1;
+ }
+ else if ( hash == hash_local2 )
+ {
+ return LOG_LOCAL2;
+ }
+ else if ( hash == hash_local3 )
+ {
+ return LOG_LOCAL3;
+ }
+ else if ( hash == hash_local4 )
+ {
+ return LOG_LOCAL4;
+ }
+ else if ( hash == hash_local5 )
+ {
+ return LOG_LOCAL5;
+ }
+ else if ( hash == hash_local6 )
+ {
+ return LOG_LOCAL6;
+ }
+ else if ( hash == hash_local7 )
+ {
+ return LOG_LOCAL7;
+ }
#ifdef __APPLE__
- else if ( hash == hash_launchd )
- {
- return LOG_LAUNCHD;
- }
+ else if ( hash == hash_launchd )
+ {
+ return LOG_LAUNCHD;
+ }
#endif
- return LOG_DAEMON;
+ return LOG_DAEMON;
}
//we do not need to use this now, but I already created this function to be
@@ -301,135 +301,135 @@ static int log_facility_id(const char *facility_name)
/*
char *log_facility_name(int code)
{
- char *defvalue = { "daemon" };
- switch(code)
- {
- case LOG_AUTH:
- {
- return "auth";
- }
- case LOG_AUTHPRIV:
- {
- return "authpriv";
- }
+ char *defvalue = { "daemon" };
+ switch(code)
+ {
+ case LOG_AUTH:
+ {
+ return "auth";
+ }
+ case LOG_AUTHPRIV:
+ {
+ return "authpriv";
+ }
#ifdef __FreeBSD__
- case LOG_CONSOLE:
- {
- return "console";
- }
+ case LOG_CONSOLE:
+ {
+ return "console";
+ }
#endif
- case LOG_CRON:
- {
- return "cron";
- }
- case LOG_DAEMON:
- {
- return defvalue;
- }
- case LOG_FTP:
- {
- return "ftp";
- }
+ case LOG_CRON:
+ {
+ return "cron";
+ }
+ case LOG_DAEMON:
+ {
+ return defvalue;
+ }
+ case LOG_FTP:
+ {
+ return "ftp";
+ }
#ifdef __APPLE__
- case LOG_INSTALL:
- {
- return "install";
- }
+ case LOG_INSTALL:
+ {
+ return "install";
+ }
#endif
- case LOG_KERN:
- {
- return "kern";
- }
- case LOG_LPR:
- {
- return "lpr";
- }
- case LOG_MAIL:
- {
- return "mail";
- }
+ case LOG_KERN:
+ {
+ return "kern";
+ }
+ case LOG_LPR:
+ {
+ return "lpr";
+ }
+ case LOG_MAIL:
+ {
+ return "mail";
+ }
#ifdef __APPLE__
- case LOG_NETINFO:
- {
- return "netinfo" ;
- }
- case LOG_RAS:
- {
- return "ras";
- }
- case LOG_REMOTEAUTH:
- {
- return "remoteauth";
- }
+ case LOG_NETINFO:
+ {
+ return "netinfo" ;
+ }
+ case LOG_RAS:
+ {
+ return "ras";
+ }
+ case LOG_REMOTEAUTH:
+ {
+ return "remoteauth";
+ }
#endif
- case LOG_NEWS:
- {
- return "news";
- }
+ case LOG_NEWS:
+ {
+ return "news";
+ }
#ifdef __FreeBSD__
- case LOG_NTP:
- {
- return "ntp" ;
- }
- case LOG_SECURITY:
- {
- return "security";
- }
+ case LOG_NTP:
+ {
+ return "ntp" ;
+ }
+ case LOG_SECURITY:
+ {
+ return "security";
+ }
#endif
- case LOG_SYSLOG:
- {
- return "syslog";
- }
- case LOG_USER:
- {
- return "user";
- }
- case LOG_UUCP:
- {
- return "uucp";
- }
- case LOG_LOCAL0:
- {
- return "local0";
- }
- case LOG_LOCAL1:
- {
- return "local1";
- }
- case LOG_LOCAL2:
- {
- return "local2";
- }
- case LOG_LOCAL3:
- {
- return "local3";
- }
- case LOG_LOCAL4:
- {
- return "local4" ;
- }
- case LOG_LOCAL5:
- {
- return "local5";
- }
- case LOG_LOCAL6:
- {
- return "local6";
- }
- case LOG_LOCAL7:
- {
- return "local7" ;
- }
+ case LOG_SYSLOG:
+ {
+ return "syslog";
+ }
+ case LOG_USER:
+ {
+ return "user";
+ }
+ case LOG_UUCP:
+ {
+ return "uucp";
+ }
+ case LOG_LOCAL0:
+ {
+ return "local0";
+ }
+ case LOG_LOCAL1:
+ {
+ return "local1";
+ }
+ case LOG_LOCAL2:
+ {
+ return "local2";
+ }
+ case LOG_LOCAL3:
+ {
+ return "local3";
+ }
+ case LOG_LOCAL4:
+ {
+ return "local4" ;
+ }
+ case LOG_LOCAL5:
+ {
+ return "local5";
+ }
+ case LOG_LOCAL6:
+ {
+ return "local6";
+ }
+ case LOG_LOCAL7:
+ {
+ return "local7" ;
+ }
#ifdef __APPLE__
- case LOG_LAUNCHD:
- {
- return "launchd";
- }
+ case LOG_LAUNCHD:
+ {
+ return "launchd";
+ }
#endif
- }
+ }
- return defvalue;
-}
+ return defvalue;
+}
*/
// ----------------------------------------------------------------------------
@@ -486,7 +486,7 @@ static FILE *open_log_file(int fd, FILE *fp, const char *filename, int *enabled_
filename = "/dev/null";
devnull = 1;
- syslog_init();
+ syslog_init();
if(enabled_syslog) *enabled_syslog = 1;
}
else if(enabled_syslog) *enabled_syslog = 0;
@@ -607,13 +607,15 @@ int error_log_limit(int reset) {
if(prevented) {
char date[LOG_DATE_LENGTH];
log_date(date, LOG_DATE_LENGTH);
- fprintf(stderr, "%s: %s LOG FLOOD PROTECTION reset for process '%s' (prevented %lu logs in the last %ld seconds).\n"
- , date
- , program_name
- , program_name
- , prevented
- , now - start
- );
+ fprintf(
+ stderr,
+ "%s: %s LOG FLOOD PROTECTION reset for process '%s' "
+ "(prevented %lu logs in the last %"PRId64" seconds).\n",
+ date,
+ program_name,
+ program_name,
+ prevented,
+ (int64_t)(now - start));
}
start = now;
@@ -628,13 +630,15 @@ int error_log_limit(int reset) {
if(prevented) {
char date[LOG_DATE_LENGTH];
log_date(date, LOG_DATE_LENGTH);
- fprintf(stderr, "%s: %s LOG FLOOD PROTECTION resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
- , date
- , program_name
- , program_name
- , prevented
- , error_log_throttle_period
- );
+ fprintf(
+ stderr,
+ "%s: %s LOG FLOOD PROTECTION resuming logging from process '%s' "
+ "(prevented %lu logs in the last %"PRId64" seconds).\n",
+ date,
+ program_name,
+ program_name,
+ prevented,
+ (int64_t)error_log_throttle_period);
}
// restart the period accounting
@@ -650,15 +654,18 @@ int error_log_limit(int reset) {
if(!prevented) {
char date[LOG_DATE_LENGTH];
log_date(date, LOG_DATE_LENGTH);
- fprintf(stderr, "%s: %s LOG FLOOD PROTECTION too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
- , date
- , program_name
- , counter
- , now - start
- , error_log_errors_per_period
- , error_log_throttle_period
- , program_name
- , start + error_log_throttle_period - now);
+ fprintf(
+ stderr,
+ "%s: %s LOG FLOOD PROTECTION too many logs (%lu logs in %"PRId64" seconds, threshold is set to %lu logs "
+ "in %"PRId64" seconds). Preventing more logs from process '%s' for %"PRId64" seconds.\n",
+ date,
+ program_name,
+ counter,
+ (int64_t)(now - start),
+ error_log_errors_per_period,
+ (int64_t)error_log_throttle_period,
+ program_name,
+ (int64_t)(start + error_log_throttle_period - now));
}
prevented++;
diff --git a/libnetdata/os.c b/libnetdata/os.c
index 4271a917..196288a6 100644
--- a/libnetdata/os.c
+++ b/libnetdata/os.c
@@ -123,7 +123,9 @@ void get_system_HZ(void) {
// =====================================================================================================================
// FreeBSD
-#if (TARGET_OS == OS_FREEBSD)
+#if __FreeBSD__
+
+const char *os_type = "freebsd";
int getsysctl_by_name(const char *name, void *ptr, size_t len) {
size_t nlen = len;
@@ -198,7 +200,9 @@ int getsysctl_mib(const char *name, int *mib, size_t len) {
// =====================================================================================================================
// MacOS
-#if (TARGET_OS == OS_MACOS)
+#if __APPLE__
+
+const char *os_type = "macos";
int getsysctl_by_name(const char *name, void *ptr, size_t len) {
size_t nlen = len;
@@ -214,4 +218,13 @@ int getsysctl_by_name(const char *name, void *ptr, size_t len) {
return 0;
}
-#endif // (TARGET_OS == OS_MACOS)
+#endif
+
+// =====================================================================================================================
+// Linux
+
+#if __linux__
+
+const char *os_type = "linux";
+
+#endif
diff --git a/libnetdata/os.h b/libnetdata/os.h
index 2494174b..7872f82b 100644
--- a/libnetdata/os.h
+++ b/libnetdata/os.h
@@ -6,15 +6,9 @@
#include "libnetdata.h"
// =====================================================================================================================
-// Linux
-
-#if (TARGET_OS == OS_LINUX)
-
-
-// =====================================================================================================================
// FreeBSD
-#elif (TARGET_OS == OS_FREEBSD)
+#if __FreeBSD__
#include <sys/sysctl.h>
@@ -35,28 +29,24 @@ extern int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr
extern int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len);
+#endif
// =====================================================================================================================
// MacOS
-#elif (TARGET_OS == OS_MACOS)
+#if __APPLE__
#include <sys/sysctl.h>
#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
extern int getsysctl_by_name(const char *name, void *ptr, size_t len);
-
-// =====================================================================================================================
-// unknown O/S
-
-#else
-#error unsupported operating system
#endif
-
// =====================================================================================================================
-// common for all O/S
+// common defs for Apple/FreeBSD/Linux
+
+extern const char *os_type;
extern int processors;
extern long get_system_cpus(void);