00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "../../sr_module.h"
00027 #include "../../mem/mem.h"
00028 #include "../../str.h"
00029 #include "../../dprint.h"
00030 #include "../../locking.h"
00031 #include "../../atomic_ops.h"
00032 #include "../../cfg/cfg.h"
00033 #include "../../rpc.h"
00034 #include "../../rand/fastrand.h"
00035 #include "../../timer.h"
00036 #include "../../mod_fix.h"
00037
00038 MODULE_VERSION
00039
00040 static int mt_mem_alloc_f(struct sip_msg*, char*,char*);
00041 static int mt_mem_free_f(struct sip_msg*, char*,char*);
00042 static int mod_init(void);
00043 static void mod_destroy(void);
00044
00045
00046 static cmd_export_t cmds[]={
00047 {"mt_mem_alloc", mt_mem_alloc_f, 1, fixup_var_int_1,
00048 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
00049 {"mt_mem_free", mt_mem_free_f, 1, fixup_var_int_1,
00050 REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONSEND_ROUTE},
00051 {0, 0, 0, 0, 0}
00052 };
00053
00054
00055
00056 struct cfg_group_malloc_test {
00057 int check_content;
00058 int realloc_p;
00059 };
00060
00061
00062 static struct cfg_group_malloc_test default_mt_cfg = {
00063 0,
00064 0
00065 };
00066
00067 static void * mt_cfg = &default_mt_cfg;
00068
00069 static cfg_def_t malloc_test_cfg_def[] = {
00070 {"check_content", CFG_VAR_INT | CFG_ATOMIC, 0, 1, 0, 0,
00071 "check if allocated memory was overwritten by filling it with "
00072 "a special pattern and checking it on free."},
00073 {"realloc_p", CFG_VAR_INT | CFG_ATOMIC, 0, 90, 0, 0,
00074 "realloc probability in percents. During tests and mem_rnd_alloc"
00075 " realloc_p percents of the allocations will be made by realloc'ing"
00076 " and existing chunk. The maximum value is limited to 90, to avoid"
00077 " very long mem_rnd_alloc runs (a realloc might also free memory)." },
00078 {0, 0, 0, 0, 0, 0}
00079 };
00080
00081
00082
00083 static rpc_export_t mt_rpc[];
00084
00085
00086
00087 static param_export_t params[]={
00088 {"check_content", PARAM_INT, &default_mt_cfg.check_content},
00089 {0,0,0}
00090 };
00091
00092
00093
00094 struct module_exports exports = {
00095 "malloc_test",
00096 cmds,
00097 mt_rpc,
00098 params,
00099 mod_init,
00100 0,
00101 mod_destroy,
00102 0,
00103 0
00104 };
00105
00106
00107
00108 #define MC_F_CHECK_CONTENTS 1
00109
00110 struct mem_chunk{
00111 struct mem_chunk* next;
00112 void* addr;
00113 unsigned long size;
00114 unsigned long flags;
00115 };
00116
00117 struct allocated_list {
00118 struct mem_chunk* chunks;
00119 gen_lock_t lock;
00120 volatile long size;
00121 volatile int no;
00122 };
00123
00124 struct allocated_list* alloc_lst;
00125
00126
00127 struct rnd_time_test {
00128 unsigned long min;
00129 unsigned long max;
00130 unsigned long total;
00131 unsigned long crt;
00132 ticks_t min_intvrl;
00133 ticks_t max_intvrl;
00134 ticks_t stop_time;
00135 ticks_t start_time;
00136 unsigned long calls;
00137 unsigned long reallocs;
00138 unsigned int errs;
00139 unsigned int overfl;
00140 struct rnd_time_test* next;
00141 struct timer_ln timer;
00142 int id;
00143 };
00144
00145 struct rnd_time_test_lst {
00146 struct rnd_time_test* tests;
00147 gen_lock_t lock;
00148 volatile int last_id;
00149 };
00150
00151
00152 struct rnd_time_test_lst* rndt_lst;
00153
00154 static unsigned long mem_unleak(unsigned long size);
00155 static void mem_destroy_all_tests();
00156
00157 static int mod_init(void)
00158 {
00159 WARN("This is a test/debugging module, don't use it in production\n");
00160
00161 if (cfg_declare("malloc_test", malloc_test_cfg_def, &default_mt_cfg,
00162 cfg_sizeof(malloc_test), &mt_cfg)){
00163 ERR("failed to register the configuration\n");
00164 goto error;
00165 }
00166
00167 alloc_lst = shm_malloc(sizeof(*alloc_lst));
00168 if (alloc_lst == 0)
00169 goto error;
00170 alloc_lst->chunks = 0;
00171 atomic_set_long(&alloc_lst->size, 0);
00172 atomic_set_int(&alloc_lst->no, 0);
00173 if (lock_init(&alloc_lst->lock) == 0)
00174 goto error;
00175 rndt_lst = shm_malloc(sizeof(*rndt_lst));
00176 if (rndt_lst == 0)
00177 goto error;
00178 rndt_lst->tests = 0;
00179 atomic_set_int(&rndt_lst->last_id, 0);
00180 if (lock_init(&rndt_lst->lock) == 0)
00181 goto error;
00182 return 0;
00183 error:
00184 return -1;
00185 }
00186
00187
00188
00189 static void mod_destroy()
00190 {
00191 if (rndt_lst) {
00192 mem_destroy_all_tests();
00193 lock_destroy(&rndt_lst->lock);
00194 shm_free(rndt_lst);
00195 rndt_lst = 0;
00196 }
00197 if (alloc_lst) {
00198 mem_unleak(-1);
00199 lock_destroy(&alloc_lst->lock);
00200 shm_free(alloc_lst);
00201 alloc_lst = 0;
00202 }
00203 }
00204
00205
00206
00212 static int mem_track(void* addr, unsigned long size)
00213 {
00214 struct mem_chunk* mc;
00215 unsigned long* d;
00216 unsigned long r,i;
00217
00218 mc = shm_malloc(sizeof(*mc));
00219 if (mc == 0) goto error;
00220 mc->addr = addr;
00221 mc->size = size;
00222 mc->flags = 0;
00223 if (cfg_get(malloc_test, mt_cfg, check_content)){
00224 mc->flags |= MC_F_CHECK_CONTENTS;
00225 d = addr;
00226 for (r = 0; r < size/sizeof(*d); r++){
00227 d[r]=~(unsigned long)&d[r];
00228 }
00229 for (i=0; i< size % sizeof(*d); i++){
00230 ((char*)&d[r])[i]=~((unsigned long)&d[r] >> i*8);
00231 }
00232 }
00233 lock_get(&alloc_lst->lock);
00234 mc->next = alloc_lst->chunks;
00235 alloc_lst->chunks = mc;
00236 lock_release(&alloc_lst->lock);
00237 atomic_add_long(&alloc_lst->size, size);
00238 atomic_inc_int(&alloc_lst->no);
00239 return 0;
00240 error:
00241 return -1;
00242 }
00243
00244
00245
00252 static int mem_leak(unsigned long size)
00253 {
00254 void *d;
00255
00256 d = shm_malloc(size);
00257 if (d) {
00258 if (mem_track(d, size) < 0){
00259 shm_free(d);
00260 }else
00261 return 0;
00262 }
00263 return -1;
00264 }
00265
00266
00267
00268
00269
00270
00271 static int _mem_chunk_realloc_unsafe(struct mem_chunk *c, unsigned long size)
00272 {
00273 unsigned long* d;
00274 int r, i;
00275
00276 d = shm_realloc(c->addr, size);
00277 if (d) {
00278 if (cfg_get(malloc_test, mt_cfg, check_content) &&
00279 c->flags & MC_F_CHECK_CONTENTS) {
00280
00281
00282 for (r = 0; r < size/sizeof(*d); r++){
00283 d[r]=~(unsigned long)&d[r];
00284 }
00285 for (i=0; i< size % sizeof(*d); i++){
00286 ((char*)&d[r])[i]=~((unsigned long)&d[r] >> i*8);
00287 }
00288 }
00289 c->addr = d;
00290 c->size = size;
00291 return 0;
00292 }
00293 return -1;
00294 }
00295
00296
00297
00298 static void mem_chunk_free(struct mem_chunk* c)
00299 {
00300 unsigned long* d;
00301 unsigned long r,i;
00302 int err;
00303
00304 if (cfg_get(malloc_test, mt_cfg, check_content) &&
00305 c->flags & MC_F_CHECK_CONTENTS) {
00306 d = c->addr;
00307 err = 0;
00308 for (r = 0; r < c->size/sizeof(*d); r++){
00309 if (d[r]!=~(unsigned long)&d[r])
00310 err++;
00311 d[r] = (unsigned long)&d[r];
00312 }
00313 for (i=0; i< c->size % sizeof(*d); i++){
00314 if (((unsigned char*)&d[r])[i] !=
00315 (unsigned char)~((unsigned long)&d[r] >> i*8))
00316 err++;
00317 ((char*)&d[r])[i] = (unsigned char)((unsigned long)&d[r] >> i*8);
00318 }
00319 if (err)
00320 ERR("%d errors while checking %ld bytes at %p\n", err, c->size, d);
00321 }
00322 shm_free(c->addr);
00323 c->addr = 0;
00324 c->flags = 0;
00325 }
00326
00327
00328
00335 static unsigned long mem_unleak(unsigned long size)
00336 {
00337 struct mem_chunk** mc;
00338 struct mem_chunk* t;
00339 struct mem_chunk** min_chunk;
00340 unsigned long freed;
00341 unsigned int no;
00342
00343 freed = 0;
00344 no = 0;
00345 min_chunk = 0;
00346 lock_get(&alloc_lst->lock);
00347 if (size>=atomic_get_long(&alloc_lst->size)){
00348
00349 for (mc = &alloc_lst->chunks; *mc; ){
00350 t = *mc;
00351 mem_chunk_free(t);
00352 freed += t->size;
00353 no++;
00354 *mc = t->next;
00355 shm_free(t);
00356 }
00357 alloc_lst->chunks=0;
00358 } else {
00359
00360 for (mc = &alloc_lst->chunks; *mc && (freed < size);) {
00361 if ((*mc)->size <= (size - freed)) {
00362 t = *mc;
00363 mem_chunk_free(t);
00364 freed += t->size;
00365 no++;
00366 *mc = t->next;
00367 shm_free(t);
00368 continue;
00369 } else if (min_chunk == 0 || (*min_chunk)->size > (*mc)->size) {
00370
00371 min_chunk = mc;
00372 }
00373 mc = &(*mc)->next;
00374 }
00375 if (size > freed && min_chunk) {
00376 mc = min_chunk;
00377 t = *mc;
00378 mem_chunk_free(t);
00379 freed += t->size;
00380 no++;
00381 *mc = (*mc)->next;
00382 shm_free(t);
00383 }
00384 }
00385 lock_release(&alloc_lst->lock);
00386 atomic_add_long(&alloc_lst->size, -freed);
00387 atomic_add_int(&alloc_lst->no, -no);
00388 return freed;
00389 }
00390
00391
00392
00401 static int mem_rnd_realloc(unsigned long size, long* diff)
00402 {
00403 struct mem_chunk* t;
00404 int ret;
00405 int target, i;
00406
00407 *diff = 0;
00408 ret = -1;
00409 lock_get(&alloc_lst->lock);
00410 target = fastrand_max(atomic_get_int(&alloc_lst->no));
00411 for (t = alloc_lst->chunks, i=0; t; t=t->next, i++ ){
00412 if (target == i) {
00413 *diff = (long)size - (long)t->size;
00414 if ((ret=_mem_chunk_realloc_unsafe(t, size)) < 0)
00415 *diff = 0;
00416 break;
00417 }
00418 }
00419 lock_release(&alloc_lst->lock);
00420 atomic_add_long(&alloc_lst->size, *diff);
00421 return ret;
00422 }
00423
00424
00425
00426 #define MIN_ulong(a, b) \
00427 (unsigned long)((unsigned long)(a)<(unsigned long)(b)?(a):(b))
00428
00429
00430
00431
00432
00433
00434 static int mem_rnd_leak(unsigned long min, unsigned long max,
00435 unsigned long total_size)
00436 {
00437 unsigned long size;
00438 unsigned long crt_size, crt_min;
00439 long diff;
00440 int err, p;
00441
00442 size = total_size;
00443 err = 0;
00444 while(size){
00445 crt_min = MIN_ulong(min, size);
00446 crt_size = fastrand_max(MIN_ulong(max, size) - crt_min) + crt_min;
00447 p = cfg_get(malloc_test, mt_cfg, realloc_p);
00448 if (p && ((fastrand_max(99) +1) <= p)){
00449 if (mem_rnd_realloc(crt_size, &diff) == 0){
00450 size -= diff;
00451 continue;
00452 }
00453 }
00454 size -= crt_size;
00455 err += mem_leak(crt_size) < 0;
00456 }
00457 return -err;
00458 }
00459
00460
00461
00462
00463 static ticks_t tst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
00464 {
00465 struct rnd_time_test* tst;
00466 ticks_t next_int;
00467 ticks_t max_int;
00468 unsigned long crt_size, crt_min, remaining;
00469 long diff;
00470 int p;
00471
00472 tst = data;
00473
00474 next_int = 0;
00475 max_int = 0;
00476
00477 if (tst->total <= tst->crt) {
00478 mem_unleak(tst->crt);
00479 tst->crt = 0;
00480 tst->overfl++;
00481 }
00482 remaining = tst->total - tst->crt;
00483 crt_min = MIN_ulong(tst->min, remaining);
00484 crt_size = fastrand_max(MIN_ulong(tst->max, remaining) - crt_min) +
00485 crt_min;
00486 p = cfg_get(malloc_test, mt_cfg, realloc_p);
00487 if (p && ((fastrand_max(99) +1) <= p)) {
00488 if (mem_rnd_realloc(crt_size, &diff) == 0){
00489 tst->crt -= diff;
00490 tst->reallocs++;
00491 goto skip_alloc;
00492 }
00493 }
00494 if (mem_leak(crt_size) >= 0)
00495 tst->crt += crt_size;
00496 else
00497 tst->errs ++;
00498 skip_alloc:
00499 tst->calls++;
00500
00501 if (TICKS_GT(tst->stop_time, ticks)) {
00502 next_int = fastrand_max(tst->max_intvrl - tst->min_intvrl) +
00503 tst->min_intvrl;
00504 max_int = tst->stop_time - ticks;
00505 } else {
00506
00507 WARN("test %d time expired, stopping"
00508 " (%d s runtime, %ld calls, %d overfl, %d errors,"
00509 " crt %ld bytes)\n",
00510 tst->id, TICKS_TO_S(ticks - tst->start_time),
00511 tst->calls, tst->overfl, tst->errs, tst->crt);
00512 mem_unleak(tst->crt);
00513 ;
00514 }
00515
00516
00517 return MIN_unsigned(next_int, max_int);
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 static int mem_leak_time_test(unsigned long min, unsigned long max,
00530 unsigned long total_size,
00531 ticks_t min_intvrl, ticks_t max_intvrl,
00532 ticks_t test_time)
00533 {
00534 struct rnd_time_test* tst;
00535 struct rnd_time_test* l;
00536 ticks_t first_int;
00537 int id;
00538
00539 tst = shm_malloc(sizeof(*tst));
00540 if (tst == 0)
00541 goto error;
00542 memset(tst, 0, sizeof(*tst));
00543 id = tst->id = atomic_add_int(&rndt_lst->last_id, 1);
00544 tst->min = min;
00545 tst->max = max;
00546 tst-> total = total_size;
00547 tst->min_intvrl = min_intvrl;
00548 tst->max_intvrl = max_intvrl;
00549 tst->start_time = get_ticks_raw();
00550 tst->stop_time = get_ticks_raw() + test_time;
00551 first_int = fastrand_max(max_intvrl - min_intvrl) + min_intvrl;
00552 timer_init(&tst->timer, tst_timer, tst, 0);
00553 lock_get(&rndt_lst->lock);
00554 tst->next=rndt_lst->tests;
00555 rndt_lst->tests=tst;
00556 lock_release(&rndt_lst->lock);
00557 if (timer_add(&tst->timer, MIN_unsigned(first_int, test_time)) < 0 )
00558 goto error;
00559 return id;
00560 error:
00561 if (tst) {
00562 lock_get(&rndt_lst->lock);
00563 for (l=rndt_lst->tests; l; l=l->next)
00564 if (l->next == tst) {
00565 l->next = tst->next;
00566 break;
00567 }
00568 lock_release(&rndt_lst->lock);
00569 shm_free(tst);
00570 }
00571 return -1;
00572 }
00573
00574
00575 static int is_mem_test_stopped(struct rnd_time_test* tst)
00576 {
00577 return TICKS_LE(tst->stop_time, get_ticks_raw());
00578 }
00579
00583 static int mem_test_stop_tst(struct rnd_time_test* tst)
00584 {
00585 if (!is_mem_test_stopped(tst)) {
00586 if (timer_del(&tst->timer) == 0) {
00587 tst->stop_time=get_ticks_raw();
00588 return 0;
00589 }
00590 }
00591 return -1;
00592 }
00593
00594
00598 static int mem_test_stop(int id)
00599 {
00600 struct rnd_time_test* tst;
00601
00602 lock_get(&rndt_lst->lock);
00603 for (tst = rndt_lst->tests; tst; tst = tst->next)
00604 if (tst->id == id) {
00605 mem_test_stop_tst(tst);
00606 break;
00607 }
00608 lock_release(&rndt_lst->lock);
00609 return -(tst == 0);
00610 }
00611
00612
00613 static void mem_destroy_all_tests()
00614 {
00615 struct rnd_time_test* tst;
00616 struct rnd_time_test* nxt;
00617
00618 lock_get(&rndt_lst->lock);
00619 for (tst = rndt_lst->tests; tst;) {
00620 nxt = tst->next;
00621 mem_test_stop_tst(tst);
00622 shm_free(tst);
00623 tst = nxt;
00624 }
00625 rndt_lst->tests = 0;
00626 lock_release(&rndt_lst->lock);
00627 }
00628
00629
00630 static int mem_test_destroy(int id)
00631 {
00632 struct rnd_time_test* tst;
00633 struct rnd_time_test** crt_lnk;
00634
00635 lock_get(&rndt_lst->lock);
00636 for (tst = 0, crt_lnk = &rndt_lst->tests; *crt_lnk;
00637 crt_lnk = &(*crt_lnk)->next)
00638 if ((*crt_lnk)->id == id) {
00639 tst=*crt_lnk;
00640 mem_test_stop_tst(tst);
00641 *crt_lnk=tst->next;
00642 shm_free(tst);
00643 break;
00644 }
00645 lock_release(&rndt_lst->lock);
00646 return -(tst == 0);
00647 }
00648
00649
00650
00651
00652 static int mt_mem_alloc_f(struct sip_msg* msg, char* sz, char* foo)
00653 {
00654 int size;
00655
00656 if (sz == 0 || get_int_fparam(&size, msg, (fparam_t*)sz) < 0)
00657 return -1;
00658 return mem_leak(size)>=0?1:-1;
00659 }
00660
00661
00662
00663 static int mt_mem_free_f(struct sip_msg* msg, char* sz, char* foo)
00664 {
00665 int size;
00666 unsigned long freed;
00667
00668 size=-1;
00669 if (sz != 0 && get_int_fparam(&size, msg, (fparam_t*)sz) < 0)
00670 return -1;
00671 freed=mem_unleak(size);
00672 return (freed==0)?1:freed;
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685 static int rpc_get_size_mod(rpc_t* rpc, void* c)
00686 {
00687 char* m;
00688
00689 if (rpc->scan(c, "*s", &m) > 0) {
00690 switch(*m) {
00691 case 'b':
00692 case 'B':
00693 return 0;
00694 case 'k':
00695 case 'K':
00696 return 10;
00697 case 'm':
00698 case 'M':
00699 return 20;
00700 case 'g':
00701 case 'G':
00702 return 30;
00703 default:
00704 rpc->fault(c, 500, "bad param use b|k|m|g");
00705 return -1;
00706 }
00707 }
00708 return 0;
00709 }
00710
00711
00712
00713 static const char* rpc_mt_alloc_doc[2] = {
00714 "Allocates the specified number of bytes (debugging/test function)."
00715 "Use b|k|m|g to specify the desired size unit",
00716 0
00717 };
00718
00719 static void rpc_mt_alloc(rpc_t* rpc, void* c)
00720 {
00721 int size;
00722 int rs;
00723
00724 if (rpc->scan(c, "d", &size) < 1) {
00725 return;
00726 }
00727 rs=rpc_get_size_mod(rpc, c);
00728 if (rs<0)
00729
00730 return;
00731 if (mem_leak((unsigned long)size << rs) < 0) {
00732 rpc->fault(c, 400, "memory allocation failed");
00733 }
00734 return;
00735 }
00736
00737
00738 static const char* rpc_mt_realloc_doc[2] = {
00739 "Reallocates the specified number of bytes from a pre-allocated"
00740 " randomly selected memory chunk. If no pre-allocated memory"
00741 " chunks exists, it will fail."
00742 " Make sure mt.mem_used is non 0 or call mt.mem_alloc prior to calling"
00743 " this function."
00744 " Returns the difference in bytes (<0 if bytes were freed, >0 if more"
00745 " bytes were allocated)."
00746 "Use b|k|m|g to specify the desired size unit",
00747 0
00748 };
00749
00750 static void rpc_mt_realloc(rpc_t* rpc, void* c)
00751 {
00752 int size;
00753 int rs;
00754 long diff;
00755
00756 if (rpc->scan(c, "d", &size) < 1) {
00757 return;
00758 }
00759 rs=rpc_get_size_mod(rpc, c);
00760 if (rs<0)
00761
00762 return;
00763 if (mem_rnd_realloc((unsigned long)size << rs, &diff) < 0) {
00764 rpc->fault(c, 400, "memory allocation failed");
00765 }
00766 rpc->add(c, "d", diff >> rs);
00767 return;
00768 }
00769
00770
00771 static const char* rpc_mt_free_doc[2] = {
00772 "Frees the specified number of bytes, previously allocated by one of the"
00773 " other malloc_test functions (e.g. mt.mem_alloc or the script "
00774 "mt_mem_alloc). Use b|k|m|g to specify the desired size unit."
00775 "Returns the number of bytes freed (can be higher or"
00776 " smaller then the requested size)",
00777 0
00778 };
00779
00780
00781 static void rpc_mt_free(rpc_t* rpc, void* c)
00782 {
00783 int size;
00784 int rs;
00785
00786 size = -1;
00787 rs = 0;
00788 if (rpc->scan(c, "*d", &size) > 0) {
00789
00790 rs=rpc_get_size_mod(rpc, c);
00791 if (rs<0)
00792
00793 return;
00794 }
00795 rpc->add(c, "d", (int)(mem_unleak((unsigned long)size << rs) >> rs));
00796 return;
00797 }
00798
00799
00800
00801 static const char* rpc_mt_used_doc[2] = {
00802 "Returns how many memory chunks and how many bytes are currently"
00803 " allocated via the mem_alloc module functions."
00804 " Use b|k|m|g to specify the desired size unit.",
00805 0
00806 };
00807
00808
00809 static void rpc_mt_used(rpc_t* rpc, void* c)
00810 {
00811 int rs;
00812
00813 rs = 0;
00814 rs=rpc_get_size_mod(rpc, c);
00815 if (rs<0)
00816
00817 return;
00818 rpc->add(c, "d", atomic_get_int(&alloc_lst->no));
00819 rpc->add(c, "d", (int)(atomic_get_long(&alloc_lst->size) >> rs));
00820 return;
00821 }
00822
00823
00824 static const char* rpc_mt_rnd_alloc_doc[2] = {
00825 "Takes 4 parameters: min, max, total_size and an optional unit (b|k|m|g)."
00826 " It will allocate total_size memory, in pieces of random size between"
00827 "min .. max (inclusive).",
00828 0
00829 };
00830
00831
00832 static void rpc_mt_rnd_alloc(rpc_t* rpc, void* c)
00833 {
00834 int min, max, total_size;
00835 int rs;
00836 int err;
00837
00838 if (rpc->scan(c, "ddd", &min, &max, &total_size) < 3) {
00839 return;
00840 }
00841 rs=rpc_get_size_mod(rpc, c);
00842 if (rs<0)
00843
00844 return;
00845 if (min > max || min < 0 || max > total_size) {
00846 rpc->fault(c, 400, "invalid parameter values");
00847 return;
00848 }
00849 if ((err=mem_rnd_leak((unsigned long)min << rs,
00850 (unsigned long)max << rs,
00851 (unsigned long)total_size <<rs )) < 0) {
00852 rpc->fault(c, 400, "memory allocation failed (%d errors)", -err);
00853 }
00854 return;
00855 }
00856
00857
00858 static const char* rpc_mt_test_start_doc[2] = {
00859 "Takes 7 parameters: min, max, total_size, min_interval, max_interval, "
00860 "test_time and an optional size unit (b|k|m|g). All the time units are ms."
00861 " It will run a memory allocation test for test_time ms. At a random"
00862 " interval between min_interval and max_interval ms. it will allocate a"
00863 " memory chunk with random size, between min and max. Each time total_size"
00864 " is reached, it will free all the memory allocated and start again."
00865 "Returns the test id (integer)",
00866 0
00867 };
00868
00869
00870 static void rpc_mt_test_start(rpc_t* rpc, void* c)
00871 {
00872 int min, max, total_size;
00873 int min_intvrl, max_intvrl, total_time;
00874 int rs;
00875 int id;
00876
00877 if (rpc->scan(c, "dddddd", &min, &max, &total_size,
00878 &min_intvrl, &max_intvrl, &total_time) < 6) {
00879 return;
00880 }
00881 rs=rpc_get_size_mod(rpc, c);
00882 if (rs<0)
00883
00884 return;
00885 if (min > max || min < 0 || max > total_size) {
00886 rpc->fault(c, 400, "invalid size parameters values");
00887 return;
00888 }
00889 if (min_intvrl > max_intvrl || min_intvrl <= 0 || max_intvrl > total_time){
00890 rpc->fault(c, 400, "invalid time intervals values");
00891 return;
00892 }
00893 if ((id=mem_leak_time_test((unsigned long)min << rs,
00894 (unsigned long)max << rs,
00895 (unsigned long)total_size <<rs,
00896 MS_TO_TICKS(min_intvrl),
00897 MS_TO_TICKS(max_intvrl),
00898 MS_TO_TICKS(total_time)
00899 )) < 0) {
00900 rpc->fault(c, 400, "memory allocation failed");
00901 } else {
00902 rpc->add(c, "d", id);
00903 }
00904 return;
00905 }
00906
00907
00908 static const char* rpc_mt_test_stop_doc[2] = {
00909 "Takes 1 parameter: the test id. It will stop the corresponding test."
00910 "Note: the test is stopped, but not destroyed." ,
00911 0
00912 };
00913
00914
00915 static void rpc_mt_test_stop(rpc_t* rpc, void* c)
00916 {
00917 int id;
00918
00919 if (rpc->scan(c, "d", &id) < 1) {
00920 return;
00921 }
00922 if (mem_test_stop(id)<0) {
00923 rpc->fault(c, 400, "test %d not found", id);
00924 }
00925 return;
00926 }
00927
00928
00929 static const char* rpc_mt_test_destroy_doc[2] = {
00930 "Takes 1 parameter: the test id. It will destroy the corresponding test.",
00931 0
00932 };
00933
00934
00935 static void rpc_mt_test_destroy(rpc_t* rpc, void* c)
00936 {
00937 int id;
00938
00939 if (rpc->scan(c, "*d", &id) > 0 && id!=-1) {
00940 if (mem_test_destroy(id) < 0 )
00941 rpc->fault(c, 400, "test %d not found", id);
00942 } else {
00943 mem_destroy_all_tests();
00944 }
00945 return;
00946 }
00947
00948
00949 static const char* rpc_mt_test_destroy_all_doc[2] = {
00950 "It will destroy all the tests (running or stopped).",
00951 0
00952 };
00953
00954
00955 static void rpc_mt_test_destroy_all(rpc_t* rpc, void* c)
00956 {
00957 mem_destroy_all_tests();
00958 return;
00959 }
00960
00961
00962 static const char* rpc_mt_test_list_doc[2] = {
00963 "If a test id parameter is provided it will list the corresponding test,"
00964 " else it will list all of them. Use b |k | m | g as a second parameter"
00965 " for the size units (default bytes)",
00966 0
00967 };
00968
00969
00970 static void rpc_mt_test_list(rpc_t* rpc, void* c)
00971 {
00972 int id, rs;
00973 struct rnd_time_test* tst;
00974 void *h;
00975
00976 rs = 0;
00977 if (rpc->scan(c, "*d", &id) < 1) {
00978 id = -1;
00979 } else {
00980 rs=rpc_get_size_mod(rpc, c);
00981 if (rs < 0)
00982 return;
00983 }
00984 lock_get(&rndt_lst->lock);
00985 for (tst = rndt_lst->tests; tst; tst=tst->next)
00986 if (tst->id == id || id == -1) {
00987 rpc->add(c, "{", &h);
00988 rpc->struct_add(h, "ddddddddddd",
00989 "ID ", tst->id,
00990 "run time (s) ", (int)TICKS_TO_S((
00991 TICKS_LE(tst->stop_time,
00992 get_ticks_raw()) ?
00993 tst->stop_time : get_ticks_raw()) -
00994 tst->start_time),
00995 "remaining (s)", TICKS_LE(tst->stop_time,
00996 get_ticks_raw()) ? 0 :
00997 (int)TICKS_TO_S(tst->stop_time -
00998 get_ticks_raw()),
00999 "total calls ", (int)tst->calls,
01000 "reallocs ", (int)tst->reallocs,
01001 "errors ", (int)tst->errs,
01002 "overflows ", (int)tst->overfl,
01003 "total alloc ", (int)((tst->crt +
01004 tst->overfl * tst->total)>>rs),
01005 "min ", (int)(tst->min>>rs),
01006 "max ", (int)(tst->max>>rs),
01007 "total ", (int)(tst->total>>rs) );
01008 if (id != -1) break;
01009 }
01010 lock_release(&rndt_lst->lock);
01011
01012 return;
01013 }
01014
01015
01016 static rpc_export_t mt_rpc[] = {
01017 {"mt.mem_alloc", rpc_mt_alloc, rpc_mt_alloc_doc, 0},
01018 {"mt.mem_free", rpc_mt_free, rpc_mt_free_doc, 0},
01019 {"mt.mem_realloc", rpc_mt_realloc, rpc_mt_realloc_doc, 0},
01020 {"mt.mem_used", rpc_mt_used, rpc_mt_used_doc, 0},
01021 {"mt.mem_rnd_alloc", rpc_mt_rnd_alloc, rpc_mt_rnd_alloc_doc, 0},
01022 {"mt.mem_test_start", rpc_mt_test_start, rpc_mt_test_start_doc, 0},
01023 {"mt.mem_test_stop", rpc_mt_test_stop, rpc_mt_test_stop_doc, 0},
01024 {"mt.mem_test_destroy", rpc_mt_test_destroy, rpc_mt_test_destroy_doc, 0},
01025 {"mt.mem_test_destroy_all", rpc_mt_test_destroy_all,
01026 rpc_mt_test_destroy_all_doc, 0},
01027 {"mt.mem_test_list", rpc_mt_test_list, rpc_mt_test_list_doc, 0},
01028 {0, 0, 0, 0}
01029 };
01030