/* * libstatgrab * https://libstatgrab.org * Copyright (C) 2003-2004 Peter Saunders * Copyright (C) 2003-2019 Tim Bishop * Copyright (C) 2003-2013 Adam Sampson * Copyright (C) 2012-2019 Jens Rehsack * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef STATGRAB_GLOBALS_H #define STATGRAB_GLOBALS_H typedef sg_error (*comp_global_init_function)(unsigned id); typedef void (*comp_global_destroy_function)(void); typedef void (*comp_global_cleanup_function)(void *); struct sg_comp_status { sg_error init_error; }; #if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD) #define DECLARE_REQUIRED_COMP_LOCKS(comp,...) static const char * sg_##comp##_lock_names[] = { __VA_ARGS__ }; #define REQUIRED_COMP_LOCKS(comp) sg_##comp##_lock_names, #else #define DECLARE_REQUIRED_COMP_LOCKS(comp,...) #define REQUIRED_COMP_LOCKS(comp) #endif struct sg_comp_init { comp_global_init_function init_fn; comp_global_destroy_function destroy_fn; comp_global_cleanup_function cleanup_fn; size_t static_buf_size; #if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD) const char **required_locks; #endif struct sg_comp_status *status; }; void *sg_comp_get_tls(unsigned id); #define DEFAULT_INIT_COMP(comp,...) \ static sg_error sg_##comp##_init_comp(unsigned);\ static void sg_##comp##_destroy_comp(void); \ static void sg_##comp##_cleanup_comp(void *); \ \ static struct sg_comp_status sg_##comp##_status;\ DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ \ __sg_private \ const struct sg_comp_init sg_##comp##_init = { \ sg_##comp##_init_comp, \ sg_##comp##_destroy_comp, \ sg_##comp##_cleanup_comp, \ sizeof(struct sg_##comp##_glob), \ REQUIRED_COMP_LOCKS(comp) \ &sg_##comp##_status \ }; \ static unsigned int sg_##comp##_glob_id #define GLOBAL_GET_TLS(comp) (struct sg_##comp##_glob *)(sg_comp_get_tls(sg_##comp##_glob_id)) #define GLOBAL_SET_ID(comp,id) sg_##comp##_glob_id = (id) #define EASY_COMP_INIT_FN(comp) \ static sg_error sg_##comp##_init_comp(unsigned id){ \ GLOBAL_SET_ID(comp,id); \ return SG_ERROR_NONE; \ } #define EASY_COMP_DESTROY_FN(comp) \ static void sg_##comp##_destroy_comp(void){} #define EASY_COMP_CLEANUP_FN(comp,nvect) \ static void sg_##comp##_cleanup_comp(void *p){ \ struct sg_##comp##_glob *comp##_glob = p; \ unsigned i; \ TRACE_LOG_FMT(#comp, "sg_" #comp "_cleanup_comp(%p)", p); \ assert(comp##_glob); \ for( i = 0; i < nvect; ++i ) \ sg_vector_free(comp##_glob->comp##_vectors[i]); \ memset(comp##_glob->comp##_vectors, 0, sizeof(comp##_glob->comp##_vectors) ); \ } #define EASY_COMP_SETUP(comp,nvect,...) \ struct sg_##comp##_glob { \ sg_vector *comp##_vectors[nvect]; \ }; \ \ static unsigned int sg_##comp##_glob_id; \ \ EASY_COMP_INIT_FN(comp) \ EASY_COMP_DESTROY_FN(comp) \ EASY_COMP_CLEANUP_FN(comp,nvect) \ \ static struct sg_comp_status sg_##comp##_status;\ DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ \ __sg_private \ const struct sg_comp_init sg_##comp##_init = { \ sg_##comp##_init_comp, \ sg_##comp##_destroy_comp, \ sg_##comp##_cleanup_comp, \ sizeof(struct sg_##comp##_glob), \ REQUIRED_COMP_LOCKS(comp) \ &sg_##comp##_status \ } #define EXTENDED_COMP_SETUP(comp,nvect,...) \ static sg_error sg_##comp##_init_comp(unsigned);\ static void sg_##comp##_destroy_comp(void); \ static void sg_##comp##_cleanup_comp(void *); \ \ struct sg_##comp##_glob { \ sg_vector *comp##_vectors[nvect]; \ }; \ \ static unsigned int sg_##comp##_glob_id; \ DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ \ static struct sg_comp_status sg_##comp##_status;\ __sg_private \ const struct sg_comp_init sg_##comp##_init = { \ sg_##comp##_init_comp, \ sg_##comp##_destroy_comp, \ sg_##comp##_cleanup_comp, \ sizeof(struct sg_##comp##_glob), \ REQUIRED_COMP_LOCKS(comp) \ &sg_##comp##_status \ } #define EASY_COMP_ACCESS(fn,comp,name,idx) \ sg_##name##_stats *fn(size_t *entries) { \ \ struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ sg_error rc; \ TRACE_LOG(#comp, "entering " #fn); \ if( !comp##_glob ) { \ /* assuming error comp can't neither */ \ ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ if(entries) \ *entries = 0; \ return NULL; \ } \ \ if(!comp##_glob->comp##_vectors[idx]) \ comp##_glob->comp##_vectors[idx] = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ \ if(comp##_glob->comp##_vectors[idx]){ \ sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[idx]); \ TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", name##_stats); \ rc = fn##_int(name##_stats); \ if(SG_ERROR_NONE == rc){ \ TRACE_LOG(#comp, #fn " succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[idx]); \ return name##_stats; \ } \ } \ else { \ rc = sg_get_error(); \ } \ \ WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(rc)); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } \ \ sg_##name##_stats *fn##_r(size_t *entries) { \ \ sg_vector *name##_stats_vector = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ sg_error rc; \ TRACE_LOG(#comp, "entering " #fn "_r"); \ if(name##_stats_vector) { \ sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(name##_stats_vector); \ TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", name##_stats); \ rc = fn##_int(name##_stats); \ if(SG_ERROR_NONE == rc){ \ TRACE_LOG(#comp, #fn "_r succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(name##_stats_vector); \ return name##_stats; \ } \ sg_vector_free(name##_stats_vector); \ } \ else { \ rc = sg_get_error(); \ } \ \ WARN_LOG_FMT(#comp, #fn "_r failed with %s", sg_str_error(rc)); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } #define MULTI_COMP_ACCESS(fn,comp,name,idx) \ sg_##name##_stats *fn(size_t *entries) { \ \ struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ sg_error rc; \ TRACE_LOG(#comp, "entering " #fn); \ if( !comp##_glob ) { \ /* assuming error comp can't neither */ \ ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ if(entries) \ *entries = 0; \ return NULL; \ } \ \ if(!comp##_glob->comp##_vectors[idx]) \ comp##_glob->comp##_vectors[idx] = VECTOR_CREATE(sg_##name##_stats, 16); \ else \ VECTOR_CLEAR(comp##_glob->comp##_vectors[idx]); \ \ if(comp##_glob->comp##_vectors[idx]){ \ TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", &comp##_glob->comp##_vectors[idx]); \ rc = fn##_int(&comp##_glob->comp##_vectors[idx]); \ if(SG_ERROR_NONE == rc) { \ sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[idx]); \ TRACE_LOG(#comp, #fn " succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[idx]); \ return name##_stats; \ } \ } \ else { \ rc = sg_get_error(); \ } \ \ WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(rc)); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } \ \ sg_##name##_stats *fn##_r(size_t *entries) { \ sg_vector *name##_vector = VECTOR_CREATE(sg_##name##_stats, 16); \ sg_error rc; \ TRACE_LOG(#comp, "entering " #fn); \ if(name##_vector) { \ TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", &name##_vector); \ rc = fn##_int(&name##_vector); \ if( SG_ERROR_NONE == rc ) { \ sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(name##_vector); \ TRACE_LOG(#comp, #fn " succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(name##_vector); \ return name##_stats; \ } \ sg_vector_free(name##_vector); \ } \ else { \ rc = sg_get_error(); \ } \ \ WARN_LOG_FMT(#comp, #fn "_r failed with %s", sg_str_error(rc)); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } #define EASY_COMP_DIFF(fn,getfn,comp,name,diffidx,nowidx) \ sg_##name##_stats *fn(size_t *entries) { \ \ struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ TRACE_LOG(#comp, "entering " #fn); \ if( !comp##_glob ) { \ /* assuming error comp can't neither */ \ ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ if(entries) \ *entries = 0; \ return NULL; \ } \ \ if(!comp##_glob->comp##_vectors[nowidx]) { \ TRACE_LOG_FMT(#comp, #fn " has nothing to compare with - calling %s", #getfn); \ return getfn(entries); \ } \ \ if(!comp##_glob->comp##_vectors[diffidx]) \ comp##_glob->comp##_vectors[diffidx] = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ \ if(comp##_glob->comp##_vectors[diffidx]) { \ sg_##name##_stats name##_last = *((sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[nowidx])); \ sg_##name##_stats *name##_diff = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[diffidx]); \ sg_##name##_stats *name##_now = getfn(NULL); \ \ TRACE_LOG_FMT(#comp, "calling " #fn "_diff(%p, %p, %p)", name##_diff, name##_now, &name##_last); \ if( (NULL != name##_now) && ( SG_ERROR_NONE == fn##_int(name##_diff, name##_now, &name##_last) ) ) { \ TRACE_LOG(#comp, #fn " succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[diffidx]); \ return name##_diff; \ } \ } \ \ WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(sg_get_error())); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } \ \ sg_##name##_stats *fn##_between(const sg_##name##_stats *name##_now, const sg_##name##_stats *name##_last, size_t *entries) { \ \ sg_vector *name##_diff_vector; \ \ TRACE_LOG(#comp, "entering " #fn "_between"); \ name##_diff_vector = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ if(name##_diff_vector){ \ sg_error rc; \ sg_##name##_stats *name##_diff = (sg_##name##_stats *)VECTOR_DATA(name##_diff_vector); \ TRACE_LOG_FMT(#comp, "calling " #fn "_diff(%p, %p, %p)", name##_diff, name##_now, &name##_last); \ rc = fn##_int(name##_diff, name##_now, name##_last); \ if( SG_ERROR_NONE == rc ) { \ TRACE_LOG(#comp, #fn "_between succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(name##_diff_vector); \ return name##_diff; \ } \ sg_vector_free(name##_diff_vector); \ } \ \ WARN_LOG_FMT(#comp, #fn "_between failed with %s", sg_str_error(sg_get_error())); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } #define MULTI_COMP_DIFF(fn,getfn,comp,name,diffidx,nowidx) \ sg_##name##_stats *fn(size_t *entries){ \ \ struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ TRACE_LOG(#comp, "entering " #fn); \ if( !comp##_glob ) { \ /* assuming error comp can't neither */ \ ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ if(entries) \ *entries = 0; \ return NULL; \ } \ \ if(!comp##_glob->comp##_vectors[nowidx]){ \ TRACE_LOG_FMT(#comp, #fn " has nothing to compare with - calling %s", #getfn); \ return getfn(entries); \ } \ \ if(!comp##_glob->comp##_vectors[diffidx]) \ comp##_glob->comp##_vectors[diffidx] = VECTOR_CREATE(sg_##name##_stats, comp##_glob->comp##_vectors[nowidx]->used_count); \ \ if( comp##_glob->comp##_vectors[diffidx] ) { \ sg_error rc; \ sg_vector *last = sg_vector_clone(comp##_glob->comp##_vectors[nowidx]); \ \ if(!last) \ goto err_out; \ \ TRACE_LOG(#comp, "calling " #getfn "(NULL)"); \ getfn(NULL); \ \ rc = sg_vector_compute_diff(&comp##_glob->comp##_vectors[diffidx], comp##_glob->comp##_vectors[nowidx], last); \ sg_vector_free( last ); \ \ if( SG_ERROR_NONE == rc ) { \ TRACE_LOG(#comp, #fn " succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[diffidx]); \ return VECTOR_DATA(comp##_glob->comp##_vectors[diffidx]); \ } \ } \ \ err_out: \ if(entries) \ *entries = 0; \ \ WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(sg_get_error())); \ \ return NULL; \ } \ \ sg_##name##_stats * \ fn##_between(const sg_##name##_stats *cur, \ const sg_##name##_stats *last, \ size_t *entries) { \ \ sg_vector *name##_diff_vector; \ sg_error rc; \ \ TRACE_LOG(#comp, "entering " #fn "_between"); \ name##_diff_vector = VECTOR_CREATE(sg_##name##_stats, 1); \ if(name##_diff_vector){ \ rc = sg_vector_compute_diff(&name##_diff_vector, VECTOR_ADDRESS_CONST(cur), VECTOR_ADDRESS_CONST(last)); \ \ if( SG_ERROR_NONE == rc ) { \ TRACE_LOG(#comp, #fn "_between succeded"); \ sg_clear_error(); \ if(entries) \ *entries = VECTOR_ITEM_COUNT(name##_diff_vector); \ return VECTOR_DATA(name##_diff_vector); \ } \ \ sg_vector_free(name##_diff_vector); \ } \ else { \ rc = sg_get_error(); \ } \ \ WARN_LOG_FMT(#comp, #fn "_between failed with %s", sg_str_error(rc)); \ \ if(entries) \ *entries = 0; \ \ return NULL; \ } __sg_private sg_error sg_comp_init(int ignore_init_errors); __sg_private sg_error sg_comp_destroy(void); __sg_private sg_error sg_global_lock(void); __sg_private sg_error sg_global_unlock(void); #endif /* STATGRAB_GLOBALS_H */