0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-12 16:58:10 +00:00
netdata_netdata/libnetdata/threads/threads.c
Costa Tsaousis cb7af25c09
RRD structures managed by dictionaries ()
* rrdset - in progress

* rrdset optimal constructor; rrdset conflict

* rrdset final touches

* re-organization of rrdset object members

* prevent use-after-free

* dictionary dfe supports also counting of iterations

* rrddim managed by dictionary

* rrd.h cleanup

* DICTIONARY_ITEM now is referencing actual dictionary items in the code

* removed rrdset linked list

* Revert "removed rrdset linked list"

This reverts commit 690d6a588b4b99619c2c5e10f84e8f868ae6def5.

* removed rrdset linked list

* added comments

* Switch chart uuid to static allocation in rrdset
Remove unused functions

* rrdset_archive() and friends...

* always create rrdfamily

* enable ml_free_dimension

* rrddim_foreach done with dfe

* most custom rrddim loops replaced with rrddim_foreach

* removed accesses to rrddim->dimensions

* removed locks that are no longer needed

* rrdsetvar is now managed by the dictionary

* set rrdset is rrdsetvar, fixes https://github.com/netdata/netdata/pull/13646#issuecomment-1242574853

* conflict callback of rrdsetvar now properly checks if it has to reset the variable

* dictionary registered callbacks accept as first parameter the DICTIONARY_ITEM

* dictionary dfe now uses internal counter to report; avoided excess variables defined with dfe

* dictionary walkthrough callbacks get dictionary acquired items

* dictionary reference counters that can be dupped from zero

* added advanced functions for get and del

* rrdvar managed by dictionaries

* thread safety for rrdsetvar

* faster rrdvar initialization

* rrdvar string lengths should match in all add, del, get functions

* rrdvar internals hidden from the rest of the world

* rrdvar is now acquired throughout netdata

* hide the internal structures of rrdsetvar

* rrdsetvar is now acquired through out netdata

* rrddimvar managed by dictionary; rrddimvar linked list removed; rrddimvar structures hidden from the rest of netdata

* better error handling

* dont create variables if not initialized for health

* dont create variables if not initialized for health again

* rrdfamily is now managed by dictionaries; references of it are acquired dictionary items

* type checking on acquired objects

* rrdcalc renaming of functions

* type checking for rrdfamily_acquired

* rrdcalc managed by dictionaries

* rrdcalc double free fix

* host rrdvars is always needed

* attempt to fix deadlock 1

* attempt to fix deadlock 2

* Remove unused variable

* attempt to fix deadlock 3

* snprintfz

* rrdcalc index in rrdset fix

* Stop storing active charts and computing chart hashes

* Remove store active chart function

* Remove compute chart hash function

* Remove sql_store_chart_hash function

* Remove store_active_dimension function

* dictionary delayed destruction

* formatting and cleanup

* zero dictionary base on rrdsetvar

* added internal error to log delayed destructions of dictionaries

* typo in rrddimvar

* added debugging info to dictionary

* debug info

* fix for rrdcalc keys being empty

* remove forgotten unlock

* remove deadlock

* Switch to metadata version 5 and drop
  chart_hash
  chart_hash_map
  chart_active
  dimension_active
  v_chart_hash

* SQL cosmetic changes

* do not busy wait while destroying a referenced dictionary

* remove deadlock

* code cleanup; re-organization;

* fast cleanup and flushing of dictionaries

* number formatting fixes

* do not delete configured alerts when archiving a chart

* rrddim obsolete linked list management outside dictionaries

* removed duplicate contexts call

* fix crash when rrdfamily is not initialized

* dont keep rrddimvar referenced

* properly cleanup rrdvar

* removed some locks

* Do not attempt to cleanup chart_hash / chart_hash_map

* rrdcalctemplate managed by dictionary

* register callbacks on the right dictionary

* removed some more locks

* rrdcalc secondary index replaced with linked-list; rrdcalc labels updates are now executed by health thread

* when looking up for an alarm look using both chart id and chart name

* host initialization a bit more modular

* init rrdlabels on host update

* preparation for dictionary views

* improved comment

* unused variables without internal checks

* service threads isolation and worker info

* more worker info in service thread

* thread cancelability debugging with internal checks

* strings data races addressed; fixes https://github.com/netdata/netdata/issues/13647

* dictionary modularization

* Remove unused SQL statement definition

* unit-tested thread safety of dictionaries; removed data race conditions on dictionaries and strings; dictionaries now can detect if the caller is holds a write lock and automatically all the calls become their unsafe versions; all direct calls to unsafe version is eliminated

* remove worker_is_idle() from the exit of service functions, because we lose the lock time between loops

