+volatile sig_atomic_t netdata_exit = 0;
+
+// ----------------------------------------------------------------------------
+// memory allocation functions that handle failures
+
+// although netdata does not use memory allocations too often (netdata tries to
+// maintain its memory footprint stable during runtime, i.e. all buffers are
+// allocated during initialization and are adapted to current use throughout
+// its lifetime), these can be used to override the default system allocation
+// routines.
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+static struct memory_statistics {
+ volatile size_t malloc_calls_made;
+ volatile size_t calloc_calls_made;
+ volatile size_t realloc_calls_made;
+ volatile size_t strdup_calls_made;
+ volatile size_t free_calls_made;
+ volatile size_t memory_calls_made;
+ volatile size_t allocated_memory;
+ volatile size_t mmapped_memory;
+} memory_statistics;
+
+static inline void print_allocations(const char *file, const char *function, const unsigned long line) {
+ static struct memory_statistics old = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ //if(unlikely(!(memory_statistics.memory_calls_made % 5))) {
+ fprintf(stderr, "(%04lu@%-10.10s:%-15.15s): Allocated %zu KB (+%zu B), mmapped %zu KB (+%zu B): malloc %zu (+%zu), calloc %zu (+%zu), realloc %zu (+%zu), strdup %zu (+%zu), free %zu (+%zu)\n",
+ line, file, function,
+ (memory_statistics.allocated_memory + 512) / 1024, memory_statistics.allocated_memory - old.allocated_memory,
+ (memory_statistics.mmapped_memory + 512) / 1024, memory_statistics.mmapped_memory - old.mmapped_memory,
+ memory_statistics.malloc_calls_made, memory_statistics.malloc_calls_made - old.malloc_calls_made,
+ memory_statistics.calloc_calls_made, memory_statistics.calloc_calls_made - old.calloc_calls_made,
+ memory_statistics.realloc_calls_made, memory_statistics.realloc_calls_made - old.realloc_calls_made,
+ memory_statistics.strdup_calls_made, memory_statistics.strdup_calls_made - old.strdup_calls_made,
+ memory_statistics.free_calls_made, memory_statistics.free_calls_made - old.free_calls_made
+ );
+
+ memcpy(&old, &memory_statistics, sizeof(struct memory_statistics));
+ //}
+}
+
+static inline void malloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) {
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.malloc_calls_made++;
+ memory_statistics.allocated_memory += size;
+#endif
+ print_allocations(file, function, line);
+}
+
+static inline void mmap_accounting(size_t size) {
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.mmapped_memory, size, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.mmapped_memory += size;
+#endif
+}
+
+static inline void calloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) {
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.calloc_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.calloc_calls_made++;
+ memory_statistics.allocated_memory += size;
+#endif
+ print_allocations(file, function, line);
+}
+
+static inline void realloc_accounting(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) {
+ (void)ptr;
+
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.realloc_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.realloc_calls_made++;
+ memory_statistics.allocated_memory += size;
+#endif
+ print_allocations(file, function, line);
+}
+
+static inline void strdup_accounting(const char *file, const char *function, const unsigned long line, const char *s) {
+ size_t size = strlen(s) + 1;
+
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.strdup_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.strdup_calls_made++;
+ memory_statistics.allocated_memory += size;
+#endif
+ print_allocations(file, function, line);
+}
+
+static inline void free_accounting(const char *file, const char *function, const unsigned long line, void *ptr) {
+ (void)file;
+ (void)function;
+ (void)line;
+
+ if(likely(ptr)) {
+#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
+ __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
+ __atomic_fetch_add(&memory_statistics.free_calls_made, 1, __ATOMIC_SEQ_CST);
+#else
+ // this is for debugging - we don't care locking it
+ memory_statistics.memory_calls_made++;
+ memory_statistics.free_calls_made++;
+#endif
+ }
+}
+#endif
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s) {
+ strdup_accounting(file, function, line, s);
+#else
+char *strdupz(const char *s) {
+#endif
+
+ char *t = strdup(s);
+ if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s);
+ return t;
+}
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size) {
+ malloc_accounting(file, function, line, size);
+#else
+void *mallocz(size_t size) {
+#endif
+
+ void *p = malloc(size);
+ if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size);
+ return p;
+}
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size) {
+ calloc_accounting(file, function, line, nmemb * size);
+#else
+void *callocz(size_t nmemb, size_t size) {
+#endif
+
+ void *p = calloc(nmemb, size);
+ if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size);
+ return p;
+}
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) {
+ realloc_accounting(file, function, line, ptr, size);
+#else
+void *reallocz(void *ptr, size_t size) {
+#endif
+
+ void *p = realloc(ptr, size);
+ if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size);
+ return p;
+}
+
+#ifdef NETDATA_LOG_ALLOCATIONS
+void freez_int(const char *file, const char *function, const unsigned long line, void *ptr) {
+ free_accounting(file, function, line, ptr);
+#else
+void freez(void *ptr) {
+#endif
+
+ free(ptr);
+}
+
+// ----------------------------------------------------------------------------
+// time functions
+
+inline unsigned long long timeval_usec(struct timeval *tv) {
+ return tv->tv_sec * 1000000ULL + tv->tv_usec;
+}
+
+// time(NULL) in nanoseconds
+inline unsigned long long time_usec(void) {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return timeval_usec(&now);
+}
+
+inline unsigned long long usec_dt(struct timeval *now, struct timeval *old) {
+ unsigned long long tv1 = timeval_usec(now);
+ unsigned long long tv2 = timeval_usec(old);
+ return (tv1 > tv2) ? (tv1 - tv2) : (tv2 - tv1);
+}
+
+int sleep_usec(unsigned long long usec) {
+
+#ifndef NETDATA_WITH_USLEEP
+ // we expect microseconds (1.000.000 per second)
+ // but timespec is nanoseconds (1.000.000.000 per second)
+ struct timespec rem, req = {
+ .tv_sec = (time_t) (usec / 1000000),
+ .tv_nsec = (suseconds_t) ((usec % 1000000) * 1000)
+ };
+
+ while (nanosleep(&req, &rem) == -1) {
+ if (likely(errno == EINTR)) {
+ debug(D_SYSTEM, "nanosleep() interrupted (while sleeping for %llu microseconds).", usec);
+ req.tv_sec = rem.tv_sec;
+ req.tv_nsec = rem.tv_nsec;
+ } else {
+ error("Cannot nanosleep() for %llu microseconds.", usec);
+ break;
+ }
+ }
+
+ return 0;
+#else
+ int ret = usleep(usec);
+ if(unlikely(ret == -1 && errno == EINVAL)) {
+ // on certain systems, usec has to be up to 999999
+ if(usec > 999999) {
+ int counter = usec / 999999;
+ while(counter--)
+ usleep(999999);
+
+ usleep(usec % 999999);
+ }
+ else {
+ error("Cannot usleep() for %llu microseconds.", usec);
+ return ret;
+ }
+ }
+
+ if(ret != 0)
+ error("usleep() failed for %llu microseconds.", usec);
+
+ return ret;
+#endif