void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { if (ptr) { // avoid a bunch of NULL pointer free calls if (!bin_free(ptr)) { // not our range, use libc allocator // TRACE("libc free %p", ptr); free(ptr); } } return NULL; } else { #if defined(DEBUG) if (SimulateMallocFailure < 0 ) { //delayed failure if (++SimulateMallocFailure == 0) { SimulateMallocFailure = 1; } } if ( SimulateMallocFailure > 0) { // simulate one malloc failure TRACE("bin_l_alloc(): simulating malloc failure at %p[%lu]", ptr, nsize); return 0; } #endif // #if defined(DEBUG) // try our allocator, if it fails use libc allocator void * res = bin_realloc(ptr, nsize); if (res && ptr) { // TRACE("OUR realloc %p[%lu] -> %p[%lu]", ptr, osize, res, nsize); } if (res == 0) { res = realloc(ptr, nsize); // TRACE("libc realloc %p[%lu] -> %p[%lu]", ptr, osize, res, nsize); // if (res == 0 ){ // TRACE("realloc FAILURE %lu", nsize); // dumpFreeMemory(); // } } return res; } }
void * bin_realloc(void * ptr, size_t size) { if (ptr == 0) { //no previous data, try our malloc return bin_malloc(size); } else { if (! (slots1.is_member(ptr) || slots2.is_member(ptr)) ) { // not our data, leave it to libc realloc return 0; } //we have existing data // if it fits in current slot, return it // TODO if new size is smaller, try to relocate in smaller slot if ( slots1.can_fit(ptr, size) ) { // TRACE("OUR realloc %p[%lu] fits in slot1", ptr, size); return ptr; } if ( slots2.can_fit(ptr, size) ) { // TRACE("OUR realloc %p[%lu] fits in slot2", ptr, size); return ptr; } //we need a bigger slot void * res = bin_malloc(size); if (res == 0) { // we don't have the space, use libc malloc // TRACE("bin_malloc [%lu] FAILURE", size); res = malloc(size); if (res == 0) { TRACE("libc malloc [%lu] FAILURE", size); return 0; } } //copy data memcpy(res, ptr, slots1.size(ptr) + slots2.size(ptr)); bin_free(ptr); return res; } }
void malloc_test(struct thread_st *st) { struct block *bl; int i, b, r; struct lran2_st ld; /* data for random number generator */ unsigned long rsize[BINS_PER_BLOCK]; int rnum[BINS_PER_BLOCK]; lran2_init(&ld, st->u.seed); for(i=0; i<=st->u.max;) { #if TEST > 1 bin_test(); #endif bl = &blocks[RANDOM(&ld, n_blocks)]; r = RANDOM(&ld, 1024); if(r < 200) { /* free only */ mutex_lock(&bl->mutex); for(b=0; b<BINS_PER_BLOCK; b++) bin_free(&bl->b[b]); mutex_unlock(&bl->mutex); i += BINS_PER_BLOCK; } else { /* alloc/realloc */ /* Generate random numbers in advance. */ for(b=0; b<BINS_PER_BLOCK; b++) { rsize[b] = RANDOM(&ld, st->u.size) + 1; rnum[b] = lran2(&ld); } mutex_lock(&bl->mutex); for(b=0; b<BINS_PER_BLOCK; b++) bin_alloc(&bl->b[b], rsize[b], rnum[b]); mutex_unlock(&bl->mutex); i += BINS_PER_BLOCK; } #if TEST > 2 bin_test(); #endif } }
void malloc_test(struct thread_st *st) { int b, i, j, actions, pid = 1; struct bin_info p; struct lran2_st ld; /* data for random number generator */ lran2_init(&ld, st->u.seed); #if TEST_FORK>0 if(RANDOM(&ld, TEST_FORK) == 0) { int status; #if !USE_THR pid = fork(); #else pid = fork1(); #endif if(pid > 0) { /*printf("forked, waiting for %d...\n", pid);*/ waitpid(pid, &status, 0); printf("done with %d...\n", pid); if(!WIFEXITED(status)) { printf("child term with signal %d\n", WTERMSIG(status)); exit(1); } return; } exit(0); } #endif p.m = (struct bin *)malloc(st->u.bins*sizeof(*p.m)); p.bins = st->u.bins; p.size = st->u.size; for(b=0; b<p.bins; b++) { p.m[b].size = 0; p.m[b].ptr = NULL; if(RANDOM(&ld, 2) == 0) bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld)); } for(i=0; i<=st->u.max;) { #if TEST > 1 bin_test(&p); #endif actions = RANDOM(&ld, ACTIONS_MAX); #if USE_MALLOC && MALLOC_DEBUG if(actions < 2) { mallinfo(); } #endif for(j=0; j<actions; j++) { b = RANDOM(&ld, p.bins); bin_free(&p.m[b]); } i += actions; actions = RANDOM(&ld, ACTIONS_MAX); for(j=0; j<actions; j++) { b = RANDOM(&ld, p.bins); bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld)); #if TEST > 2 bin_test(&p); #endif } #if 0 /* Test illegal free()s while setting MALLOC_CHECK_ */ for(j=0; j<8; j++) { b = RANDOM(&ld, p.bins); if(p.m[b].ptr) { int offset = (RANDOM(&ld, 11) - 5)*8; char *rogue = (char*)(p.m[b].ptr) + offset; /*printf("p=%p rogue=%p\n", p.m[b].ptr, rogue);*/ free(rogue); } } #endif i += actions; } for(b=0; b<p.bins; b++) bin_free(&p.m[b]); free(p.m); if(pid == 0) exit(0); }
int main(int argc, char *argv[]) { int i, j, bins; int n_thr=N_THREADS; int i_max=I_MAX; unsigned long size=SIZE; struct thread_st *st; #if USE_MALLOC && USE_STARTER==2 ptmalloc_init(); printf("ptmalloc_init\n"); #endif if(argc > 1) n_total_max = atoi(argv[1]); if(n_total_max < 1) n_thr = 1; if(argc > 2) n_thr = atoi(argv[2]); if(n_thr < 1) n_thr = 1; if(n_thr > 100) n_thr = 100; if(argc > 3) i_max = atoi(argv[3]); if(argc > 4) size = atol(argv[4]); if(size < 2) size = 2; bins = MEMORY/size; if(argc > 5) bins = atoi(argv[5]); if(bins < BINS_PER_BLOCK) bins = BINS_PER_BLOCK; n_blocks = bins/BINS_PER_BLOCK; blocks = (struct block *)malloc(n_blocks*sizeof(*blocks)); if(!blocks) exit(1); thread_init(); printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n", n_total_max, n_thr, i_max, size, n_blocks*BINS_PER_BLOCK); for(i=0; i<n_blocks; i++) { mutex_init(&blocks[i].mutex); for(j=0; j<BINS_PER_BLOCK; j++) blocks[i].b[j].size = 0; } st = (struct thread_st *)malloc(n_thr*sizeof(*st)); if(!st) exit(-1); #if !defined NO_THREADS && (defined __sun__ || defined sun) /* I know of no other way to achieve proper concurrency with Solaris. */ thr_setconcurrency(n_thr); #endif /* Start all n_thr threads. */ for(i=0; i<n_thr; i++) { st[i].u.max = i_max; st[i].u.size = size; st[i].u.seed = ((long)i_max*size + i) ^ n_blocks; st[i].sp = 0; st[i].func = malloc_test; if(thread_create(&st[i])) { printf("Creating thread #%d failed.\n", i); n_thr = i; break; } printf("Created thread %lx.\n", (long)st[i].id); } for(n_running=n_total=n_thr; n_running>0;) { wait_for_thread(st, n_thr, my_end_thread); } for(i=0; i<n_blocks; i++) { for(j=0; j<BINS_PER_BLOCK; j++) bin_free(&blocks[i].b[j]); } for(i=0; i<n_thr; i++) { free(st[i].sp); } free(st); free(blocks); #if USE_MALLOC malloc_stats(); #endif printf("Done.\n"); return 0; }
/** * Creates a snapshots of the dialogs data and then calls the dumping function. * @returns 1 on success or 0 on failure */ int make_snapshot_dialogs() { bin_data x={0,0,0}; p_dialog *d; int i,k; time_t unique = time(0); FILE *f; switch (pcscf_persistency_mode) { case NO_PERSISTENCY: return 0; case WITH_FILES: f = bin_dump_to_file_create(pcscf_persistency_location,"pdialogs",unique); if (!f) return 0; for(i=0;i<p_dialogs_hash_size;i++){ if (!bin_alloc(&x,1024)) goto error; d_lock(i); d = p_dialogs[i].head; if (d){ while(d){ if (!bin_encode_p_dialog(&x,d)) goto error; d = d->next; } d_unlock(i); k = bind_dump_to_file_append(f,&x); if (k!=x.len) { LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: error while dumping to file - only wrote %d bytes of %d \n",k,x.len); d_unlock(i); bin_free(&x); return 0; } } else d_unlock(i); bin_free(&x); } return bind_dump_to_file_close(f,pcscf_persistency_location,"pdialogs",unique); break; case WITH_DATABASE_BULK: if (!bin_alloc(&x,1024)) goto error; for(i=0;i<p_dialogs_hash_size;i++){ d_lock(i); d = p_dialogs[i].head; while(d){ if (!bin_encode_p_dialog(&x,d)) goto error; d = d->next; } d_unlock(i); } return bin_dump_to_db(&x, P_DIALOGS); case WITH_DATABASE_CACHE: return bin_dump_to_db(NULL, P_DIALOGS); //ignore x, x is empty default: LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: Snapshot done but no such mode %d\n",pcscf_persistency_mode); return 0; } error: if (x.s) bin_free(&x); return 0; }
/** * Loads the subscriptions data from the last snapshot. * @returns 1 on success or 0 on failure */ int load_snapshot_subscriptions() { bin_data x; r_subscription *s; int k,max; FILE *f; switch (pcscf_persistency_mode){ case NO_PERSISTENCY: k=0; case WITH_FILES: f = bin_load_from_file_open(pcscf_persistency_location,"psubscriptions"); if (!f) return 0; bin_alloc(&x,128*1024); k=bin_load_from_file_read(f,&x); max = x.max; x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: max %d len %d\n",x.max,x.len); while(x.max<x.len){ s = bin_decode_r_subscription(&x); if (!s) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: Loaded r_subscription for <%.*s>\n",s->req_uri.len,s->req_uri.s); subs_lock(s->hash); s->prev = subscriptions[s->hash].tail; s->next = 0; if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s; subscriptions[s->hash].tail = s; if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s; subs_unlock(s->hash); memmove(x.s,x.s+x.max,x.len-x.max); x.len = x.max; x.max = max; k=bin_load_from_file_read(f,&x); max = x.max; x.max = 0; } bin_free(&x); bin_load_from_file_close(f); k = 1; break; case WITH_DATABASE_BULK: k=bin_load_from_db(&x, P_SUBSCRIPTIONS); x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: max %d len %d\n",x.max,x.len); while(x.max<x.len){ s = bin_decode_r_subscription(&x); if (!s) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_subscriptions: Loaded r_subscription for <%.*s>\n",s->req_uri.len,s->req_uri.s); subs_lock(s->hash); s->prev = subscriptions[s->hash].tail; s->next = 0; if (subscriptions[s->hash].tail) subscriptions[s->hash].tail->next = s; subscriptions[s->hash].tail = s; if (!subscriptions[s->hash].head) subscriptions[s->hash].head = s; subs_unlock(s->hash); } bin_free(&x); break; case WITH_DATABASE_CACHE: k=bin_load_from_db(NULL, P_SUBSCRIPTIONS); //ignore x, x is empty break; default: LOG(L_ERR,"ERR:"M_NAME":load_snapshot_subscriptions: Can't resume because no such mode %d\n",pcscf_persistency_mode); k=0; } if (!k) goto error; return 1; error: return 0; }
/** * Loads the registrar data from the last snapshot. * @returns 1 on success or 0 on failure */ int load_snapshot_registrar() { bin_data x; r_contact *c; int k,max; FILE *f; switch (pcscf_persistency_mode){ case NO_PERSISTENCY: k=0; case WITH_FILES: f = bin_load_from_file_open(pcscf_persistency_location,"pregistrar"); if (!f) return 0; bin_alloc(&x,128*1024); k=bin_load_from_file_read(f,&x); max = x.max; x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: max %d len %d\n",x.max,x.len); while(x.max<x.len){ c = bin_decode_r_contact(&x); if (!c) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: Loaded r_contact for <%.*s>\n",c->uri.len,c->uri.s); r_lock(c->hash); c->prev = registrar[c->hash].tail; c->next = 0; if (registrar[c->hash].tail) registrar[c->hash].tail->next = c; registrar[c->hash].tail = c; if (!registrar[c->hash].head) registrar[c->hash].head = c; r_unlock(c->hash); memmove(x.s,x.s+x.max,x.len-x.max); x.len -= x.max; x.max = max; k=bin_load_from_file_read(f,&x); max = x.max; x.max = 0; } bin_free(&x); bin_load_from_file_close(f); k = 1; break; case WITH_DATABASE_BULK: k=bin_load_from_db(&x, P_REGISTRAR); x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: max %d len %d\n",x.max,x.len); while(x.max<x.len){ c = bin_decode_r_contact(&x); if (!c) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: Loaded r_contact for <%.*s>\n",c->uri.len,c->uri.s); r_lock(c->hash); c->prev = registrar[c->hash].tail; c->next = 0; if (registrar[c->hash].tail) registrar[c->hash].tail->next = c; registrar[c->hash].tail = c; if (!registrar[c->hash].head) registrar[c->hash].head = c; r_unlock(c->hash); } bin_free(&x); break; case WITH_DATABASE_CACHE: k=bin_load_from_db(NULL, P_REGISTRAR); //ignore x, x is empty break; default: LOG(L_ERR,"ERR:"M_NAME":load_snapshot_registrar: Can't resume because no such mode %d\n",pcscf_persistency_mode); k=0; } if (!k) goto error; return 1; error: return 0; }
/** * Loads the dialogs data from the last snapshot. * @returns 1 on success or 0 on failure */ int load_snapshot_dialogs() { bin_data x; p_dialog *d; int k,max; FILE *f; switch (pcscf_persistency_mode){ case NO_PERSISTENCY: k=0; case WITH_FILES: f = bin_load_from_file_open(pcscf_persistency_location,"pdialogs"); if (!f) return 0; bin_alloc(&x,128*1024); k=bin_load_from_file_read(f,&x); max = x.max; x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: max %d len %d\n",x.max,x.len); while(x.max<x.len){ d = bin_decode_p_dialog(&x); if (!d) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: Loaded p_dialog for <%.*s>\n",d->host.len,d->host.s); d_lock(d->hash); d->prev = p_dialogs[d->hash].tail; d->next = 0; if (p_dialogs[d->hash].tail) p_dialogs[d->hash].tail->next = d; p_dialogs[d->hash].tail = d; if (!p_dialogs[d->hash].head) p_dialogs[d->hash].head = d; d_unlock(d->hash); memmove(x.s,x.s+x.max,x.len-x.max); x.len -= x.max; x.max = max; k=bin_load_from_file_read(f,&x); max = x.max; x.max = 0; } bin_free(&x); bin_load_from_file_close(f); k = 1; break; case WITH_DATABASE_BULK: k=bin_load_from_db(&x, P_DIALOGS); x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: max %d len %d\n",x.max,x.len); while(x.max<x.len){ d = bin_decode_p_dialog(&x); if (!d) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: Loaded p_dialog for <%.*s>\n",d->host.len,d->host.s); d_lock(d->hash); d->prev = p_dialogs[d->hash].tail; d->next = 0; if (p_dialogs[d->hash].tail) p_dialogs[d->hash].tail->next = d; p_dialogs[d->hash].tail = d; if (!p_dialogs[d->hash].head) p_dialogs[d->hash].head = d; d_unlock(d->hash); } bin_free(&x); break; case WITH_DATABASE_CACHE: k=bin_load_from_db(NULL, P_DIALOGS); //ignore x, x is empty break; default: LOG(L_ERR,"ERR:"M_NAME":load_snapshot_dialogs: Can't resume because no such mode %d\n",pcscf_persistency_mode); k=0; } if (!k) goto error; return 1; error: return 0; }