1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 AT&T Intellectual Property * 5* and is licensed under the * 6* Common Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.opensource.org/licenses/cpl1.0.txt * 11* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12* * 13* Information and Software Systems Research * 14* AT&T Research * 15* Florham Park NJ * 16* * 17* Glenn Fowler <gsf@research.att.com> * 18* David Korn <dgk@research.att.com> * 19* Phong Vo <kpv@research.att.com> * 20* * 21***********************************************************************/ 22#if defined(_UWIN) && defined(_BLD_ast) 23 24void _STUB_vmdebug(){} 25 26#else 27 28#include "vmhdr.h" 29 30/* Method to help with debugging. This does rigorous checks on 31** addresses and arena integrity. 32** 33** Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94. 34*/ 35 36/* structure to keep track of file names */ 37typedef struct _dbfile_s Dbfile_t; 38struct _dbfile_s 39{ Dbfile_t* next; 40 char file[1]; 41}; 42static Dbfile_t* Dbfile; 43 44/* global watch list */ 45#define S_WATCH 32 46static int Dbnwatch; 47static Void_t* Dbwatch[S_WATCH]; 48 49/* types of warnings reported by dbwarn() */ 50#define DB_CHECK 0 51#define DB_ALLOC 1 52#define DB_FREE 2 53#define DB_RESIZE 3 54#define DB_WATCH 4 55#define DB_RESIZED 5 56 57#define LONGV(x) ((Vmulong_t)(x)) 58 59static int Dbinit = 0; 60#define DBINIT() (Dbinit ? 0 : (dbinit(), Dbinit=1) ) 61static void dbinit() 62{ int fd; 63 if((fd = vmtrace(-1)) >= 0) 64 vmtrace(fd); 65} 66 67static int Dbfd = 2; /* default warning file descriptor */ 68#if __STD_C 69int vmdebug(int fd) 70#else 71int vmdebug(fd) 72int fd; 73#endif 74{ 75 int old = Dbfd; 76 Dbfd = fd; 77 return old; 78} 79 80/* just an entry point to make it easy to set break point */ 81#if __STD_C 82static void vmdbwarn(Vmalloc_t* vm, char* mesg, int n) 83#else 84static void vmdbwarn(vm, mesg, n) 85Vmalloc_t* vm; 86char* mesg; 87int n; 88#endif 89{ 90 reg Vmdata_t* vd = vm->data; 91 92 write(Dbfd,mesg,n); 93 if(vd->mode&VM_DBABORT) 94 abort(); 95} 96 97/* issue a warning of some type */ 98#if __STD_C 99static void dbwarn(Vmalloc_t* vm, Void_t* data, int where, 100 const char* file, int line, const Void_t* func, int type) 101#else 102static void dbwarn(vm, data, where, file, line, func, type) 103Vmalloc_t* vm; /* region holding the block */ 104Void_t* data; /* data block */ 105int where; /* byte that was corrupted */ 106const char* file; /* file where call originates */ 107int line; /* line number of call */ 108const Void_t* func; /* function called from */ 109int type; /* operation being done */ 110#endif 111{ 112 char buf[1024], *bufp, *endbuf, *s; 113#define SLOP 64 /* enough for a message and an int */ 114 115 DBINIT(); 116 117 bufp = buf; 118 endbuf = buf + sizeof(buf); 119 120 if(type == DB_ALLOC) 121 bufp = (*_Vmstrcpy)(bufp, "alloc error", ':'); 122 else if(type == DB_FREE) 123 bufp = (*_Vmstrcpy)(bufp, "free error", ':'); 124 else if(type == DB_RESIZE) 125 bufp = (*_Vmstrcpy)(bufp, "resize error", ':'); 126 else if(type == DB_CHECK) 127 bufp = (*_Vmstrcpy)(bufp, "corrupted data", ':'); 128 else if(type == DB_WATCH) 129 bufp = (*_Vmstrcpy)(bufp, "alert", ':'); 130 131 /* region info */ 132 bufp = (*_Vmstrcpy)(bufp, "region", '='); 133 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(vm), 0), ':'); 134 135 if(data) 136 { bufp = (*_Vmstrcpy)(bufp,"block",'='); 137 bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(VLONG(data),0),':'); 138 } 139 140 if(!data) 141 { if(where == DB_ALLOC) 142 bufp = (*_Vmstrcpy)(bufp, "can't get memory", ':'); 143 else bufp = (*_Vmstrcpy)(bufp, "region is locked", ':'); 144 } 145 else if(type == DB_FREE || type == DB_RESIZE) 146 { if(where == 0) 147 bufp = (*_Vmstrcpy)(bufp, "unallocated block", ':'); 148 else bufp = (*_Vmstrcpy)(bufp, "already freed", ':'); 149 } 150 else if(type == DB_WATCH) 151 { bufp = (*_Vmstrcpy)(bufp, "size", '='); 152 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(DBSIZE(data),-1), ':'); 153 if(where == DB_ALLOC) 154 bufp = (*_Vmstrcpy)(bufp,"just allocated", ':'); 155 else if(where == DB_FREE) 156 bufp = (*_Vmstrcpy)(bufp,"being freed", ':'); 157 else if(where == DB_RESIZE) 158 bufp = (*_Vmstrcpy)(bufp,"being resized", ':'); 159 else if(where == DB_RESIZED) 160 bufp = (*_Vmstrcpy)(bufp,"just resized", ':'); 161 } 162 else if(type == DB_CHECK) 163 { bufp = (*_Vmstrcpy)(bufp, "bad byte at", '='); 164 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(where),-1), ':'); 165 if((s = DBFILE(data)) && (bufp + strlen(s) + SLOP) < endbuf) 166 { bufp = (*_Vmstrcpy)(bufp,"allocated at", '='); 167 bufp = (*_Vmstrcpy)(bufp, s, ','); 168 bufp = (*_Vmstrcpy)(bufp,(*_Vmitoa)(LONGV(DBLINE(data)),-1),':'); 169 } 170 } 171 172 /* location where offending call originates from */ 173 if(file && file[0] && line > 0 && (bufp + strlen(file) + SLOP) < endbuf) 174 { bufp = (*_Vmstrcpy)(bufp, "detected at", '='); 175 bufp = (*_Vmstrcpy)(bufp, file, ','); 176 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(LONGV(line),-1), ','); 177 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(func),-1), ':'); 178 } 179 180 *(bufp - 1) = '\n'; 181 *bufp = '\0'; 182 183 vmdbwarn(vm,buf,(bufp-buf)); 184} 185 186/* check for watched address and issue warnings */ 187#if __STD_C 188static void dbwatch(Vmalloc_t* vm, Void_t* data, 189 const char* file, int line, const Void_t* func, int type) 190#else 191static void dbwatch(vm, data, file, line, func, type) 192Vmalloc_t* vm; 193Void_t* data; 194const char* file; 195int line; 196const Void_t* func; 197int type; 198#endif 199{ 200 reg int n; 201 202 for(n = Dbnwatch; n >= 0; --n) 203 { if(Dbwatch[n] == data) 204 { dbwarn(vm,data,type,file,line,func,DB_WATCH); 205 return; 206 } 207 } 208} 209 210/* record information about the block */ 211#if __STD_C 212static void dbsetinfo(Vmuchar_t* data, size_t size, const char* file, int line) 213#else 214static void dbsetinfo(data, size, file, line) 215Vmuchar_t* data; /* real address not the one from Vmbest */ 216size_t size; /* the actual requested size */ 217const char* file; /* file where the request came from */ 218int line; /* and line number */ 219#endif 220{ 221 reg Vmuchar_t *begp, *endp; 222 reg Dbfile_t *last, *db; 223 224 DBINIT(); 225 226 /* find the file structure */ 227 if(!file || !file[0]) 228 db = NIL(Dbfile_t*); 229 else 230 { for(last = NIL(Dbfile_t*), db = Dbfile; db; last = db, db = db->next) 231 if(strcmp(db->file,file) == 0) 232 break; 233 if(!db) 234 { db = (Dbfile_t*)vmalloc(Vmheap,sizeof(Dbfile_t)+strlen(file)); 235 if(db) 236 { (*_Vmstrcpy)(db->file,file,0); 237 db->next = Dbfile; 238 Dbfile = db->next; 239 } 240 } 241 else if(last) /* move-to-front heuristic */ 242 { last->next = db->next; 243 db->next = Dbfile; 244 Dbfile = db->next; 245 } 246 } 247 248 DBSETFL(data,(db ? db->file : NIL(char*)),line); 249 DBSIZE(data) = size; 250 DBSEG(data) = SEG(DBBLOCK(data)); 251 252 DBHEAD(data,begp,endp); 253 while(begp < endp) 254 *begp++ = DB_MAGIC; 255 DBTAIL(data,begp,endp); 256 while(begp < endp) 257 *begp++ = DB_MAGIC; 258} 259 260/* Check to see if an address is in some data block of a region. 261** This returns -(offset+1) if block is already freed, +(offset+1) 262** if block is live, 0 if no match. 263*/ 264#if __STD_C 265static long dbaddr(Vmalloc_t* vm, Void_t* addr) 266#else 267static long dbaddr(vm, addr) 268Vmalloc_t* vm; 269Void_t* addr; 270#endif 271{ 272 reg Block_t *b, *endb; 273 reg Seg_t* seg; 274 reg Vmuchar_t* data; 275 reg long offset = -1L; 276 reg Vmdata_t* vd = vm->data; 277 reg int local, inuse; 278 279 SETINUSE(vd, inuse); 280 GETLOCAL(vd,local); 281 if(ISLOCK(vd,local) || !addr) 282 { CLRINUSE(vd, inuse); 283 return -1L; 284 } 285 SETLOCK(vd,local); 286 287 b = endb = NIL(Block_t*); 288 for(seg = vd->seg; seg; seg = seg->next) 289 { b = SEGBLOCK(seg); 290 endb = (Block_t*)(seg->baddr - sizeof(Head_t)); 291 if((Vmuchar_t*)addr > (Vmuchar_t*)b && 292 (Vmuchar_t*)addr < (Vmuchar_t*)endb) 293 break; 294 } 295 if(!seg) 296 goto done; 297 298 if(local) /* must be vmfree or vmresize checking address */ 299 { if(DBSEG(addr) == seg) 300 { b = DBBLOCK(addr); 301 if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) ) 302 offset = 0; 303 else offset = -2L; 304 } 305 goto done; 306 } 307 308 while(b < endb) 309 { data = (Vmuchar_t*)DATA(b); 310 if((Vmuchar_t*)addr >= data && (Vmuchar_t*)addr < data+SIZE(b)) 311 { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) ) 312 { data = DB2DEBUG(data); 313 if((Vmuchar_t*)addr >= data && 314 (Vmuchar_t*)addr < data+DBSIZE(data)) 315 offset = (Vmuchar_t*)addr - data; 316 } 317 goto done; 318 } 319 320 b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) ); 321 } 322 323done: 324 CLRLOCK(vd,local); 325 CLRINUSE(vd, inuse); 326 return offset; 327} 328 329 330#if __STD_C 331static long dbsize(Vmalloc_t* vm, Void_t* addr) 332#else 333static long dbsize(vm, addr) 334Vmalloc_t* vm; 335Void_t* addr; 336#endif 337{ 338 reg Block_t *b, *endb; 339 reg Seg_t* seg; 340 reg long size; 341 reg Vmdata_t* vd = vm->data; 342 reg int inuse; 343 344 SETINUSE(vd, inuse); 345 if(ISLOCK(vd,0)) 346 { CLRINUSE(vd, inuse); 347 return -1L; 348 } 349 SETLOCK(vd,0); 350 351 size = -1L; 352 for(seg = vd->seg; seg; seg = seg->next) 353 { b = SEGBLOCK(seg); 354 endb = (Block_t*)(seg->baddr - sizeof(Head_t)); 355 if((Vmuchar_t*)addr <= (Vmuchar_t*)b || 356 (Vmuchar_t*)addr >= (Vmuchar_t*)endb) 357 continue; 358 while(b < endb) 359 { if(addr == (Void_t*)DB2DEBUG(DATA(b))) 360 { if(ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) ) 361 size = (long)DBSIZE(addr); 362 goto done; 363 } 364 365 b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) ); 366 } 367 } 368done: 369 CLRLOCK(vd,0); 370 CLRINUSE(vd, inuse); 371 return size; 372} 373 374#if __STD_C 375static Void_t* dballoc(Vmalloc_t* vm, size_t size) 376#else 377static Void_t* dballoc(vm, size) 378Vmalloc_t* vm; 379size_t size; 380#endif 381{ 382 reg size_t s; 383 reg Vmuchar_t* data; 384 reg char* file; 385 reg int line; 386 reg Void_t* func; 387 reg Vmdata_t* vd = vm->data; 388 reg int inuse; 389 390 SETINUSE(vd, inuse); 391 VMFLF(vm,file,line,func); 392 393 if(ISLOCK(vd,0) ) 394 { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_ALLOC); 395 CLRINUSE(vd, inuse); 396 return NIL(Void_t*); 397 } 398 SETLOCK(vd,0); 399 400 if(vd->mode&VM_DBCHECK) 401 vmdbcheck(vm); 402 403 s = ROUND(size,ALIGN) + DB_EXTRA; 404 if(s < sizeof(Body_t)) /* no tiny blocks during Vmdebug */ 405 s = sizeof(Body_t); 406 407 if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,(*(Vmbest->allocf))) ) ) 408 { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_ALLOC); 409 goto done; 410 } 411 412 data = DB2DEBUG(data); 413 dbsetinfo(data,size,file,line); 414 415 if((vd->mode&VM_TRACE) && _Vmtrace) 416 { vm->file = file; vm->line = line; vm->func = func; 417 (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,0); 418 } 419 420 if(Dbnwatch > 0 ) 421 dbwatch(vm,data,file,line,func,DB_ALLOC); 422 423done: 424 CLRLOCK(vd,0); 425 ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc); 426 CLRINUSE(vd, inuse); 427 return (Void_t*)data; 428} 429 430 431#if __STD_C 432static int dbfree(Vmalloc_t* vm, Void_t* data ) 433#else 434static int dbfree(vm, data ) 435Vmalloc_t* vm; 436Void_t* data; 437#endif 438{ 439 char* file; 440 int line; 441 Void_t* func; 442 reg long offset; 443 reg int rv, *ip, *endip; 444 reg Vmdata_t* vd = vm->data; 445 reg int inuse; 446 447 SETINUSE(vd, inuse); 448 VMFLF(vm,file,line,func); 449 450 if(!data) 451 { CLRINUSE(vd, inuse); 452 return 0; 453 } 454 455 if(ISLOCK(vd,0) ) 456 { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_FREE); 457 CLRINUSE(vd, inuse); 458 return -1; 459 } 460 SETLOCK(vd,0); 461 462 if(vd->mode&VM_DBCHECK) 463 vmdbcheck(vm); 464 465 if((offset = KPVADDR(vm,data,dbaddr)) != 0) 466 { dbwarn(vm,(Vmuchar_t*)data,offset == -1L ? 0 : 1,file,line,func,DB_FREE); 467 if(vm->disc->exceptf) 468 (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc); 469 CLRLOCK(vd,0); 470 CLRINUSE(vd, inuse); 471 return -1; 472 } 473 474 if(Dbnwatch > 0) 475 dbwatch(vm,data,file,line,func,DB_FREE); 476 477 if((vd->mode&VM_TRACE) && _Vmtrace) 478 { vm->file = file; vm->line = line; vm->func = func; 479 (*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),DBSIZE(data),0); 480 } 481 482 /* clear free space */ 483 ip = (int*)data; 484 endip = ip + (DBSIZE(data)+sizeof(int)-1)/sizeof(int); 485 while(ip < endip) 486 *ip++ = 0; 487 488 rv = KPVFREE((vm), (Void_t*)DB2BEST(data), (*Vmbest->freef)); 489 CLRLOCK(vd,0); 490 ANNOUNCE(0, vm, VM_FREE, data, vm->disc); 491 CLRINUSE(vd, inuse); 492 return rv; 493} 494 495/* Resizing an existing block */ 496#if __STD_C 497static Void_t* dbresize(Vmalloc_t* vm, Void_t* addr, reg size_t size, int type) 498#else 499static Void_t* dbresize(vm,addr,size,type) 500Vmalloc_t* vm; /* region allocating from */ 501Void_t* addr; /* old block of data */ 502reg size_t size; /* new size */ 503int type; /* !=0 for movable, >0 for copy */ 504#endif 505{ 506 reg Vmuchar_t* data; 507 reg size_t s, oldsize; 508 reg long offset; 509 char *file, *oldfile; 510 int line, oldline; 511 Void_t* func; 512 reg Vmdata_t* vd = vm->data; 513 reg int inuse; 514 515 SETINUSE(vd, inuse); 516 if(!addr) 517 { oldsize = 0; 518 data = (Vmuchar_t*)dballoc(vm,size); 519 goto done; 520 } 521 if(size == 0) 522 { (void)dbfree(vm,addr); 523 CLRINUSE(vd, inuse); 524 return NIL(Void_t*); 525 } 526 527 VMFLF(vm,file,line,func); 528 529 if(ISLOCK(vd,0) ) 530 { dbwarn(vm,NIL(Vmuchar_t*),0,file,line,func,DB_RESIZE); 531 CLRINUSE(vd, inuse); 532 return NIL(Void_t*); 533 } 534 SETLOCK(vd,0); 535 536 if(vd->mode&VM_DBCHECK) 537 vmdbcheck(vm); 538 539 if((offset = KPVADDR(vm,addr,dbaddr)) != 0) 540 { dbwarn(vm,(Vmuchar_t*)addr,offset == -1L ? 0 : 1,file,line,func,DB_RESIZE); 541 if(vm->disc->exceptf) 542 (void)(*vm->disc->exceptf)(vm,VM_BADADDR,addr,vm->disc); 543 CLRLOCK(vd,0); 544 CLRINUSE(vd, inuse); 545 return NIL(Void_t*); 546 } 547 548 if(Dbnwatch > 0) 549 dbwatch(vm,addr,file,line,func,DB_RESIZE); 550 551 /* Vmbest data block */ 552 data = DB2BEST(addr); 553 oldsize = DBSIZE(addr); 554 oldfile = DBFILE(addr); 555 oldline = DBLINE(addr); 556 557 /* do the resize */ 558 s = ROUND(size,ALIGN) + DB_EXTRA; 559 if(s < sizeof(Body_t)) 560 s = sizeof(Body_t); 561 data = (Vmuchar_t*)KPVRESIZE(vm,(Void_t*)data,s, 562 (type&~VM_RSZERO),(*(Vmbest->resizef)) ); 563 if(!data) /* failed, reset data for old block */ 564 { dbwarn(vm,NIL(Vmuchar_t*),DB_ALLOC,file,line,func,DB_RESIZE); 565 dbsetinfo((Vmuchar_t*)addr,oldsize,oldfile,oldline); 566 } 567 else 568 { data = DB2DEBUG(data); 569 dbsetinfo(data,size,file,line); 570 571 if((vd->mode&VM_TRACE) && _Vmtrace) 572 { vm->file = file; vm->line = line; 573 (*_Vmtrace)(vm,(Vmuchar_t*)addr,data,size,0); 574 } 575 if(Dbnwatch > 0) 576 dbwatch(vm,data,file,line,func,DB_RESIZED); 577 } 578 579 CLRLOCK(vd,0); 580 ANNOUNCE(0, vm, VM_RESIZE, (Void_t*)data, vm->disc); 581 582done: if(data && (type&VM_RSZERO) && size > oldsize) 583 { reg Vmuchar_t *d = data+oldsize, *ed = data+size; 584 do { *d++ = 0; } while(d < ed); 585 } 586 CLRINUSE(vd, inuse); 587 return (Void_t*)data; 588} 589 590/* compact any residual free space */ 591#if __STD_C 592static int dbcompact(Vmalloc_t* vm) 593#else 594static int dbcompact(vm) 595Vmalloc_t* vm; 596#endif 597{ 598 return (*(Vmbest->compactf))(vm); 599} 600 601/* check for memory overwrites over all live blocks */ 602#if __STD_C 603int vmdbcheck(Vmalloc_t* vm) 604#else 605int vmdbcheck(vm) 606Vmalloc_t* vm; 607#endif 608{ 609 reg Block_t *b, *endb; 610 reg Seg_t* seg; 611 int rv; 612 reg Vmdata_t* vd = vm->data; 613 614 /* check the meta-data of this region */ 615 if(vd->mode & (VM_MTDEBUG|VM_MTBEST|VM_MTPROFILE)) 616 { if(_vmbestcheck(vd, NIL(Block_t*)) < 0) 617 return -1; 618 if(!(vd->mode&VM_MTDEBUG)) 619 return 0; 620 } 621 else return -1; 622 623 rv = 0; 624 for(seg = vd->seg; seg; seg = seg->next) 625 { b = SEGBLOCK(seg); 626 endb = (Block_t*)(seg->baddr - sizeof(Head_t)); 627 while(b < endb) 628 { reg Vmuchar_t *data, *begp, *endp; 629 630 if(ISJUNK(SIZE(b)) || !ISBUSY(SIZE(b))) 631 goto next; 632 633 data = DB2DEBUG(DATA(b)); 634 if(DBISBAD(data)) /* seen this before */ 635 { rv += 1; 636 goto next; 637 } 638 639 DBHEAD(data,begp,endp); 640 for(; begp < endp; ++begp) 641 if(*begp != DB_MAGIC) 642 goto set_bad; 643 644 DBTAIL(data,begp,endp); 645 for(; begp < endp; ++begp) 646 { if(*begp == DB_MAGIC) 647 continue; 648 set_bad: 649 dbwarn(vm,data,begp-data,NIL(char*),0,0,DB_CHECK); 650 DBSETBAD(data); 651 rv += 1; 652 goto next; 653 } 654 655 next: b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS)); 656 } 657 } 658 659 return rv; 660} 661 662/* set/delete an address to watch */ 663#if __STD_C 664Void_t* vmdbwatch(Void_t* addr) 665#else 666Void_t* vmdbwatch(addr) 667Void_t* addr; /* address to insert */ 668#endif 669{ 670 reg int n; 671 reg Void_t* out; 672 673 out = NIL(Void_t*); 674 if(!addr) 675 Dbnwatch = 0; 676 else 677 { for(n = Dbnwatch - 1; n >= 0; --n) 678 if(Dbwatch[n] == addr) 679 break; 680 if(n < 0) /* insert */ 681 { if(Dbnwatch == S_WATCH) 682 { /* delete left-most */ 683 out = Dbwatch[0]; 684 Dbnwatch -= 1; 685 for(n = 0; n < Dbnwatch; ++n) 686 Dbwatch[n] = Dbwatch[n+1]; 687 } 688 Dbwatch[Dbnwatch] = addr; 689 Dbnwatch += 1; 690 } 691 } 692 return out; 693} 694 695#if __STD_C 696static Void_t* dbalign(Vmalloc_t* vm, size_t size, size_t align) 697#else 698static Void_t* dbalign(vm, size, align) 699Vmalloc_t* vm; 700size_t size; 701size_t align; 702#endif 703{ 704 reg Vmuchar_t* data; 705 reg size_t s; 706 reg char* file; 707 reg int line; 708 reg Void_t* func; 709 reg Vmdata_t* vd = vm->data; 710 reg int inuse; 711 712 SETINUSE(vd, inuse); 713 VMFLF(vm,file,line,func); 714 715 if(size <= 0 || align <= 0) 716 { CLRINUSE(vd, inuse); 717 return NIL(Void_t*); 718 } 719 720 if(ISLOCK(vd,0) ) 721 { CLRINUSE(vd, inuse); 722 return NIL(Void_t*); 723 } 724 SETLOCK(vd,0); 725 726 if((s = ROUND(size,ALIGN) + DB_EXTRA) < sizeof(Body_t)) 727 s = sizeof(Body_t); 728 729 if(!(data = (Vmuchar_t*)KPVALIGN(vm,s,align,(*(Vmbest->alignf)))) ) 730 goto done; 731 732 data += DB_HEAD; 733 dbsetinfo(data,size,file,line); 734 735 if((vd->mode&VM_TRACE) && _Vmtrace) 736 { vm->file = file; vm->line = line; vm->func = func; 737 (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,size,align); 738 } 739 740done: 741 CLRLOCK(vd,0); 742 ANNOUNCE(0, vm, VM_ALLOC, (Void_t*)data, vm->disc); 743 CLRINUSE(vd, inuse); 744 return (Void_t*)data; 745} 746 747/* print statistics of region vm. If vm is NULL, use Vmregion */ 748#if __STD_C 749ssize_t vmdbstat(Vmalloc_t* vm) 750#else 751ssize_t vmdbstat(vm) 752Vmalloc_t* vm; 753#endif 754{ Vmstat_t st; 755 char buf[1024], *bufp; 756 757 vmstat(vm ? vm : Vmregion, &st); 758 bufp = buf; 759 bufp = (*_Vmstrcpy)(bufp, "n_busy", '='); 760 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_busy,-1), ','); 761 bufp = (*_Vmstrcpy)(bufp, " s_busy", '='); 762 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_busy),-1), '\n'); 763 bufp = (*_Vmstrcpy)(bufp, "n_free", '='); 764 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_free,-1), ','); 765 bufp = (*_Vmstrcpy)(bufp, " s_free", '='); 766 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.s_free),-1), '\n'); 767 bufp = (*_Vmstrcpy)(bufp, "m_busy", '='); 768 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_busy),-1), ','); 769 bufp = (*_Vmstrcpy)(bufp, " m_free", '='); 770 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.m_free),-1), '\n'); 771 bufp = (*_Vmstrcpy)(bufp, "n_segment", '='); 772 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)((Vmulong_t)st.n_seg,-1), ','); 773 bufp = (*_Vmstrcpy)(bufp, " extent", '='); 774 bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(st.extent),-1), '\n'); 775 *bufp = 0; 776 write(Dbfd, buf, strlen(buf)); 777 return strlen(buf); 778} 779 780static Vmethod_t _Vmdebug = 781{ 782 dballoc, 783 dbresize, 784 dbfree, 785 dbaddr, 786 dbsize, 787 dbcompact, 788 dbalign, 789 VM_MTDEBUG 790}; 791 792__DEFINE__(Vmethod_t*,Vmdebug,&_Vmdebug); 793 794#ifdef NoF 795NoF(vmdebug) 796#endif 797 798#endif 799