1 /* 2 * libstatgrab 3 * https://libstatgrab.org 4 * Copyright (C) 2003-2004 Peter Saunders 5 * Copyright (C) 2003-2019 Tim Bishop 6 * Copyright (C) 2003-2013 Adam Sampson 7 * Copyright (C) 2012-2019 Jens Rehsack 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 * 02110-1301, USA. 23 */ 24 25 #ifndef STATGRAB_GLOBALS_H 26 #define STATGRAB_GLOBALS_H 27 28 typedef sg_error (*comp_global_init_function)(unsigned id); 29 typedef void (*comp_global_destroy_function)(void); 30 typedef void (*comp_global_cleanup_function)(void *); 31 32 struct sg_comp_status { 33 sg_error init_error; 34 }; 35 36 #if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD) 37 #define DECLARE_REQUIRED_COMP_LOCKS(comp,...) static const char * sg_##comp##_lock_names[] = { __VA_ARGS__ }; 38 #define REQUIRED_COMP_LOCKS(comp) sg_##comp##_lock_names, 39 #else 40 #define DECLARE_REQUIRED_COMP_LOCKS(comp,...) 41 #define REQUIRED_COMP_LOCKS(comp) 42 #endif 43 44 struct sg_comp_init { 45 comp_global_init_function init_fn; 46 comp_global_destroy_function destroy_fn; 47 comp_global_cleanup_function cleanup_fn; 48 size_t static_buf_size; 49 #if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD) 50 const char **required_locks; 51 #endif 52 struct sg_comp_status *status; 53 }; 54 55 void *sg_comp_get_tls(unsigned id); 56 57 #define DEFAULT_INIT_COMP(comp,...) \ 58 static sg_error sg_##comp##_init_comp(unsigned);\ 59 static void sg_##comp##_destroy_comp(void); \ 60 static void sg_##comp##_cleanup_comp(void *); \ 61 \ 62 static struct sg_comp_status sg_##comp##_status;\ 63 DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ 64 \ 65 __sg_private \ 66 const struct sg_comp_init sg_##comp##_init = { \ 67 sg_##comp##_init_comp, \ 68 sg_##comp##_destroy_comp, \ 69 sg_##comp##_cleanup_comp, \ 70 sizeof(struct sg_##comp##_glob), \ 71 REQUIRED_COMP_LOCKS(comp) \ 72 &sg_##comp##_status \ 73 }; \ 74 static unsigned int sg_##comp##_glob_id 75 76 #define GLOBAL_GET_TLS(comp) (struct sg_##comp##_glob *)(sg_comp_get_tls(sg_##comp##_glob_id)) 77 #define GLOBAL_SET_ID(comp,id) sg_##comp##_glob_id = (id) 78 79 #define EASY_COMP_INIT_FN(comp) \ 80 static sg_error sg_##comp##_init_comp(unsigned id){ \ 81 GLOBAL_SET_ID(comp,id); \ 82 return SG_ERROR_NONE; \ 83 } 84 85 #define EASY_COMP_DESTROY_FN(comp) \ 86 static void sg_##comp##_destroy_comp(void){} 87 88 #define EASY_COMP_CLEANUP_FN(comp,nvect) \ 89 static void sg_##comp##_cleanup_comp(void *p){ \ 90 struct sg_##comp##_glob *comp##_glob = p; \ 91 unsigned i; \ 92 TRACE_LOG_FMT(#comp, "sg_" #comp "_cleanup_comp(%p)", p); \ 93 assert(comp##_glob); \ 94 for( i = 0; i < nvect; ++i ) \ 95 sg_vector_free(comp##_glob->comp##_vectors[i]); \ 96 memset(comp##_glob->comp##_vectors, 0, sizeof(comp##_glob->comp##_vectors) ); \ 97 } 98 99 #define EASY_COMP_SETUP(comp,nvect,...) \ 100 struct sg_##comp##_glob { \ 101 sg_vector *comp##_vectors[nvect]; \ 102 }; \ 103 \ 104 static unsigned int sg_##comp##_glob_id; \ 105 \ 106 EASY_COMP_INIT_FN(comp) \ 107 EASY_COMP_DESTROY_FN(comp) \ 108 EASY_COMP_CLEANUP_FN(comp,nvect) \ 109 \ 110 static struct sg_comp_status sg_##comp##_status;\ 111 DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ 112 \ 113 __sg_private \ 114 const struct sg_comp_init sg_##comp##_init = { \ 115 sg_##comp##_init_comp, \ 116 sg_##comp##_destroy_comp, \ 117 sg_##comp##_cleanup_comp, \ 118 sizeof(struct sg_##comp##_glob), \ 119 REQUIRED_COMP_LOCKS(comp) \ 120 &sg_##comp##_status \ 121 } 122 123 #define EXTENDED_COMP_SETUP(comp,nvect,...) \ 124 static sg_error sg_##comp##_init_comp(unsigned);\ 125 static void sg_##comp##_destroy_comp(void); \ 126 static void sg_##comp##_cleanup_comp(void *); \ 127 \ 128 struct sg_##comp##_glob { \ 129 sg_vector *comp##_vectors[nvect]; \ 130 }; \ 131 \ 132 static unsigned int sg_##comp##_glob_id; \ 133 DECLARE_REQUIRED_COMP_LOCKS(comp, __VA_ARGS__) \ 134 \ 135 static struct sg_comp_status sg_##comp##_status;\ 136 __sg_private \ 137 const struct sg_comp_init sg_##comp##_init = { \ 138 sg_##comp##_init_comp, \ 139 sg_##comp##_destroy_comp, \ 140 sg_##comp##_cleanup_comp, \ 141 sizeof(struct sg_##comp##_glob), \ 142 REQUIRED_COMP_LOCKS(comp) \ 143 &sg_##comp##_status \ 144 } 145 146 #define EASY_COMP_ACCESS(fn,comp,name,idx) \ 147 sg_##name##_stats *fn(size_t *entries) { \ 148 \ 149 struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ 150 sg_error rc; \ 151 TRACE_LOG(#comp, "entering " #fn); \ 152 if( !comp##_glob ) { \ 153 /* assuming error comp can't neither */ \ 154 ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ 155 if(entries) \ 156 *entries = 0; \ 157 return NULL; \ 158 } \ 159 \ 160 if(!comp##_glob->comp##_vectors[idx]) \ 161 comp##_glob->comp##_vectors[idx] = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ 162 \ 163 if(comp##_glob->comp##_vectors[idx]){ \ 164 sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[idx]); \ 165 TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", name##_stats); \ 166 rc = fn##_int(name##_stats); \ 167 if(SG_ERROR_NONE == rc){ \ 168 TRACE_LOG(#comp, #fn " succeded"); \ 169 sg_clear_error(); \ 170 if(entries) \ 171 *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[idx]); \ 172 return name##_stats; \ 173 } \ 174 } \ 175 else { \ 176 rc = sg_get_error(); \ 177 } \ 178 \ 179 WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(rc)); \ 180 \ 181 if(entries) \ 182 *entries = 0; \ 183 \ 184 return NULL; \ 185 } \ 186 \ 187 sg_##name##_stats *fn##_r(size_t *entries) { \ 188 \ 189 sg_vector *name##_stats_vector = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ 190 sg_error rc; \ 191 TRACE_LOG(#comp, "entering " #fn "_r"); \ 192 if(name##_stats_vector) { \ 193 sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(name##_stats_vector); \ 194 TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", name##_stats); \ 195 rc = fn##_int(name##_stats); \ 196 if(SG_ERROR_NONE == rc){ \ 197 TRACE_LOG(#comp, #fn "_r succeded"); \ 198 sg_clear_error(); \ 199 if(entries) \ 200 *entries = VECTOR_ITEM_COUNT(name##_stats_vector); \ 201 return name##_stats; \ 202 } \ 203 sg_vector_free(name##_stats_vector); \ 204 } \ 205 else { \ 206 rc = sg_get_error(); \ 207 } \ 208 \ 209 WARN_LOG_FMT(#comp, #fn "_r failed with %s", sg_str_error(rc)); \ 210 \ 211 if(entries) \ 212 *entries = 0; \ 213 \ 214 return NULL; \ 215 } 216 217 #define MULTI_COMP_ACCESS(fn,comp,name,idx) \ 218 sg_##name##_stats *fn(size_t *entries) { \ 219 \ 220 struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ 221 sg_error rc; \ 222 TRACE_LOG(#comp, "entering " #fn); \ 223 if( !comp##_glob ) { \ 224 /* assuming error comp can't neither */ \ 225 ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ 226 if(entries) \ 227 *entries = 0; \ 228 return NULL; \ 229 } \ 230 \ 231 if(!comp##_glob->comp##_vectors[idx]) \ 232 comp##_glob->comp##_vectors[idx] = VECTOR_CREATE(sg_##name##_stats, 16); \ 233 else \ 234 VECTOR_CLEAR(comp##_glob->comp##_vectors[idx]); \ 235 \ 236 if(comp##_glob->comp##_vectors[idx]){ \ 237 TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", &comp##_glob->comp##_vectors[idx]); \ 238 rc = fn##_int(&comp##_glob->comp##_vectors[idx]); \ 239 if(SG_ERROR_NONE == rc) { \ 240 sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[idx]); \ 241 TRACE_LOG(#comp, #fn " succeded"); \ 242 sg_clear_error(); \ 243 if(entries) \ 244 *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[idx]); \ 245 return name##_stats; \ 246 } \ 247 } \ 248 else { \ 249 rc = sg_get_error(); \ 250 } \ 251 \ 252 WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(rc)); \ 253 \ 254 if(entries) \ 255 *entries = 0; \ 256 \ 257 return NULL; \ 258 } \ 259 \ 260 sg_##name##_stats *fn##_r(size_t *entries) { \ 261 sg_vector *name##_vector = VECTOR_CREATE(sg_##name##_stats, 16); \ 262 sg_error rc; \ 263 TRACE_LOG(#comp, "entering " #fn); \ 264 if(name##_vector) { \ 265 TRACE_LOG_FMT(#comp, "calling " #fn "_int(%p)", &name##_vector); \ 266 rc = fn##_int(&name##_vector); \ 267 if( SG_ERROR_NONE == rc ) { \ 268 sg_##name##_stats *name##_stats = (sg_##name##_stats *)VECTOR_DATA(name##_vector); \ 269 TRACE_LOG(#comp, #fn " succeded"); \ 270 sg_clear_error(); \ 271 if(entries) \ 272 *entries = VECTOR_ITEM_COUNT(name##_vector); \ 273 return name##_stats; \ 274 } \ 275 sg_vector_free(name##_vector); \ 276 } \ 277 else { \ 278 rc = sg_get_error(); \ 279 } \ 280 \ 281 WARN_LOG_FMT(#comp, #fn "_r failed with %s", sg_str_error(rc)); \ 282 \ 283 if(entries) \ 284 *entries = 0; \ 285 \ 286 return NULL; \ 287 } 288 289 #define EASY_COMP_DIFF(fn,getfn,comp,name,diffidx,nowidx) \ 290 sg_##name##_stats *fn(size_t *entries) { \ 291 \ 292 struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ 293 TRACE_LOG(#comp, "entering " #fn); \ 294 if( !comp##_glob ) { \ 295 /* assuming error comp can't neither */ \ 296 ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ 297 if(entries) \ 298 *entries = 0; \ 299 return NULL; \ 300 } \ 301 \ 302 if(!comp##_glob->comp##_vectors[nowidx]) { \ 303 TRACE_LOG_FMT(#comp, #fn " has nothing to compare with - calling %s", #getfn); \ 304 return getfn(entries); \ 305 } \ 306 \ 307 if(!comp##_glob->comp##_vectors[diffidx]) \ 308 comp##_glob->comp##_vectors[diffidx] = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ 309 \ 310 if(comp##_glob->comp##_vectors[diffidx]) { \ 311 sg_##name##_stats name##_last = *((sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[nowidx])); \ 312 sg_##name##_stats *name##_diff = (sg_##name##_stats *)VECTOR_DATA(comp##_glob->comp##_vectors[diffidx]); \ 313 sg_##name##_stats *name##_now = getfn(NULL); \ 314 \ 315 TRACE_LOG_FMT(#comp, "calling " #fn "_diff(%p, %p, %p)", name##_diff, name##_now, &name##_last); \ 316 if( (NULL != name##_now) && ( SG_ERROR_NONE == fn##_int(name##_diff, name##_now, &name##_last) ) ) { \ 317 TRACE_LOG(#comp, #fn " succeded"); \ 318 sg_clear_error(); \ 319 if(entries) \ 320 *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[diffidx]); \ 321 return name##_diff; \ 322 } \ 323 } \ 324 \ 325 WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(sg_get_error())); \ 326 \ 327 if(entries) \ 328 *entries = 0; \ 329 \ 330 return NULL; \ 331 } \ 332 \ 333 sg_##name##_stats *fn##_between(const sg_##name##_stats *name##_now, const sg_##name##_stats *name##_last, size_t *entries) { \ 334 \ 335 sg_vector *name##_diff_vector; \ 336 \ 337 TRACE_LOG(#comp, "entering " #fn "_between"); \ 338 name##_diff_vector = sg_vector_create(1, 1, 1, & VECTOR_INIT_INFO(sg_##name##_stats)); \ 339 if(name##_diff_vector){ \ 340 sg_error rc; \ 341 sg_##name##_stats *name##_diff = (sg_##name##_stats *)VECTOR_DATA(name##_diff_vector); \ 342 TRACE_LOG_FMT(#comp, "calling " #fn "_diff(%p, %p, %p)", name##_diff, name##_now, &name##_last); \ 343 rc = fn##_int(name##_diff, name##_now, name##_last); \ 344 if( SG_ERROR_NONE == rc ) { \ 345 TRACE_LOG(#comp, #fn "_between succeded"); \ 346 sg_clear_error(); \ 347 if(entries) \ 348 *entries = VECTOR_ITEM_COUNT(name##_diff_vector); \ 349 return name##_diff; \ 350 } \ 351 sg_vector_free(name##_diff_vector); \ 352 } \ 353 \ 354 WARN_LOG_FMT(#comp, #fn "_between failed with %s", sg_str_error(sg_get_error())); \ 355 \ 356 if(entries) \ 357 *entries = 0; \ 358 \ 359 return NULL; \ 360 } 361 362 #define MULTI_COMP_DIFF(fn,getfn,comp,name,diffidx,nowidx) \ 363 sg_##name##_stats *fn(size_t *entries){ \ 364 \ 365 struct sg_##comp##_glob *comp##_glob = GLOBAL_GET_TLS(comp); \ 366 TRACE_LOG(#comp, "entering " #fn); \ 367 if( !comp##_glob ) { \ 368 /* assuming error comp can't neither */ \ 369 ERROR_LOG(#comp, #fn " failed - cannot get glob"); \ 370 if(entries) \ 371 *entries = 0; \ 372 return NULL; \ 373 } \ 374 \ 375 if(!comp##_glob->comp##_vectors[nowidx]){ \ 376 TRACE_LOG_FMT(#comp, #fn " has nothing to compare with - calling %s", #getfn); \ 377 return getfn(entries); \ 378 } \ 379 \ 380 if(!comp##_glob->comp##_vectors[diffidx]) \ 381 comp##_glob->comp##_vectors[diffidx] = VECTOR_CREATE(sg_##name##_stats, comp##_glob->comp##_vectors[nowidx]->used_count); \ 382 \ 383 if( comp##_glob->comp##_vectors[diffidx] ) { \ 384 sg_error rc; \ 385 sg_vector *last = sg_vector_clone(comp##_glob->comp##_vectors[nowidx]); \ 386 \ 387 if(!last) \ 388 goto err_out; \ 389 \ 390 TRACE_LOG(#comp, "calling " #getfn "(NULL)"); \ 391 getfn(NULL); \ 392 \ 393 rc = sg_vector_compute_diff(&comp##_glob->comp##_vectors[diffidx], comp##_glob->comp##_vectors[nowidx], last); \ 394 sg_vector_free( last ); \ 395 \ 396 if( SG_ERROR_NONE == rc ) { \ 397 TRACE_LOG(#comp, #fn " succeded"); \ 398 sg_clear_error(); \ 399 if(entries) \ 400 *entries = VECTOR_ITEM_COUNT(comp##_glob->comp##_vectors[diffidx]); \ 401 return VECTOR_DATA(comp##_glob->comp##_vectors[diffidx]); \ 402 } \ 403 } \ 404 \ 405 err_out: \ 406 if(entries) \ 407 *entries = 0; \ 408 \ 409 WARN_LOG_FMT(#comp, #fn " failed with %s", sg_str_error(sg_get_error())); \ 410 \ 411 return NULL; \ 412 } \ 413 \ 414 sg_##name##_stats * \ 415 fn##_between(const sg_##name##_stats *cur, \ 416 const sg_##name##_stats *last, \ 417 size_t *entries) { \ 418 \ 419 sg_vector *name##_diff_vector; \ 420 sg_error rc; \ 421 \ 422 TRACE_LOG(#comp, "entering " #fn "_between"); \ 423 name##_diff_vector = VECTOR_CREATE(sg_##name##_stats, 1); \ 424 if(name##_diff_vector){ \ 425 rc = sg_vector_compute_diff(&name##_diff_vector, VECTOR_ADDRESS_CONST(cur), VECTOR_ADDRESS_CONST(last)); \ 426 \ 427 if( SG_ERROR_NONE == rc ) { \ 428 TRACE_LOG(#comp, #fn "_between succeded"); \ 429 sg_clear_error(); \ 430 if(entries) \ 431 *entries = VECTOR_ITEM_COUNT(name##_diff_vector); \ 432 return VECTOR_DATA(name##_diff_vector); \ 433 } \ 434 \ 435 sg_vector_free(name##_diff_vector); \ 436 } \ 437 else { \ 438 rc = sg_get_error(); \ 439 } \ 440 \ 441 WARN_LOG_FMT(#comp, #fn "_between failed with %s", sg_str_error(rc)); \ 442 \ 443 if(entries) \ 444 *entries = 0; \ 445 \ 446 return NULL; \ 447 } 448 449 __sg_private sg_error sg_comp_init(int ignore_init_errors); 450 __sg_private sg_error sg_comp_destroy(void); 451 __sg_private sg_error sg_global_lock(void); 452 __sg_private sg_error sg_global_unlock(void); 453 454 #endif /* STATGRAB_GLOBALS_H */ 455