alloc.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:13k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /* memory allocation routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Adapted from alloc routine in K&R; memory statistics and interrupt
  5.  * protection added for use with net package. Must be used in place of
  6.  * standard Turbo-C library routines because the latter check for stack/heap
  7.  * collisions. This causes erroneous failures because process stacks are
  8.  * allocated off the heap.
  9.  */
  10. #include <stdio.h>
  11. #include <dos.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "proc.h"
  15. #include "cmdparse.h"
  16. static unsigned long Memfail; /* Count of allocation failures */
  17. static unsigned long Allocs; /* Total allocations */
  18. static unsigned long Frees; /* Total frees */
  19. static unsigned long Invalid; /* Total calls to free with garbage arg */
  20. static int Memwait; /* Number of tasks waiting for memory */
  21. static unsigned long Yellows; /* Yellow alert garbage collections */
  22. static unsigned long Reds; /* Red alert garbage collections */
  23. unsigned long Availmem; /* Heap memory, ABLKSIZE units */
  24. static unsigned long Morecores;
  25. static int Memdebug;
  26. static unsigned long Sizes[16];
  27. /* This debugging pattern MUST be exactly equal in size to the "header"
  28.  * union defined later
  29.  */
  30. static char Debugpat[] = { 0xfe,0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef };
  31. static int domdebug(int argc,char *argv[],void *ptr);
  32. static int dostat(int argc,char *argv[],void *p);
  33. static int dofreelist(int argc,char *argv[],void *p);
  34. static int dothresh(int argc,char *argv[],void *p);
  35. static int dosizes(int argc,char *argv[],void *p);
  36. struct cmds Memcmds[] = {
  37. "debug", domdebug, 0, 0, NULL,
  38. "freelist", dofreelist, 0, 0, NULL,
  39. "sizes", dosizes, 0, 0, NULL,
  40. "status", dostat, 0, 0, NULL,
  41. "thresh", dothresh, 0, 0, NULL,
  42. NULL,
  43. };
  44. #ifdef LARGEDATA
  45. #define HUGE huge
  46. #else
  47. #define HUGE
  48. #endif
  49. union header {
  50. struct {
  51. union header HUGE *ptr;
  52. unsigned long size;
  53. } s;
  54. char c[8]; /* For debugging; also ensure size is 8 bytes */
  55. };
  56. typedef union header HEADER;
  57. #define ABLKSIZE (sizeof (HEADER))
  58. #define BTOU(nb) ((((nb) + ABLKSIZE - 1) / ABLKSIZE) + 1)
  59. static HEADER HUGE *morecore(unsigned nu);
  60. static HEADER Base;
  61. static HEADER HUGE *Allocp = NULL;
  62. static unsigned long Heapsize;
  63. /* Memory blocks obtained from MS-DOS by allocmem() call */
  64. struct sysblock {
  65. unsigned seg;
  66. unsigned npar;
  67. };
  68. #define NSYSBLOCK 5
  69. struct sysblock Sysblock[NSYSBLOCK];
  70. /* Allocate block of 'nb' bytes */
  71. void *
  72. malloc(nb)
  73. size_t nb;
  74. {
  75. int i;
  76. int i_state;
  77. register HEADER HUGE *p, HUGE *q;
  78. register unsigned nu;
  79. if(nb == 0)
  80. return NULL;
  81. Allocs++;
  82. /* Record the size of this request */
  83. if((i = ilog2(nb)) >= 0)
  84. Sizes[i]++;
  85. /* Round up to full block, then add one for header */
  86. nu = BTOU(nb);
  87. i_state = dirps();
  88. /* Initialize heap pointers if necessary */
  89. if((q = Allocp) == NULL){
  90. Base.s.ptr = Allocp = q = &Base;
  91. Base.s.size = 1;
  92. }
  93. /* Search heap list */
  94. for(p = q->s.ptr; ; q = p, p = p->s.ptr){
  95. if(p->s.size >= nu){
  96. /* This chunk is at least as large as we need */
  97. if(p->s.size <= nu + 1){
  98. /* This is either a perfect fit (size == nu)
  99.  * or the free chunk is just one unit larger.
  100.  * In either case, alloc the whole thing,
  101.  * because there's no point in keeping a free
  102.  * block only large enough to hold the header.
  103.  */
  104. q->s.ptr = p->s.ptr;
  105. } else {
  106. /* Carve out piece from end of entry */
  107. p->s.size -= nu;
  108. p += p->s.size;
  109. p->s.size = nu;
  110. }
  111. #ifdef circular
  112. Allocp = q;
  113. #endif
  114. p->s.ptr = p; /* for auditing */
  115. Availmem -= p->s.size;
  116. p++;
  117. break;
  118. }
  119. /* We've searched all the way around the list without
  120.  * finding anything. Try to get more core from the system,
  121.  * unless we're in an interrupt handler
  122.  */
  123. if(p == Allocp && (!i_state || (p = morecore(nu)) == NULL)){
  124. p = NULL;
  125. Memfail++;
  126. break;
  127. }
  128. }
  129. restore(i_state);
  130. #ifdef LARGEDATA
  131. /* On the brain-damaged Intel CPUs in "large data" model,
  132.  * make sure the pointer's offset field isn't null
  133.  * (unless the entire pointer is null).
  134.  * The Turbo C compiler and certain
  135.  * library functions like strrchr() assume this.
  136.  */
  137. if(FP_OFF(p) == 0 && FP_SEG(p) != 0){
  138. /* Return denormalized but equivalent pointer */
  139. return (void *)MK_FP(FP_SEG(p)-1,16);
  140. }
  141. #endif
  142. return (void *)p;
  143. }
  144. /* Get more memory from the system and put it on the heap */
  145. static HEADER HUGE *
  146. morecore(nu)
  147. unsigned nu;
  148. {
  149. char HUGE *cp;
  150. HEADER HUGE *up;
  151. unsigned size;
  152. unsigned segp;
  153. unsigned npar;
  154. struct sysblock *sp;
  155. int i;
  156. void *sbrk(int); /***/
  157. Morecores++;
  158. size = nu * ABLKSIZE;
  159. /* First try to expand our main memory block */
  160. if((int)(cp = (char HUGE *)sbrk(size)) != -1){
  161. up = (HEADER *)cp;
  162. up->s.size = nu;
  163. up->s.ptr = up; /* satisfy audit */
  164. free(up + 1);
  165. Heapsize += size;
  166. Frees--; /* Nullify increment inside free() */
  167. return Allocp;
  168. }
  169. #ifndef __GNUC__
  170. /* That failed; the main memory block must have grown into another
  171.  * allocated block, or something else (e.g., the increase handles
  172.  * call in ioinit()) must have allocated memory just beyond it.
  173.  * Allocate or extend an additional memory block.
  174.  */
  175. npar = (size+16)/16; /* Convert size from bytes to paragraphs */
  176. cp = NULL;
  177. for(sp=Sysblock,i=0;i < NSYSBLOCK;i++,sp++){
  178. if(sp->npar != 0){
  179. /* Try to expand this block */
  180. if(setblock(sp->seg,sp->npar + npar) != -1){
  181. /* Failed (-1 == SUCCESS; strange!) */
  182. continue;
  183. }
  184. /* Block expansion succeeded */
  185. cp = MK_FP(sp->seg + sp->npar,0);
  186. sp->npar += npar;
  187. } else {
  188. /* Allocate new block */
  189. if(allocmem(npar,&segp) != -1){
  190. return NULL; /* Complete failure */
  191. }
  192. /* -1 indicates SUCCESS (strange) */
  193. sp->seg = segp;
  194. sp->npar = npar;
  195. cp = MK_FP(segp,0);
  196. }
  197. break;
  198. }
  199. if(cp != (char HUGE *)NULL){
  200. /* Expand or create succeeded, add to heap */
  201. up = (HEADER *)cp;
  202. up->s.size = (npar*16)/ABLKSIZE;
  203. up->s.ptr = up; /* satisfy audit */
  204. free(up + 1);
  205. Heapsize += npar*16;
  206. Frees--; /* Nullify increment inside free() */
  207. return Allocp;
  208. }
  209. #endif /* __GNUC__ */
  210. return NULL;
  211. }
  212. /* Put memory block back on heap */
  213. void
  214. free(blk)
  215. void *blk;
  216. {
  217. register HEADER HUGE *p, HUGE *q;
  218. unsigned short HUGE *ptr;
  219. int i_state;
  220. int i;
  221. if(blk == NULL)
  222. return; /* Required by ANSI */
  223. Frees++;
  224. p = ((HEADER HUGE *)blk) - 1;
  225. /* Audit check */
  226. if(p->s.ptr != p){
  227. Invalid++;
  228. if(istate()){
  229. ptr = (unsigned short *)&blk;
  230. printf("free: WARNING! invalid pointer (%p) proc %sn",
  231.  blk,Curproc->name);
  232. stktrace();
  233. logmsg(-1,"free: WARNING! invalid pointer (%p) pc = 0x%x %x proc %sn",
  234.  blk,ptr[-1],ptr[-2],Curproc->name);
  235. }
  236. return;
  237. }
  238. Availmem += p->s.size;
  239. if(Memdebug){
  240. /* Fill data area with pattern to detect later overwrites */
  241. for(i=1;i<p->s.size;i++){
  242. memcpy(p[i].c,Debugpat,sizeof(Debugpat));
  243. }
  244. }
  245. i_state = dirps();
  246.   /* Search the free list looking for the right place to insert */
  247. for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
  248. /* Highest address on circular list? */
  249. if(q >= q->s.ptr && (p > q || p < q->s.ptr))
  250. break;
  251. }
  252. if(p + p->s.size == q->s.ptr){
  253. /* Combine with front of this entry */
  254. p->s.size += q->s.ptr->s.size;
  255. p->s.ptr = q->s.ptr->s.ptr;
  256. if(Memdebug){
  257. memcpy(q->s.ptr->c,Debugpat,sizeof(Debugpat));
  258. }
  259. } else {
  260. /* Link to front of this entry */
  261. p->s.ptr = q->s.ptr;
  262. }
  263. if(q + q->s.size == p){
  264. /* Combine with end of this entry */
  265. q->s.size += p->s.size;
  266. q->s.ptr = p->s.ptr;
  267. if(Memdebug){
  268. memcpy(p->c,Debugpat,sizeof(Debugpat));
  269. }
  270. } else {
  271. /* Link to end of this entry */
  272. q->s.ptr = p;
  273. }
  274. #ifdef circular
  275. Allocp = q;
  276. #endif
  277. restore(i_state);
  278. if(Memwait != 0)
  279. ksignal(&Memwait,0);
  280. }
  281. /* Move existing block to new area */
  282. void *
  283. realloc(area,size)
  284. void *area;
  285. size_t size;
  286. {
  287. unsigned osize;
  288. HEADER HUGE *hp;
  289. void *new;
  290. hp = ((HEADER *)area) - 1;
  291. osize = (hp->s.size -1) * ABLKSIZE;
  292. /* We must copy the block since freeing it may cause the heap
  293.  * debugging code to scribble over it.
  294.  */
  295. if((new = malloc(size)) != NULL)
  296. memcpy(new,area,size>osize? osize : size);
  297. free(area);
  298. return new;
  299. }
  300. /* Allocate block of cleared memory */
  301. void *
  302. calloc(nelem,size)
  303. size_t nelem; /* Number of elements */
  304. size_t size; /* Size of each element */
  305. {
  306. register unsigned i;
  307. register char *cp;
  308. i = nelem * size;
  309. if((cp = malloc(i)) != NULL)
  310. memset(cp,0,i);
  311. return cp;
  312. }
  313. /* Version of malloc() that waits if necessary for memory to become available */
  314. void *
  315. mallocw(nb)
  316. size_t nb;
  317. {
  318. register void *p;
  319. while((p = malloc(nb)) == NULL){
  320. Memwait++;
  321. kwait(&Memwait);
  322. Memwait--;
  323. }
  324. return p;
  325. }
  326. /* Version of calloc that waits if necessary for memory to become available */
  327. void *
  328. callocw(nelem,size)
  329. unsigned nelem; /* Number of elements */
  330. unsigned size; /* Size of each element */
  331. {
  332. register unsigned i;
  333. register char *cp;
  334. i = nelem * size;
  335. cp = mallocw(i);
  336. memset(cp,0,i);
  337. return cp;
  338. }
  339. /* Return 0 if at least Memthresh memory is available. Return 1 if
  340.  * less than Memthresh but more than Memthresh/2 is available; i.e.,
  341.  * if a yellow garbage collection should be performed. Return 2 if
  342.  * less than Memthresh/2 is available, i.e., a red collection should
  343.  * be performed.
  344.  */
  345. int
  346. availmem()
  347. {
  348. void *p;
  349. if(Availmem*ABLKSIZE >= Memthresh)
  350. return 0; /* We're clearly OK */
  351. /* There's not enough on the heap; try calling malloc to see if
  352.  * it can get more from the system
  353.  */
  354. if((p = malloc(Memthresh)) != NULL){
  355. free(p);
  356. return 0; /* Okay */
  357. }
  358. if((p = malloc(Memthresh/2)) != NULL){
  359. free(p);
  360. return 1; /* Yellow alert */
  361. }
  362. return 2; /* Red alert */
  363. }
  364. /* Print heap stats */
  365. static int
  366. dostat(argc,argv,envp)
  367. int argc;
  368. char *argv[];
  369. void *envp;
  370. {
  371. struct sysblock *sp;
  372. int i;
  373. printf("heap size %lu avail %lu (%lu%%) morecores %lun",
  374.  Heapsize,Availmem * ABLKSIZE,100L*Availmem*ABLKSIZE/Heapsize,
  375.  Morecores);
  376. if(Sysblock[0].npar != 0){
  377. printf("Extra blocks:");
  378. for(i=0,sp=Sysblock;i< NSYSBLOCK;i++,sp++){
  379. if(sp->npar == 0)
  380. break;
  381. printf(" (%x0-%x0)",sp->seg,sp->seg+sp->npar);
  382. }
  383. printf("n");
  384. }
  385. printf("allocs %lu frees %lu (diff %lu) alloc fails %lu invalid frees %lun",
  386. Allocs,Frees,Allocs-Frees,Memfail,Invalid);
  387. printf("garbage collections yellow %lu red %lun",Yellows,Reds);
  388. printf("n");
  389. mbufstat();
  390. return 0;
  391. }
  392. /* Print heap free list */
  393. static int
  394. dofreelist(argc,argv,envp)
  395. int argc;
  396. char *argv[];
  397. void *envp;
  398. {
  399. HEADER HUGE *p;
  400. int i = 0;
  401. int j;
  402. unsigned corrupt;
  403. int i_state;
  404. for(p = Base.s.ptr;p != (HEADER HUGE *)&Base;p = p->s.ptr){
  405. corrupt = 0;
  406. if(Memdebug){
  407. i_state = dirps();
  408. for(j=1;j<p->s.size;j++){
  409. if(memcmp(p[j].c,Debugpat,sizeof(Debugpat)) != 0){
  410. corrupt = j;
  411. break;
  412. }
  413. }
  414. restore(i_state);
  415. }
  416. if(corrupt)
  417. printf("%p %6lu C: %u",p,p->s.size * ABLKSIZE,corrupt);
  418. else
  419. printf("%p %6lu",p,p->s.size * ABLKSIZE);
  420. if(++i == 4){
  421. i = 0;
  422. if(printf("n") == EOF)
  423. return 0;
  424. } else
  425. printf(" | ");
  426. }
  427. if(i != 0)
  428. printf("n");
  429. return 0;
  430. }
  431. static int
  432. dosizes(argc,argv,p)
  433. int argc;
  434. char *argv[];
  435. void *p;
  436. {
  437. int i;
  438. for(i=0;i<16;i += 4){
  439. printf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ldn",
  440.  1<<i,Sizes[i], 2<<i,Sizes[i+1],
  441.  4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
  442. }
  443. mbufsizes();
  444. return 0;
  445. }
  446. int
  447. domem(argc,argv,p)
  448. int argc;
  449. char *argv[];
  450. void *p;
  451. {
  452. return subcmd(Memcmds,argc,argv,p);
  453. }
  454. static int
  455. dothresh(argc,argv,p)
  456. int argc;
  457. char *argv[];
  458. void *p;
  459. {
  460. return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  461. }
  462. static int
  463. domdebug(argc,argv,ptr)
  464. int argc;
  465. char *argv[];
  466. void *ptr;
  467. {
  468. int prev,j,i_state;
  469. HEADER HUGE *p;
  470. prev = Memdebug;
  471. setbool(&Memdebug,"Heap debugging",argc,argv);
  472. if(prev == 1 || Memdebug == 0)
  473. return 0;
  474. /* Turning debugging on; reinitialize free areas to debug pattern */
  475. i_state = dirps();
  476. for(p = Base.s.ptr;p != (HEADER HUGE *)&Base;p = p->s.ptr){
  477. for(j=1;j<p->s.size;j++){
  478. memcpy(p[j].c,Debugpat,sizeof(Debugpat));
  479. }
  480. }
  481. restore(i_state);
  482. return 0;
  483. }
  484. /* Background memory compactor, used when memory runs low */
  485. void
  486. gcollect(i,v1,v2)
  487. int i; /* Args not used */
  488. void *v1;
  489. void *v2;
  490. {
  491. void (**fp)(int);
  492. int red;
  493. for(;;){
  494. ppause(1000L); /* Run every second */
  495. /* If memory is low, collect some garbage. If memory is VERY
  496.  * low, invoke the garbage collection routines in "red" mode.
  497.  */
  498. switch(availmem()){
  499. case 0:
  500. continue; /* All is well */
  501. case 1:
  502. red = 0;
  503. Yellows++;
  504. break;
  505. case 2:
  506. red = 1;
  507. Reds++;
  508. break;
  509. }
  510. for(fp = Gcollect;*fp != NULL;fp++)
  511. (**fp)(red);
  512. }
  513. }