source: abuse/tags/pd/imlib/oldjmalloc.c @ 49

Last change on this file since 49 was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1#include <malloc.h>
2#include "jmalloc.hpp"
3#include <stdio.h>
4#include "macs.hpp"
5#include <string.h>
6#include "exitproc.hpp"
7#include "dprint.hpp"
8
9
10#ifdef __WATCOMC__
11#include <dos.h>
12#include <new.h>
13
14
15
16char *WAT_dos_alloc(long &size)
17{
18  union REGS r;
19  r.x.eax=0x0100;
20  r.x.ebx=(size+15)>>4;
21  int386(0x31,&r,&r);
22 
23  if (r.x.cflag)
24  {
25    size=(long)r.w.bx*16;
26    return NULL;
27  }
28  else
29    return (char *)((r.x.eax&0xffff)<<4);
30}
31
32void WAT_dos_free(void *ptr)
33{
34  union REGS r;
35  r.x.eax=0x0101;
36  r.x.edx=((long)ptr)>>4;
37  printf("free : segment is %d\n",r.w.dx);
38  int386(0x31,&r,&r);
39  if (r.x.cflag)
40    printf("DOS_free failed\n");
41
42}
43
44#endif
45
46struct memory_node
47{
48  memory_node *next;
49  long size;
50#ifdef MEM_CHECK
51  char *name;                     // name is allocated on regular heap
52#endif                            // because it is used for debugging purposes
53                                  // and will probably be run on my linux box with VMM
54  memory_node *next_free;         // if free (size<0) this is a pointer to the next free block
55                                  // otherwise data starts here
56};
57
58
59
60struct memory_block
61{
62  int type;
63  memory_node *fnode;
64} ;
65
66
67#define JM_SMALL_SIZE 128      // above 128 bytes is considered to be a big block and no hashing is done
68
69memory_node *jm_small[JM_SMALL_SIZE/4];
70memory_node *jm_big;
71
72memory_node *last_used=NULL;
73
74#define MAX_BLOCKS 4
75long mem_blocks=0;
76memory_block blocks[MAX_BLOCKS];
77
78#define REG_MEM    1
79#define LOW_MEM    2
80#define STATIC_MEM 3
81
82
83#ifdef MEM_CHECK
84void mem_check()
85{
86  int i,j;
87  for (i=0;i<mem_blocks;i++)
88  {
89    memory_node *last=blocks[i].fnode,*n;
90    for (j=0,n=last->next;n;n=n->next,j++)
91    {
92      if (last>=n)
93      {
94        printf("Memory corrupted, block #%d\n",j);
95        if (last->size>=0)
96          printf("last block name is %s\n",last->name);
97        else printf("last block was free\n");
98        mem_report("corrupt");
99      }
100    }   
101  }
102
103
104}
105#endif
106
107void add_block(void *addr, long size, int type)
108{
109  if (mem_blocks<MAX_BLOCKS-1)
110  {   
111    blocks[mem_blocks].fnode=(memory_node *)addr;
112    blocks[mem_blocks].type=type;
113
114    memory_node *f=blocks[mem_blocks].fnode;
115    f->size=-size+sizeof(memory_node)-sizeof(memory_node *);
116    f->next=NULL;
117    f->next_free=jm_big;
118    jm_big=f;
119    mem_blocks++;
120  }
121  else
122    fprintf(stderr,"added more than MEM_BLOCKS blocks\n");
123}
124
125void *operator new( size_t size)
126{
127  return jmalloc(size,"::new object");
128}
129
130void operator delete(void *ptr)
131{
132  jfree(ptr);
133}
134
135void jmem_cleanup(int ret, void *arg)
136{ jmalloc_uninit(); }
137
138void jmalloc_init(long min_size)  // allocates as much memory as possible, craps if min_size too big
139{
140  if (mem_blocks)
141    dprintf("warning : jmalloc_init called twice\n");
142  else
143  {
144    memset(jm_small,0,sizeof(memory_node *)*JM_SMALL_SIZE/4);      // clear out old free stacks
145    jm_big=NULL;
146
147    exit_proc(jmem_cleanup,jmalloc_uninit);          // make sure memory gets freed up on exit
148
149    void *mem_start;
150    long mem_size;
151
152    mem_start=NULL;
153
154    for (mem_size=4000000;!mem_start && mem_size>0x4000;mem_size-=0x100)  // allocate 4 MB
155      mem_start=malloc(mem_size);
156    if (mem_start)
157    {
158      free(mem_start);
159      mem_size-=0x4000;
160      mem_start=malloc(mem_size);     // save some space on regular heap
161      dprintf("Memory subsystem : added high mem block (%d bytes)\n",mem_size);
162      add_block(mem_start,mem_size,REG_MEM);
163    }
164
165#ifdef __WATCOMC__                      // allocate low memory from DOS
166    long dos_size=0xA0000;
167    char *dmem=(char *)WAT_dos_alloc(dos_size);
168    if (dmem) { printf("expecting dos_alloc to fail for %d bytes\n",0xa0000); }
169    if (dos_size<12000)
170      dprintf("Memory subsystem : low memory not used.. only %d bytes available\n",dos_size);
171    else
172    {
173      dos_size-=10000;   // 10k in case we need to for something else
174      dmem=(char *)WAT_dos_alloc(dos_size);
175      if (dmem)
176      {
177        add_block(dmem,dos_size,LOW_MEM);
178        dprintf("Memory subsystem : using %d bytes of low memory\n",dos_size);
179      } else dprintf("error in jmalloc_init\n");
180    }
181#endif
182
183   
184    if (j_available()<min_size)
185    {
186      fprintf(stderr,"available memory = %d bytes, need %d\n",j_available(),min_size);
187      fprintf(stderr,"You do not have enough memory available!\n"
188              "  DOS users  : Make sure you have himem.sys or other extended memory\n"
189              "               manager running. (look in your config.sys)\n"
190              "               Can you remove any TSR/driver programs?\n"
191              "  UNIX users : Do you have a swap file/partition installed?\n"
192              "  MAC users  : I don't think so....... :)    -JC\n");
193      exit(0);
194    }
195  }
196}
197
198void jmalloc_uninit()
199{
200  if (mem_blocks)
201  {
202    int i;
203    for (i=0;i<mem_blocks;i++)
204    {
205      switch (blocks[i].type)
206      {
207        case REG_MEM :
208        {
209          free((void *)blocks[i].fnode); } break;
210/*#ifdef __WATCOMC__         don't do this, because we don't know the segment numer
211                             and the memory manager will clean up for us...
212        case LOW_MEM :
213        { WAT_dos_free(blocks[i].fnode); break; }
214#endif*/
215        case STATIC_MEM : break;
216        default :
217          dprintf("Memory subsystem : Unknow memory block type\n");
218      }
219    }
220    mem_blocks=0;
221  } else
222    dprintf("jmalloc_uninit :: jmalloc_init not called\n");
223}
224
225
226int join_blocks()
227{
228  int i,j=0;
229  memory_node *f=NULL;
230
231  memset(jm_small,0,sizeof(memory_node *)*JM_SMALL_SIZE/4);      // clear out old free stacks
232  jm_big=NULL;
233
234  for (i=0;!f && i<mem_blocks;i++)     
235  {
236    for (f=blocks[i].fnode;f;)
237    {
238      if (f->size<0)
239      {
240        if (!f->next || f->next->size>0)  // if next bock is not free and to stack
241        {
242          if (-f->size<JM_SMALL_SIZE)
243          {
244            f->next_free=jm_small[-f->size/4];
245            jm_small[-f->size/4]=f;
246          } else
247          {
248            f->next_free=jm_big;
249            jm_big=f;
250          }
251          f=f->next;
252        } else if (f->next && f->next->size<0)
253        {
254          f->size+=f->next->size-sizeof(memory_node)+sizeof(memory_node *);
255          f->next=f->next->next;
256          j=1;
257        }               
258      }
259      else f=f->next;
260    }
261  }
262  return j;
263}
264
265void *jmalloc(long size, char *what_for)
266{
267  if (!mem_blocks)              // if not initialized, then use real malloc
268    return malloc(size);
269#ifdef MEM_CHECK
270  if (size<=0)     
271  {
272    size=4;
273    printf("jmalloc : asking for 0 or less\n");   
274  }
275#endif
276  size=(size+3)&(0xffffffff-3);      // make sure the size is word alligned
277
278  while (1)     // loop until we find a block to return
279  {
280    if (size<JM_SMALL_SIZE && jm_small[size/4])  // see if we have a block this size already waiting
281    {
282      memory_node *find=jm_small[size/4];
283      find->size=-find->size;                 // mark as being used
284#ifdef MEM_CHECK
285      find->name=strcpy((char *)malloc(strlen(what_for)+1),what_for);
286#endif     
287      jm_small[size/4]=find->next_free;                       // pop the block from the free stack
288      return (void *)&find->next_free;
289    } else   
290    {
291      // find first block which will accomodate this size
292      // save the last pointer so we can compact the stack
293      memory_node *find=NULL,*f,*last=NULL;
294      for (f=jm_big;!find && f;f=f->next_free)
295        if (-f->size>=size)
296          find=f;
297        else last=f;
298
299      if (find)
300      {
301        find->size=-find->size;                 // mark as being used
302#ifdef MEM_CHECK
303        find->name=strcpy((char *)malloc(strlen(what_for)+1),what_for);
304#endif         
305        if (last)
306          last->next_free=find->next_free;
307        else
308          jm_big=find->next_free;                    // pop the block from the free stack
309        if (find->size-size>sizeof(memory_node))     // enough space for free block?
310        {
311          memory_node *new_free=(memory_node *)(((char *)(&find->next_free))+size);
312          new_free->size=(find->size+sizeof(memory_node *)-size-sizeof(memory_node));
313          find->size=size;
314          if (new_free->size<JM_SMALL_SIZE)
315          {
316            new_free->next_free=jm_small[new_free->size/4];
317            jm_small[new_free->size/4]=new_free;
318          } else
319          {
320            new_free->next_free=jm_big;
321            jm_big=new_free;       
322          }       
323          new_free->next=find->next;
324          find->next=new_free;
325          new_free->size=-new_free->size;           // mark this block as free
326        }
327        return (void *)&find->next_free;
328      } else if (!join_blocks())
329        free_up_memory();
330    }
331  }
332}
333
334
335/*    // start at the last spot we used and see if we can find a block near there
336    if (last_used && (last_used->size<0) && ((-last_used->size-reserve)>=size))
337        f=last_used;
338
339    if (!f)     // no block yet, scan for one.
340    {
341      int i;
342      for (i=0;!f && i<mem_blocks;i++)     
343      {
344        for (f=blocks[i].fnode;f && (f->size>=0 || -f->size-reserve<=size);f=f->next);     
345      }
346    }
347    if (!f && !join_blocks())
348      free_up_memory();                       // user defined function to free memory
349    else
350    {
351      if (size>=-f->size-reserve)             // allocating the whole block?
352      {
353        f->size=-f->size;                     // chain stays the same, but mark memory as used
354#ifdef MEM_CHECK
355        f->name=strcpy((char *)malloc(strlen(what_for)+1),what_for);
356#endif   
357        last_used=f->next;                    // use next spot as refrence spot
358      }
359      else                                    // else create a new free node
360      {
361        memory_node *new_free;
362        new_free=(memory_node *)(((unsigned char *)f)+size+sizeof(memory_node));       
363        new_free->next=f->next;
364        new_free->size=f->size+size+sizeof(memory_node);
365
366        f->next=new_free;
367        f->size=size;
368        last_used=new_free;
369#ifdef MEM_CHECK
370        f->name=strcpy((char *)malloc(strlen(what_for)+1),what_for);
371#endif   
372      }
373      return (void *)(((unsigned char *)(f))+sizeof(memory_node));
374    }
375  }
376  return NULL; // while never happen
377} */
378
379
380void jfree(void *ptr)
381{
382  if (!mem_blocks)
383    free(ptr);
384  else
385  {
386    memory_node *f=(memory_node *)(((char *)ptr)+sizeof(memory_node *)-sizeof(memory_node));   
387#ifdef MEM_CHECK
388    if (f->size<0)
389    {
390      printf("Bad pointer\n");
391      return ;
392    }
393    free(f->name);
394#endif
395    if (f->size<JM_SMALL_SIZE)    // insert into small block chain?
396    {
397      f->next_free=jm_small[f->size/4];
398      jm_small[f->size/4]=f;
399    }
400    else
401    {
402      f->next_free=jm_big;
403      jm_big=f;
404    }
405    f->size=-f->size;   // mark free and join blocks later
406  }
407}
408
409
410void *jrealloc(void *ptr, long size, char *what_for)
411{
412  if (!mem_blocks)
413  {
414    if (ptr)                     // some platforms don't do this!
415      return realloc(ptr,size);
416    else return malloc(size);
417  }
418
419  if (!ptr)
420    return jmalloc(size,what_for);
421  else
422  {
423    if (size==0)                    // if the new size needed is zero then we can throw this away.
424    {     
425      jfree(ptr);
426      return NULL;
427    }
428    else
429    {
430      memory_node *f=(memory_node *)(((char *)ptr)+sizeof(memory_node *)-sizeof(memory_node));
431      long old_size=f->size;       // for now we are not going to be very smart about our re-allocation
432                                  // i.e. just allocate another block and copy this into it.
433      void *new_loc=jmalloc(size,what_for); 
434
435      if (size>old_size)
436        memcpy(new_loc,ptr,old_size);
437      else
438        memcpy(new_loc,ptr,size);
439
440      jfree(ptr);
441      return new_loc;
442    }
443  }
444  return NULL;
445}
446
447
448long j_allocated()
449{
450  memory_node *f;
451  long s=0,i;
452  for (i=0;i<mem_blocks;i++)
453  {
454    for (f=blocks[i].fnode;f;f=f->next)
455    {
456      if (f->size>0)
457      s+=f->size;
458    }
459  }
460  return s;
461}
462
463long j_available()
464{
465  memory_node *f;
466  long s=0,i;
467  for (i=0;i<mem_blocks;i++)
468  {
469    if (!blocks[i].fnode)
470      printf("block #%d is NULL\n",i);
471
472    for (f=blocks[i].fnode;f;f=f->next)
473    {
474      if (f->size<0)
475        s+=-f->size;
476    }
477  }
478  return s;
479}
480
481
482
483void mem_report(char *filename)
484{
485  long tot=0;
486  FILE *fp=fopen(filename,"wb");
487  int size_count[64];
488  memset(size_count,0,sizeof(size_count));
489  if (fp)
490  {
491    long i,size,tblocks=0;
492    for (i=0;i<mem_blocks;i++)
493    {
494      fprintf(fp,"*************** MEMORY BLOCK #%d ****************\n",i);
495      long offset=0;
496      memory_node *p=blocks[i].fnode;
497      while (p)
498      {
499        if (p->size>=0)
500        {
501          tblocks++;
502          if (p->size<64)
503            size_count[p->size]++;
504        }
505
506        if (p==last_used)
507          fprintf(fp,"-> ");
508#ifdef MEM_CHECK
509        if (p->size<0)
510          fprintf(fp,"%10d %d  %s\n",offset,p->size,"FREE");
511        else
512          fprintf(fp,"%10d %d  %s\n",offset,p->size,p->name);
513#else
514        fprintf(fp,"%10d %d\n",offset,p->size);
515#endif
516        offset+=(abs(p->size)+sizeof(memory_node));
517        tot+=abs(p->size);
518        p=p->next;
519      }
520    }
521    fprintf(fp,"##  Total = %d bytes\n",tot);
522    fprintf(fp,"##  Total allocated = %d bytes\n",j_allocated());
523    fprintf(fp,"##  Total blocks = %d\n",tblocks);
524
525
526    for (i=0;i<JM_SMALL_SIZE/4;i++)
527    {
528      memory_node *f=jm_small[i];
529      if (f)
530      {
531        int t;
532        fprintf(fp,"Size %d : Free = ",i*4);
533        for (t=0;f;f=f->next_free,t++)
534          if (-f->size!=i*4)
535            fprintf(fp,"  bad size! (%d)\n",f->size);
536
537        int tb=0;
538        for (int j=0;j<mem_blocks;j++)
539        {
540          memory_node *p=blocks[j].fnode;
541          for (;p;p=p->next)
542            if (p->size==i*4)
543              tb++;
544        }
545       
546        fprintf(fp,"%d, Used = %d\n",t,tb);
547
548      }
549    }
550
551  }
552  fclose(fp);
553}
554
555
556
557
558
559
560
Note: See TracBrowser for help on using the repository browser.