diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-12-05 16:29:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2022-12-05 16:31:29 +0000 |
commit | 2d852004321781e79bb7f59bf61603d66000daae (patch) | |
tree | 0ecddb3a16d1eb813fd4a3f7f507417028d6a5bc /libnetdata | |
parent | Releasing debian version 1.37.0-1. (diff) | |
download | netdata-2d852004321781e79bb7f59bf61603d66000daae.tar.xz netdata-2d852004321781e79bb7f59bf61603d66000daae.zip |
Merging upstream version 1.37.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libnetdata')
-rw-r--r-- | libnetdata/dictionary/dictionary.c | 42 | ||||
-rw-r--r-- | libnetdata/procfile/procfile.c | 67 | ||||
-rw-r--r-- | libnetdata/procfile/procfile.h | 15 | ||||
-rw-r--r-- | libnetdata/socket/security.c | 38 | ||||
-rw-r--r-- | libnetdata/string/string.c | 9 | ||||
-rw-r--r-- | libnetdata/worker_utilization/worker_utilization.c | 94 | ||||
-rw-r--r-- | libnetdata/worker_utilization/worker_utilization.h | 4 |
7 files changed, 153 insertions, 116 deletions
diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c index f03da25a..0277e067 100644 --- a/libnetdata/dictionary/dictionary.c +++ b/libnetdata/dictionary/dictionary.c @@ -3,10 +3,9 @@ #define DICTIONARY_INTERNALS #include "../libnetdata.h" -#include <Judy.h> // runtime flags of the dictionary - must be checked with atomics -typedef enum { +typedef enum __attribute__ ((__packed__)) { DICT_FLAG_NONE = 0, DICT_FLAG_DESTROYED = (1 << 0), // this dictionary has been destroyed } DICT_FLAGS; @@ -23,14 +22,14 @@ typedef enum { #define is_view_dictionary(dict) ((dict)->master) #define is_master_dictionary(dict) (!is_view_dictionary(dict)) -typedef enum item_options { +typedef enum __attribute__ ((__packed__)) item_options { ITEM_OPTION_NONE = 0, ITEM_OPTION_ALLOCATED_NAME = (1 << 0), // the name pointer is a STRING // IMPORTANT: This is 1-bit - to add more change ITEM_OPTIONS_BITS } ITEM_OPTIONS; -typedef enum item_flags { +typedef enum __attribute__ ((__packed__)) item_flags { ITEM_FLAG_NONE = 0, ITEM_FLAG_DELETED = (1 << 0), // this item is marked deleted, so it is not available for traversal (deleted from the index too) ITEM_FLAG_BEING_CREATED = (1 << 1), // this item is currently being created - this flag is removed when construction finishes @@ -623,7 +622,7 @@ static void dictionary_execute_delete_callback(DICTIONARY *dict, DICTIONARY_ITEM if(likely(!dict->hooks || !dict->hooks->del_callback)) return; - // We may execute the delete callback on items deleted from a view, + // We may execute delete callback on items deleted from a view, // because we may have references to it, after the master is gone // so, the shared structure will remain until the last reference is released. @@ -782,7 +781,7 @@ static void garbage_collect_pending_deletes(DICTIONARY *dict) { while(item) { examined++; - // this will cleanup + // this will clean up item_next = item->next; int rc = item_check_and_acquire_advanced(dict, item, is_view); @@ -882,7 +881,7 @@ static void item_acquire(DICTIONARY *dict, DICTIONARY_ITEM *item) { static void item_release(DICTIONARY *dict, DICTIONARY_ITEM *item) { // this function may be called without any lock on the dictionary - // or even when someone else has write lock on the dictionary + // or even when someone else has 'write' lock on the dictionary bool is_deleted; REFCOUNT refcount; @@ -934,11 +933,11 @@ static int item_check_and_acquire_advanced(DICTIONARY *dict, DICTIONARY_ITEM *it int ret = RC_ITEM_OK; + refcount = DICTIONARY_ITEM_REFCOUNT_GET(dict, item); + do { spins++; - refcount = DICTIONARY_ITEM_REFCOUNT_GET(dict, item); - if(refcount < 0) { // we can't use this item ret = RC_ITEM_IS_CURRENTLY_BEING_DELETED; @@ -953,8 +952,7 @@ static int item_check_and_acquire_advanced(DICTIONARY *dict, DICTIONARY_ITEM *it desired = refcount + 1; - } while(!__atomic_compare_exchange_n(&item->refcount, &refcount, desired, - false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + } while(!__atomic_compare_exchange_n(&item->refcount, &refcount, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); // if ret == ITEM_OK, we acquired the item @@ -971,7 +969,7 @@ static int item_check_and_acquire_advanced(DICTIONARY *dict, DICTIONARY_ITEM *it else pointer_del(dict, item); - // mark it in our dictionary as deleted too + // mark it in our dictionary as deleted too, // this is safe to be done here, because we have got // a reference counter on item dict_item_set_deleted(dict, item); @@ -1013,11 +1011,11 @@ static inline int item_is_not_referenced_and_can_be_removed_advanced(DICTIONARY int ret = RC_ITEM_OK; + refcount = DICTIONARY_ITEM_REFCOUNT_GET(dict, item); + do { spins++; - refcount = DICTIONARY_ITEM_REFCOUNT_GET(dict, item); - if(refcount < 0) { // we can't use this item ret = RC_ITEM_IS_CURRENTLY_BEING_DELETED; @@ -1035,8 +1033,7 @@ static inline int item_is_not_referenced_and_can_be_removed_advanced(DICTIONARY ret = RC_ITEM_IS_CURRENTLY_BEING_CREATED; break; } - } while(!__atomic_compare_exchange_n(&item->refcount, &refcount, desired, - false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + } while(!__atomic_compare_exchange_n(&item->refcount, &refcount, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); #ifdef NETDATA_INTERNAL_CHECKS if(ret == RC_ITEM_OK) @@ -1055,8 +1052,7 @@ static inline bool item_shared_release_and_check_if_it_can_be_freed(DICTIONARY * // if we can set refcount to REFCOUNT_DELETING, we can delete this item REFCOUNT links = __atomic_sub_fetch(&item->shared->links, 1, __ATOMIC_SEQ_CST); - if(links == 0 && __atomic_compare_exchange_n(&item->shared->links, &links, REFCOUNT_DELETING, - false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { + if(links == 0 && __atomic_compare_exchange_n(&item->shared->links, &links, REFCOUNT_DELETING, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { // we can delete it return true; @@ -1430,16 +1426,16 @@ static void dict_item_shared_set_deleted(DICTIONARY *dict, DICTIONARY_ITEM *item static bool dict_item_set_deleted(DICTIONARY *dict, DICTIONARY_ITEM *item) { ITEM_FLAGS expected, desired; + expected = __atomic_load_n(&item->flags, __ATOMIC_SEQ_CST); + do { - expected = __atomic_load_n(&item->flags, __ATOMIC_SEQ_CST); if (expected & ITEM_FLAG_DELETED) return false; desired = expected | ITEM_FLAG_DELETED; - } while(!__atomic_compare_exchange_n(&item->flags, &expected, desired, - false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + } while(!__atomic_compare_exchange_n(&item->flags, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); DICTIONARY_ENTRIES_MINUS1(dict); return true; @@ -1474,7 +1470,7 @@ static inline void dict_item_free_or_mark_deleted(DICTIONARY *dict, DICTIONARY_I } // this is used by traversal functions to remove the current item -// if it is deleted and it has zero references. This will eliminate +// if it is deleted, and it has zero references. This will eliminate // the need for the garbage collector to kick-in later. // Most deletions happen during traversal, so this is a nice hack // to speed up everything! @@ -1601,7 +1597,7 @@ static DICTIONARY_ITEM *dict_item_add_or_reset_value_and_acquire(DICTIONARY *dic hashtable_inserted_item_unsafe(dict, item); // unlock the index lock, before we add it to the linked list - // DONT DO IT THE OTHER WAY AROUND - DO NOT CROSS THE LOCKS! + // DON'T DO IT THE OTHER WAY AROUND - DO NOT CROSS THE LOCKS! dictionary_index_wrlock_unlock(dict); item_linked_list_add(dict, item); diff --git a/libnetdata/procfile/procfile.c b/libnetdata/procfile/procfile.c index b4ca025e..eb04316c 100644 --- a/libnetdata/procfile/procfile.c +++ b/libnetdata/procfile/procfile.c @@ -22,16 +22,21 @@ size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER; // ---------------------------------------------------------------------------- char *procfile_filename(procfile *ff) { - if(ff->filename[0]) return ff->filename; + if(ff->filename) + return ff->filename; + char filename[FILENAME_MAX + 1]; char buffer[FILENAME_MAX + 1]; snprintfz(buffer, FILENAME_MAX, "/proc/self/fd/%d", ff->fd); - ssize_t l = readlink(buffer, ff->filename, FILENAME_MAX); + ssize_t l = readlink(buffer, filename, FILENAME_MAX); if(unlikely(l == -1)) - snprintfz(ff->filename, FILENAME_MAX, "unknown filename for fd %d", ff->fd); + snprintfz(filename, FILENAME_MAX, "unknown filename for fd %d", ff->fd); else - ff->filename[l] = '\0'; + filename[l] = '\0'; + + + ff->filename = strdupz(filename); // on non-linux systems, something like this will be needed // fcntl(ff->fd, F_GETPATH, ff->filename) @@ -141,8 +146,9 @@ void procfile_close(procfile *ff) { debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", procfile_filename(ff)); - if(likely(ff->lines)) procfile_lines_free(ff->lines); - if(likely(ff->words)) procfile_words_free(ff->words); + freez(ff->filename); + procfile_lines_free(ff->lines); + procfile_words_free(ff->words); if(likely(ff->fd != -1)) close(ff->fd); freez(ff); @@ -319,40 +325,31 @@ procfile *procfile_readall(procfile *ff) { return ff; } -NOINLINE -static void procfile_set_separators(procfile *ff, const char *separators) { - static PF_CHAR_TYPE def[256]; - static char initialized = 0; - - if(unlikely(!initialized)) { - // this is thread safe - // if initialized is zero, multiple threads may be executing - // this code at the same time, setting in def[] the exact same values - int i = 256; - while(i--) { - if(unlikely(i == '\n' || i == '\r')) - def[i] = PF_CHAR_IS_NEWLINE; +static PF_CHAR_TYPE procfile_default_separators[256]; +__attribute__((constructor)) void procfile_initialize_default_separators(void) { + int i = 256; + while(i--) { + if(unlikely(i == '\n' || i == '\r')) + procfile_default_separators[i] = PF_CHAR_IS_NEWLINE; - else if(unlikely(isspace(i) || !isprint(i))) - def[i] = PF_CHAR_IS_SEPARATOR; + else if(unlikely(isspace(i) || !isprint(i))) + procfile_default_separators[i] = PF_CHAR_IS_SEPARATOR; - else - def[i] = PF_CHAR_IS_WORD; - } - - initialized = 1; + else + procfile_default_separators[i] = PF_CHAR_IS_WORD; } +} - // copy the default - PF_CHAR_TYPE *ffs = ff->separators, *ffd = def, *ffe = &def[256]; - while(ffd != ffe) - *ffs++ = *ffd++; - +NOINLINE +static void procfile_set_separators(procfile *ff, const char *separators) { // set the separators if(unlikely(!separators)) separators = " \t=|"; - ffs = ff->separators; + // copy the default + memcpy(ff->separators, procfile_default_separators, 256 * sizeof(PF_CHAR_TYPE)); + + PF_CHAR_TYPE *ffs = ff->separators; const char *s = separators; while(*s) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR; @@ -416,8 +413,7 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f procfile *ff = mallocz(sizeof(procfile) + size); //strncpyz(ff->filename, filename, FILENAME_MAX); - ff->filename[0] = '\0'; - + ff->filename = NULL; ff->fd = fd; ff->size = size; ff->len = 0; @@ -449,7 +445,8 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa // info("PROCFILE: opened '%s' on fd %d", filename, ff->fd); //strncpyz(ff->filename, filename, FILENAME_MAX); - ff->filename[0] = '\0'; + freez(ff->filename); + ff->filename = NULL; ff->flags = flags; // do not do the separators again if NULL is given diff --git a/libnetdata/procfile/procfile.h b/libnetdata/procfile/procfile.h index 5d45e402..cae4ad48 100644 --- a/libnetdata/procfile/procfile.h +++ b/libnetdata/procfile/procfile.h @@ -37,7 +37,7 @@ typedef struct { #define PROCFILE_FLAG_DEFAULT 0x00000000 #define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001 -typedef enum procfile_separator { +typedef enum __attribute__ ((__packed__)) procfile_separator { PF_CHAR_IS_SEPARATOR, PF_CHAR_IS_NEWLINE, PF_CHAR_IS_WORD, @@ -46,17 +46,16 @@ typedef enum procfile_separator { PF_CHAR_IS_CLOSE } PF_CHAR_TYPE; -typedef struct { - char filename[FILENAME_MAX + 1]; // not populated until profile_filename() is called - +typedef struct procfile { + char *filename; // not populated until procfile_filename() is called uint32_t flags; - int fd; // the file descriptor - size_t len; // the bytes we have placed into data - size_t size; // the bytes we have allocated for data + int fd; // the file descriptor + size_t len; // the bytes we have placed into data + size_t size; // the bytes we have allocated for data pflines *lines; pfwords *words; PF_CHAR_TYPE separators[256]; - char data[]; // allocated buffer to keep file contents + char data[]; // allocated buffer to keep file contents } procfile; // close the proc file and free all related memory diff --git a/libnetdata/socket/security.c b/libnetdata/socket/security.c index f7b44049..88b3f6d9 100644 --- a/libnetdata/socket/security.c +++ b/libnetdata/socket/security.c @@ -204,31 +204,43 @@ static SSL_CTX * security_initialize_openssl_server() { * NETDATA_SSL_CONTEXT_EXPORTING - Starts the OpenTSDB context */ void security_start_ssl(int selector) { + static SPINLOCK sp = NETDATA_SPINLOCK_INITIALIZER; + netdata_spinlock_lock(&sp); + switch (selector) { case NETDATA_SSL_CONTEXT_SERVER: { - struct stat statbuf; - if (stat(netdata_ssl_security_key, &statbuf) || stat(netdata_ssl_security_cert, &statbuf)) { - info("To use encryption it is necessary to set \"ssl certificate\" and \"ssl key\" in [web] !\n"); - return; + if(!netdata_ssl_srv_ctx) { + struct stat statbuf; + if (stat(netdata_ssl_security_key, &statbuf) || stat(netdata_ssl_security_cert, &statbuf)) + info("To use encryption it is necessary to set \"ssl certificate\" and \"ssl key\" in [web] !\n"); + else { + netdata_ssl_srv_ctx = security_initialize_openssl_server(); + SSL_CTX_set_mode(netdata_ssl_srv_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); + } } - - netdata_ssl_srv_ctx = security_initialize_openssl_server(); - SSL_CTX_set_mode(netdata_ssl_srv_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); break; } + case NETDATA_SSL_CONTEXT_STREAMING: { - netdata_ssl_client_ctx = security_initialize_openssl_client(); - //This is necessary for the stream, because it is working sometimes with nonblock socket. - //It returns the bitmask after to change, there is not any description of errors in the documentation - SSL_CTX_set_mode( - netdata_ssl_client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |SSL_MODE_AUTO_RETRY); + if(!netdata_ssl_client_ctx) { + netdata_ssl_client_ctx = security_initialize_openssl_client(); + //This is necessary for the stream, because it is working sometimes with nonblock socket. + //It returns the bitmask after to change, there is not any description of errors in the documentation + SSL_CTX_set_mode(netdata_ssl_client_ctx, + SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | + SSL_MODE_AUTO_RETRY); + } break; } + case NETDATA_SSL_CONTEXT_EXPORTING: { - netdata_ssl_exporting_ctx = security_initialize_openssl_client(); + if(!netdata_ssl_exporting_ctx) + netdata_ssl_exporting_ctx = security_initialize_openssl_client(); break; } } + + netdata_spinlock_unlock(&sp); } /** diff --git a/libnetdata/string/string.c b/libnetdata/string/string.c index a3f74b4e..d2db8aab 100644 --- a/libnetdata/string/string.c +++ b/libnetdata/string/string.c @@ -71,11 +71,12 @@ void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_ static inline bool string_entry_check_and_acquire(STRING *se) { REFCOUNT expected, desired, count = 0; + + expected = __atomic_load_n(&se->refcount, __ATOMIC_SEQ_CST); + do { count++; - expected = __atomic_load_n(&se->refcount, __ATOMIC_SEQ_CST); - if(expected <= 0) { // We cannot use this. // The reference counter reached value zero, @@ -85,8 +86,8 @@ static inline bool string_entry_check_and_acquire(STRING *se) { } desired = expected + 1; - } - while(!__atomic_compare_exchange_n(&se->refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); + + } while(!__atomic_compare_exchange_n(&se->refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); string_internal_stats_add(spins, count - 1); diff --git a/libnetdata/worker_utilization/worker_utilization.c b/libnetdata/worker_utilization/worker_utilization.c index 14b8926e..afaff209 100644 --- a/libnetdata/worker_utilization/worker_utilization.c +++ b/libnetdata/worker_utilization/worker_utilization.c @@ -44,35 +44,55 @@ struct worker { struct worker *prev; }; -static netdata_mutex_t workers_base_lock = NETDATA_MUTEX_INITIALIZER; -static __thread struct worker *worker = NULL; -static Pvoid_t workers_per_workname_JudyHS_array = NULL; +struct workers_workname { // this is what we add to JudyHS + SPINLOCK spinlock; + struct worker *base; +}; + +static struct workers_globals { + SPINLOCK spinlock; + Pvoid_t worknames_JudyHS; + +} workers_globals = { // workers globals, the base of all worknames + .spinlock = NETDATA_SPINLOCK_INITIALIZER, // a lock for the worknames index + .worknames_JudyHS = NULL, // the worknames index +}; -void worker_register(const char *workname) { +static __thread struct worker *worker = NULL; // the current thread worker + +void worker_register(const char *name) { if(unlikely(worker)) return; worker = callocz(1, sizeof(struct worker)); worker->pid = gettid(); worker->tag = strdupz(netdata_thread_tag()); - worker->workname = strdupz(workname); + worker->workname = strdupz(name); usec_t now = now_monotonic_usec(); worker->statistics_last_checkpoint = now; worker->last_action_timestamp = now; worker->last_action = WORKER_IDLE; - size_t workname_size = strlen(workname) + 1; - netdata_mutex_lock(&workers_base_lock); + size_t name_size = strlen(name) + 1; + netdata_spinlock_lock(&workers_globals.spinlock); - Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)workname, workname_size); + Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)name, name_size); if(!PValue) - PValue = JudyHSIns(&workers_per_workname_JudyHS_array, (void *)workname, workname_size, PJE0); + PValue = JudyHSIns(&workers_globals.worknames_JudyHS, (void *)name, name_size, PJE0); + + struct workers_workname *workname = *PValue; + if(!workname) { + workname = mallocz(sizeof(struct workers_workname)); + workname->spinlock = NETDATA_SPINLOCK_INITIALIZER; + workname->base = NULL; + *PValue = workname; + } - struct worker *base = *PValue; - DOUBLE_LINKED_LIST_APPEND_UNSAFE(base, worker, prev, next); - *PValue = base; + netdata_spinlock_lock(&workname->spinlock); + DOUBLE_LINKED_LIST_APPEND_UNSAFE(workname->base, worker, prev, next); + netdata_spinlock_unlock(&workname->spinlock); - netdata_mutex_unlock(&workers_base_lock); + netdata_spinlock_unlock(&workers_globals.spinlock); } void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type) { @@ -105,17 +125,20 @@ void worker_unregister(void) { if(unlikely(!worker)) return; size_t workname_size = strlen(worker->workname) + 1; - netdata_mutex_lock(&workers_base_lock); - Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)worker->workname, workname_size); + netdata_spinlock_lock(&workers_globals.spinlock); + Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)worker->workname, workname_size); if(PValue) { - struct worker *base = *PValue; - DOUBLE_LINKED_LIST_REMOVE_UNSAFE(base, worker, prev, next); - *PValue = base; - - if(!base) - JudyHSDel(&workers_per_workname_JudyHS_array, (void *)worker->workname, workname_size, PJE0); + struct workers_workname *workname = *PValue; + netdata_spinlock_lock(&workname->spinlock); + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(workname->base, worker, prev, next); + netdata_spinlock_unlock(&workname->spinlock); + + if(!workname->base) { + JudyHSDel(&workers_globals.worknames_JudyHS, (void *) worker->workname, workname_size, PJE0); + freez(workname); + } } - netdata_mutex_unlock(&workers_base_lock); + netdata_spinlock_unlock(&workers_globals.spinlock); for(int i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) { string_freez(worker->per_job_type[i].name); @@ -187,7 +210,7 @@ void worker_set_metric(size_t job_id, NETDATA_DOUBLE value) { // statistics interface -void workers_foreach(const char *workname, void (*callback)( +void workers_foreach(const char *name, void (*callback)( void *data , pid_t pid , const char *thread_tag @@ -203,18 +226,27 @@ void workers_foreach(const char *workname, void (*callback)( , NETDATA_DOUBLE *job_custom_values ) , void *data) { - netdata_mutex_lock(&workers_base_lock); + netdata_spinlock_lock(&workers_globals.spinlock); usec_t busy_time, delta; size_t i, jobs_started, jobs_running; - size_t workname_size = strlen(workname) + 1; - struct worker *base = NULL; - Pvoid_t *PValue = JudyHSGet(workers_per_workname_JudyHS_array, (void *)workname, workname_size); - if(PValue) - base = *PValue; + size_t workname_size = strlen(name) + 1; + struct workers_workname *workname; + Pvoid_t *PValue = JudyHSGet(workers_globals.worknames_JudyHS, (void *)name, workname_size); + if(PValue) { + workname = *PValue; + netdata_spinlock_lock(&workname->spinlock); + } + else + workname = NULL; + + netdata_spinlock_unlock(&workers_globals.spinlock); + + if(!workname) + return; struct worker *p; - DOUBLE_LINKED_LIST_FOREACH_FORWARD(base, p, prev, next) { + DOUBLE_LINKED_LIST_FOREACH_FORWARD(workname->base, p, prev, next) { usec_t now = now_monotonic_usec(); // find per job type statistics @@ -326,5 +358,5 @@ void workers_foreach(const char *workname, void (*callback)( ); } - netdata_mutex_unlock(&workers_base_lock); + netdata_spinlock_unlock(&workname->spinlock); } diff --git a/libnetdata/worker_utilization/worker_utilization.h b/libnetdata/worker_utilization/worker_utilization.h index 04d24f1f..f1412e6b 100644 --- a/libnetdata/worker_utilization/worker_utilization.h +++ b/libnetdata/worker_utilization/worker_utilization.h @@ -15,7 +15,7 @@ typedef enum { WORKER_METRIC_INCREMENTAL_TOTAL = 4, } WORKER_METRIC_TYPE; -void worker_register(const char *workname); +void worker_register(const char *name); void worker_register_job_name(size_t job_id, const char *name); void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type); void worker_unregister(void); @@ -26,7 +26,7 @@ void worker_set_metric(size_t job_id, NETDATA_DOUBLE value); // statistics interface -void workers_foreach(const char *workname, void (*callback)( +void workers_foreach(const char *name, void (*callback)( void *data , pid_t pid , const char *thread_tag |