* rewritten dictionary to have 2 separate locks, one for indexing and another for traversal

* Update collectors/cgroups.plugin/sys_fs_cgroup.c

Co-authored-by: Vladimir Kobal <vlad@prokk.net>

* Update collectors/cgroups.plugin/sys_fs_cgroup.c

Co-authored-by: Vladimir Kobal <vlad@prokk.net>

* Update collectors/proc.plugin/proc_net_dev.c

Co-authored-by: Vladimir Kobal <vlad@prokk.net>

* fix memory leak in rrdset cache_dir

* minor dictionary changes

* dont use index locks in single threaded

* obsolete dict option

* rrddim options and flags separation; rrdset_done() optimization to keep array of reference pointers to rrddim;

* fix jump on uninitialized value in dictionary; remove double free of cache_dir

* addressed codacy findings

* removed debugging code

* use the private refcount on dictionaries

* make dictionary item desctructors work on dictionary destruction; strictier control on dictionary API; proper cleanup sequence on rrddim;

* more dictionary statistics

* global statistics about dictionary operations, memory, items, callbacks

* dictionary support for views - missing the public API

* removed warning about unused parameter

* chart and context name for cloud

* chart and context name for cloud, again

* dictionary statistics fixed; first implementation of dictionary views - not currently used

* only the master can globally delete an item

* context needs netdata prefix

* fix context and chart it of spins

* fix for host variables when health is not enabled

* run garbage collector on item insert too

* Fix info message; remove extra "using"

* update dict unittest for new placement of garbage collector

* we need RRDHOST->rrdvars for maintaining custom host variables

* Health initialization needs the host->host_uuid

* split STRING to its own files; no code changes other than that

* initialize health unconditionally

* unit tests do not pollute the global scope with their variables

* Skip initialization when creating archived hosts on startup. When a child connects it will initialize properly

Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>
Co-authored-by: Vladimir Kobal <vlad@prokk.net>
2022-09-19 23:46:13 +03:00

263 lines
7.9 KiB
C

