summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2022-12-05 16:29:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2022-12-05 16:31:29 +0000
commit2d852004321781e79bb7f59bf61603d66000daae (patch)
tree0ecddb3a16d1eb813fd4a3f7f507417028d6a5bc /libnetdata
parentReleasing debian version 1.37.0-1. (diff)
downloadnetdata-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.c42
-rw-r--r--libnetdata/procfile/procfile.c67
-rw-r--r--libnetdata/procfile/procfile.h15
-rw-r--r--libnetdata/socket/security.c38
-rw-r--r--libnetdata/string/string.c9
-rw-r--r--libnetdata/worker_utilization/worker_utilization.c94
-rw-r--r--libnetdata/worker_utilization/worker_utilization.h4
7 files changed, 153 insertions, 116 deletions
diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c
index f03da25ab..0277e067f 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 b4ca025ec..eb04316c3 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 5d45e4028..cae4ad484 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 f7b44049b..88b3f6d93 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 a3f74b4ef..d2db8aab4 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 14b8926e0..afaff209b 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 04d24f1f7..f1412e6b4 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