// SPDX-License-Identifier: GPL-3.0-or-later
#include "../libnetdata.h"
static size_t default_stacksize = 0, wanted_stacksize = 0;
static pthread_attr_t *attr = NULL;
// ----------------------------------------------------------------------------
// per thread data
typedef struct {
void *arg;
pthread_t *thread;
const char *tag;
void *(*start_routine) (void *);
NETDATA_THREAD_OPTIONS options;
} NETDATA_THREAD;
static __thread NETDATA_THREAD *netdata_thread = NULL;
inline int netdata_thread_tag_exists(void) {
return (netdata_thread && netdata_thread->tag && *netdata_thread->tag);
}
const char *netdata_thread_tag(void) {
return (netdata_thread_tag_exists() ? netdata_thread->tag : "MAIN");
}
// ----------------------------------------------------------------------------
// compatibility library functions
static __thread pid_t gettid_cached_tid = 0;
pid_t gettid(void) {
pid_t tid = 0;
if(likely(gettid_cached_tid > 0))
return gettid_cached_tid;
#ifdef __FreeBSD__
tid = (pid_t)pthread_getthreadid_np();
#elif defined(__APPLE__)
#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
uint64_t curthreadid;
pthread_threadid_np(NULL, &curthreadid);
tid = (pid_t)curthreadid;
#else /* __MAC_OS_X_VERSION_MIN_REQUIRED */
tid = (pid_t)pthread_self;
#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */
#else /* __APPLE__*/
tid = (pid_t)syscall(SYS_gettid);
#endif /* __FreeBSD__, __APPLE__*/
gettid_cached_tid = tid;
return tid;
}
// ----------------------------------------------------------------------------
// early initialization
size_t netdata_threads_init(void) {
int i;
// --------------------------------------------------------------------
// get the required stack size of the threads of netdata
attr = callocz(1, sizeof(pthread_attr_t));
i = pthread_attr_init(attr);
if(i != 0)
fatal("pthread_attr_init() failed with code %d.", i);
i = pthread_attr_getstacksize(attr, &default_stacksize);
if(i != 0)
fatal("pthread_attr_getstacksize() failed with code %d.", i);
else
debug(D_OPTIONS, "initial pthread stack size is %zu bytes", default_stacksize);
return default_stacksize;
}
// ----------------------------------------------------------------------------
// late initialization
void netdata_threads_init_after_fork(size_t stacksize) {
wanted_stacksize = stacksize;
int i;
// ------------------------------------------------------------------------
// set default pthread stack size
if(attr && default_stacksize < wanted_stacksize && wanted_stacksize > 0) {
i = pthread_attr_setstacksize(attr, wanted_stacksize);
if(i != 0)
fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i);
else
debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
}
}
// ----------------------------------------------------------------------------
// netdata_thread_create
extern void rrdset_thread_rda_free(void);
static void thread_cleanup(void *ptr) {
if(netdata_thread != ptr) {
NETDATA_THREAD *info = (NETDATA_THREAD *)ptr;
error("THREADS: internal error - thread local variable does not match the one passed to this function. Expected thread '%s', passed thread '%s'", netdata_thread->tag, info->tag);
}
if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
info("thread with task id %d finished", gettid());
rrdset_thread_rda_free();
thread_cache_destroy();
freez((void *)netdata_thread->tag);
netdata_thread->tag = NULL;
freez(netdata_thread);
netdata_thread = NULL;
}
static void thread_set_name_np(NETDATA_THREAD *nt) {
if (nt->tag) {
int ret = 0;
char threadname[NETDATA_THREAD_NAME_MAX+1];
strncpyz(threadname, nt->tag, NETDATA_THREAD_NAME_MAX);
#if defined(__FreeBSD__)
pthread_set_name_np(pthread_self(), threadname);
#elif defined(__APPLE__)
ret = pthread_setname_np(threadname);
#else
ret = pthread_setname_np(pthread_self(), threadname);
#endif
if (ret != 0)
error("cannot set pthread name of %d to %s. ErrCode: %d", gettid(), threadname, ret);
else
info("set name of thread %d to %s", gettid(), threadname);
}
}
void uv_thread_set_name_np(uv_thread_t ut, const char* name) {
int ret = 0;
char threadname[NETDATA_THREAD_NAME_MAX+1];
strncpyz(threadname, name, NETDATA_THREAD_NAME_MAX);
#if defined(__FreeBSD__)
pthread_set_name_np(ut, threadname);
#elif defined(__APPLE__)
// Apple can only set its own name
UNUSED(ut);
#else
ret = pthread_setname_np(ut, threadname);
#endif
if (ret)
info("cannot set libuv thread name to %s. Err: %d", threadname, ret);
}
void os_thread_get_current_name_np(char threadname[NETDATA_THREAD_NAME_MAX + 1])
{
threadname[0] = '\0';
#if defined(__FreeBSD__)
pthread_get_name_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
#elif defined(HAVE_PTHREAD_GETNAME_NP) /* Linux & macOS */
(void)pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
#endif
}
static void *thread_start(void *ptr) {
netdata_thread = (NETDATA_THREAD *)ptr;
if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_STARTUP))
info("thread created with task id %d", gettid());
if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
error("cannot set pthread cancel type to DEFERRED.");
if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
error("cannot set pthread cancel state to ENABLE.");
thread_set_name_np(ptr);
void *ret = NULL;
pthread_cleanup_push(thread_cleanup, ptr);
ret = netdata_thread->start_routine(netdata_thread->arg);
pthread_cleanup_pop(1);
return ret;
}
int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg) {
NETDATA_THREAD *info = mallocz(sizeof(NETDATA_THREAD));
info->arg = arg;
info->thread = thread;
info->tag = strdupz(tag);
info->start_routine = start_routine;
info->options = options;
int ret = pthread_create(thread, attr, thread_start, info);
if(ret != 0)
error("failed to create new thread for %s. pthread_create() failed with code %d", tag, ret);
else {
if (!(options & NETDATA_THREAD_OPTION_JOINABLE)) {
int ret2 = pthread_detach(*thread);
if (ret2 != 0)
error("cannot request detach of newly created %s thread. pthread_detach() failed with code %d", tag, ret2);
}
}
return ret;
}
// ----------------------------------------------------------------------------
// netdata_thread_cancel
#ifdef NETDATA_INTERNAL_CHECKS
int netdata_thread_cancel_with_trace(netdata_thread_t thread, int line, const char *file, const char *function) {
#else
int netdata_thread_cancel(netdata_thread_t thread) {
#endif
int ret = pthread_cancel(thread);
if(ret != 0)
#ifdef NETDATA_INTERNAL_CHECKS
error("cannot cancel thread. pthread_cancel() failed with code %d at %d@%s, function %s()", ret, line, file, function);
#else
error("cannot cancel thread. pthread_cancel() failed with code %d.", ret);
#endif
return ret;
}
// ----------------------------------------------------------------------------
// netdata_thread_join
int netdata_thread_join(netdata_thread_t thread, void **retval) {
int ret = pthread_join(thread, retval);
if(ret != 0)
error("cannot join thread. pthread_join() failed with code %d.", ret);
return ret;
}
int netdata_thread_detach(pthread_t thread) {
int ret = pthread_detach(thread);
if(ret != 0)
error("cannot detach thread. pthread_detach() failed with code %d.", ret);
return ret;
}