Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/vmalloc/vmbest.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#if defined(_UWIN) && defined(_BLD_ast)
23
24
void _STUB_vmbest(){}
25
26
#else
27
28
#include "vmhdr.h"
29
30
/* Best-fit allocation method. This is based on a best-fit strategy
31
** using a splay tree for storage of lists of free blocks of the same
32
** size. Recent free blocks may be cached for fast reuse.
33
**
34
** Written by Kiem-Phong Vo, [email protected], 01/16/94.
35
*/
36
37
#ifdef DEBUG
38
static int N_free; /* # of free calls */
39
static int N_alloc; /* # of alloc calls */
40
static int N_resize; /* # of resize calls */
41
static int N_wild; /* # allocated from the wild block */
42
static int N_last; /* # allocated from last free block */
43
static int N_reclaim; /* # of bestreclaim calls */
44
#endif /*DEBUG*/
45
46
#define COMPACT 8 /* factor to decide when to compact */
47
48
/* Check to see if a block is in the free tree */
49
#if __STD_C
50
static int vmintree(Block_t* node, Block_t* b)
51
#else
52
static int vmintree(node,b)
53
Block_t* node;
54
Block_t* b;
55
#endif
56
{ Block_t* t;
57
58
for(t = node; t; t = LINK(t))
59
if(t == b)
60
return 1;
61
if(LEFT(node) && vmintree(LEFT(node),b))
62
return 1;
63
if(RIGHT(node) && vmintree(RIGHT(node),b))
64
return 1;
65
return 0;
66
}
67
68
#if __STD_C
69
static int vmonlist(Block_t* list, Block_t* b)
70
#else
71
static int vmonlist(list,b)
72
Block_t* list;
73
Block_t* b;
74
#endif
75
{
76
for(; list; list = LINK(list))
77
if(list == b)
78
return 1;
79
return 0;
80
}
81
82
/* Check to see if a block is known to be free */
83
#if __STD_C
84
static int vmisfree(Vmdata_t* vd, Block_t* b)
85
#else
86
static int vmisfree(vd,b)
87
Vmdata_t* vd;
88
Block_t* b;
89
#endif
90
{
91
if(SIZE(b) & (BUSY|JUNK|PFREE))
92
return 0;
93
94
if(b == vd->wild)
95
return 1;
96
97
if(SIZE(b) < MAXTINY)
98
return vmonlist(TINY(vd)[INDEX(SIZE(b))], b);
99
100
if(vd->root)
101
return vmintree(vd->root, b);
102
103
return 0;
104
}
105
106
/* Check to see if a block is known to be junked */
107
#if __STD_C
108
static int vmisjunk(Vmdata_t* vd, Block_t* b)
109
#else
110
static int vmisjunk(vd,b)
111
Vmdata_t* vd;
112
Block_t* b;
113
#endif
114
{
115
Block_t* t;
116
117
if((SIZE(b)&BUSY) == 0 || (SIZE(b)&JUNK) == 0)
118
return 0;
119
120
if(b == vd->free) /* recently freed */
121
return 1;
122
123
/* check the list that b is supposed to be in */
124
for(t = CACHE(vd)[C_INDEX(SIZE(b))]; t; t = LINK(t))
125
if(t == b)
126
return 1;
127
128
/* on occasions, b may be put onto the catch-all list */
129
if(C_INDEX(SIZE(b)) < S_CACHE)
130
for(t = CACHE(vd)[S_CACHE]; t; t = LINK(t))
131
if(t == b)
132
return 1;
133
134
return 0;
135
}
136
137
/* check to see if the free tree is in good shape */
138
#if __STD_C
139
static int vmchktree(Block_t* node)
140
#else
141
static int vmchktree(node)
142
Block_t* node;
143
#endif
144
{ Block_t* t;
145
146
if(SIZE(node) & BITS)
147
{ /**/ASSERT(0); return -1; }
148
149
for(t = LINK(node); t; t = LINK(t))
150
if(SIZE(t) != SIZE(node))
151
{ /**/ASSERT(0); return -1; }
152
153
if((t = LEFT(node)) )
154
{ if(SIZE(t) >= SIZE(node) )
155
{ /**/ASSERT(0); return -1; }
156
else return vmchktree(t);
157
}
158
if((t = RIGHT(node)) )
159
{ if(SIZE(t) <= SIZE(node) )
160
{ /**/ASSERT(0); return -1; }
161
else return vmchktree(t);
162
}
163
164
return 0;
165
}
166
167
#if __STD_C
168
int _vmbestcheck(Vmdata_t* vd, Block_t* freeb)
169
#else
170
int _vmbestcheck(vd, freeb)
171
Vmdata_t* vd;
172
Block_t* freeb; /* known to be free but not on any free list */
173
#endif
174
{
175
reg Seg_t *seg;
176
reg Block_t *b, *endb, *nextb;
177
int rv = 0;
178
179
if(!CHECK())
180
return 0;
181
182
/* make sure the free tree is still in shape */
183
if(vd->root && vmchktree(vd->root) < 0 )
184
{ rv = -1; /**/ASSERT(0); }
185
186
for(seg = vd->seg; seg && rv == 0; seg = seg->next)
187
{ b = SEGBLOCK(seg);
188
endb = (Block_t*)(seg->baddr - sizeof(Head_t));
189
for(; b < endb && rv == 0; b = nextb)
190
{ nextb = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
191
192
if(!ISBUSY(SIZE(b)) ) /* a completely free block */
193
{ /* there should be no marked bits of any type */
194
if(SIZE(b) & (BUSY|JUNK|PFREE) )
195
{ rv = -1; /**/ASSERT(0); }
196
197
/* next block must be busy and marked PFREE */
198
if(!ISBUSY(SIZE(nextb)) || !ISPFREE(SIZE(nextb)) )
199
{ rv = -1; /**/ASSERT(0); }
200
201
/* must have a self-reference pointer */
202
if(SELF(b) != b)
203
{ rv = -1; /**/ASSERT(0); }
204
205
/* segment pointer should be well-defined */
206
if(!TINIEST(b) && SEG(b) != seg)
207
{ rv = -1; /**/ASSERT(0); }
208
209
/* must be on a free list */
210
if(b != freeb && !vmisfree(vd, b) )
211
{ rv = -1; /**/ASSERT(0); }
212
}
213
else
214
{ /* segment pointer should be well-defined */
215
if(SEG(b) != seg)
216
{ rv = -1; /**/ASSERT(0); }
217
218
/* next block should not be marked PFREE */
219
if(ISPFREE(SIZE(nextb)) )
220
{ rv = -1; /**/ASSERT(0); }
221
222
/* if PFREE, last block should be free */
223
if(ISPFREE(SIZE(b)) && LAST(b) != freeb &&
224
!vmisfree(vd, LAST(b)) )
225
{ rv = -1; /**/ASSERT(0); }
226
227
/* if free but unreclaimed, should be junk */
228
if(ISJUNK(SIZE(b)) && !vmisjunk(vd, b))
229
{ rv = -1; /**/ASSERT(0); }
230
}
231
}
232
}
233
234
return rv;
235
}
236
237
/* Tree rotation functions */
238
#define RROTATE(x,y) (LEFT(x) = RIGHT(y), RIGHT(y) = (x), (x) = (y))
239
#define LROTATE(x,y) (RIGHT(x) = LEFT(y), LEFT(y) = (x), (x) = (y))
240
#define RLINK(s,x) ((s) = LEFT(s) = (x))
241
#define LLINK(s,x) ((s) = RIGHT(s) = (x))
242
243
/* Find and delete a suitable element in the free tree. */
244
#if __STD_C
245
static Block_t* bestsearch(Vmdata_t* vd, reg size_t size, Block_t* wanted)
246
#else
247
static Block_t* bestsearch(vd, size, wanted)
248
Vmdata_t* vd;
249
reg size_t size;
250
Block_t* wanted;
251
#endif
252
{
253
reg size_t s;
254
reg Block_t *t, *root, *l, *r;
255
Block_t link;
256
257
/* extracting a tiniest block from its list */
258
if((root = wanted) && size == TINYSIZE)
259
{ reg Seg_t* seg;
260
261
l = TLEFT(root);
262
if((r = LINK(root)) )
263
TLEFT(r) = l;
264
if(l)
265
LINK(l) = r;
266
else TINY(vd)[0] = r;
267
268
seg = vd->seg;
269
if(!seg->next)
270
SEG(root) = seg;
271
else for(;; seg = seg->next)
272
{ if((Vmuchar_t*)root > (Vmuchar_t*)seg->addr &&
273
(Vmuchar_t*)root < seg->baddr)
274
{ SEG(root) = seg;
275
break;
276
}
277
}
278
279
return root;
280
}
281
282
/**/ASSERT(!vd->root || vmchktree(vd->root) == 0);
283
284
/* find the right one to delete */
285
l = r = &link;
286
if((root = vd->root) ) do
287
{ /**/ ASSERT(!ISBITS(size) && !ISBITS(SIZE(root)));
288
if(size == (s = SIZE(root)) )
289
break;
290
if(size < s)
291
{ if((t = LEFT(root)) )
292
{ if(size <= (s = SIZE(t)) )
293
{ RROTATE(root,t);
294
if(size == s)
295
break;
296
t = LEFT(root);
297
}
298
else
299
{ LLINK(l,t);
300
t = RIGHT(t);
301
}
302
}
303
RLINK(r,root);
304
}
305
else
306
{ if((t = RIGHT(root)) )
307
{ if(size >= (s = SIZE(t)) )
308
{ LROTATE(root,t);
309
if(size == s)
310
break;
311
t = RIGHT(root);
312
}
313
else
314
{ RLINK(r,t);
315
t = LEFT(t);
316
}
317
}
318
LLINK(l,root);
319
}
320
/**/ ASSERT(root != t);
321
} while((root = t) );
322
323
if(root) /* found it, now isolate it */
324
{ RIGHT(l) = LEFT(root);
325
LEFT(r) = RIGHT(root);
326
}
327
else /* nothing exactly fit */
328
{ LEFT(r) = NIL(Block_t*);
329
RIGHT(l) = NIL(Block_t*);
330
331
/* grab the least one from the right tree */
332
if((root = LEFT(&link)) )
333
{ while((t = LEFT(root)) )
334
RROTATE(root,t);
335
LEFT(&link) = RIGHT(root);
336
}
337
}
338
339
if(root && (r = LINK(root)) )
340
{ /* head of a link list, use next one for root */
341
LEFT(r) = RIGHT(&link);
342
RIGHT(r) = LEFT(&link);
343
}
344
else if(!(r = LEFT(&link)) )
345
r = RIGHT(&link);
346
else /* graft left tree to right tree */
347
{ while((t = LEFT(r)) )
348
RROTATE(r,t);
349
LEFT(r) = RIGHT(&link);
350
}
351
vd->root = r; /**/ASSERT(!r || !ISBITS(SIZE(r)));
352
353
/**/ASSERT(!vd->root || vmchktree(vd->root) == 0);
354
/**/ASSERT(!wanted || wanted == root);
355
356
return root;
357
}
358
359
/* Reclaim all delayed free blocks into the free tree */
360
#if __STD_C
361
static int bestreclaim(reg Vmdata_t* vd, Block_t* wanted, int c)
362
#else
363
static int bestreclaim(vd, wanted, c)
364
reg Vmdata_t* vd;
365
Block_t* wanted;
366
int c;
367
#endif
368
{
369
reg size_t size, s;
370
reg Block_t *fp, *np, *t, *list;
371
reg int n, saw_wanted;
372
373
/**/COUNT(N_reclaim);
374
/**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
375
376
if((fp = vd->free) )
377
{ LINK(fp) = CACHE(vd)[S_CACHE]; CACHE(vd)[S_CACHE] = fp;
378
vd->free = NIL(Block_t*);
379
}
380
381
saw_wanted = wanted ? 0 : 1;
382
for(n = S_CACHE; n >= c; --n)
383
{ list = CACHE(vd)[n]; CACHE(vd)[n] = NIL(Block_t*);
384
while((fp = list) )
385
{ /* Note that below here we allow ISJUNK blocks to be
386
** forward-merged even though they are not removed from
387
** the list immediately. In this way, the list is
388
** scanned only once. It works because the LINK and SIZE
389
** fields are not destroyed during the merging. This can
390
** be seen by observing that a tiniest block has a 2-word
391
** header and a 2-word body. Merging a tiniest block
392
** (1seg) and the next block (2seg) looks like this:
393
** 1seg size link left 2seg size link left ....
394
** 1seg size link left rite xxxx xxxx .... self
395
** After the merge, the 2seg word is replaced by the RIGHT
396
** pointer of the new block and somewhere beyond the
397
** two xxxx fields, the SELF pointer will replace some
398
** other word. The important part is that the two xxxx
399
** fields are kept intact.
400
*/
401
list = LINK(list); /**/ASSERT(!vmonlist(list,fp));
402
403
size = SIZE(fp);
404
if(!ISJUNK(size)) /* already done */
405
continue;
406
407
if(ISPFREE(size)) /* backward merge */
408
{ fp = LAST(fp);
409
s = SIZE(fp); /**/ASSERT(!(s&BITS));
410
REMOVE(vd,fp,INDEX(s),t,bestsearch);
411
size = (size&~BITS) + s + sizeof(Head_t);
412
}
413
else size &= ~BITS;
414
415
for(;;) /* forward merge */
416
{ np = (Block_t*)((Vmuchar_t*)fp+size+sizeof(Head_t));
417
s = SIZE(np); /**/ASSERT(s > 0);
418
if(!ISBUSY(s))
419
{ /**/ASSERT((s&BITS) == 0);
420
if(np == vd->wild)
421
vd->wild = NIL(Block_t*);
422
else REMOVE(vd,np,INDEX(s),t,bestsearch);
423
}
424
else if(ISJUNK(s))
425
{ /* reclaim any touched junk list */
426
if((int)C_INDEX(s) < c)
427
c = (int)C_INDEX(s);
428
SIZE(np) = 0;
429
CLRBITS(s);
430
}
431
else break;
432
size += s + sizeof(Head_t);
433
}
434
SIZE(fp) = size;
435
436
/* tell next block that this one is free */
437
np = NEXT(fp); /**/ASSERT(ISBUSY(SIZE(np)));
438
/**/ASSERT(!ISJUNK(SIZE(np)));
439
SETPFREE(SIZE(np));
440
SELF(fp) = fp;
441
442
if(fp == wanted) /* to be consumed soon */
443
{ /**/ASSERT(!saw_wanted); /* should be seen just once */
444
saw_wanted = 1;
445
continue;
446
}
447
448
/* wilderness preservation */
449
if(np->body.data >= vd->seg->baddr)
450
{ vd->wild = fp;
451
continue;
452
}
453
454
/* tiny block goes to tiny list */
455
if(size < MAXTINY)
456
{ s = INDEX(size);
457
np = LINK(fp) = TINY(vd)[s];
458
if(s == 0) /* TINIEST block */
459
{ if(np)
460
TLEFT(np) = fp;
461
TLEFT(fp) = NIL(Block_t*);
462
}
463
else
464
{ if(np)
465
LEFT(np) = fp;
466
LEFT(fp) = NIL(Block_t*);
467
SETLINK(fp);
468
}
469
TINY(vd)[s] = fp;
470
continue;
471
}
472
473
LEFT(fp) = RIGHT(fp) = LINK(fp) = NIL(Block_t*);
474
if(!(np = vd->root) ) /* inserting into an empty tree */
475
{ vd->root = fp;
476
continue;
477
}
478
479
size = SIZE(fp);
480
while(1) /* leaf insertion */
481
{ /**/ASSERT(np != fp);
482
if((s = SIZE(np)) > size)
483
{ if((t = LEFT(np)) )
484
{ /**/ ASSERT(np != t);
485
np = t;
486
}
487
else
488
{ LEFT(np) = fp;
489
break;
490
}
491
}
492
else if(s < size)
493
{ if((t = RIGHT(np)) )
494
{ /**/ ASSERT(np != t);
495
np = t;
496
}
497
else
498
{ RIGHT(np) = fp;
499
break;
500
}
501
}
502
else /* s == size */
503
{ if((t = LINK(np)) )
504
{ LINK(fp) = t;
505
LEFT(t) = fp;
506
}
507
LINK(np) = fp;
508
LEFT(fp) = np;
509
SETLINK(fp);
510
break;
511
}
512
}
513
}
514
}
515
516
/**/ASSERT(!wanted || saw_wanted == 1);
517
/**/ASSERT(_vmbestcheck(vd, wanted) == 0);
518
return saw_wanted;
519
}
520
521
#if __STD_C
522
static int bestcompact(Vmalloc_t* vm, int local)
523
#else
524
static int bestcompact(vm, local)
525
Vmalloc_t* vm;
526
int local;
527
#endif
528
{
529
reg Seg_t *seg, *next;
530
reg Block_t *bp, *tp;
531
reg size_t size, segsize, round;
532
reg Vmdata_t* vd = vm->data;
533
534
SETLOCK(vm, local);
535
536
bestreclaim(vd,NIL(Block_t*),0);
537
538
for(seg = vd->seg; seg; seg = next)
539
{ next = seg->next;
540
541
bp = BLOCK(seg->baddr);
542
if(!ISPFREE(SIZE(bp)) )
543
continue;
544
545
bp = LAST(bp); /**/ASSERT(vmisfree(vd,bp));
546
size = SIZE(bp);
547
if(bp == vd->wild)
548
{ /* During large block allocations, _Vmextend might
549
** have been enlarged the rounding factor. Reducing
550
** it a bit help avoiding getting large raw memory.
551
*/
552
if((round = vm->disc->round) == 0)
553
round = _Vmpagesize;
554
if(size > COMPACT*vd->incr && vd->incr > round)
555
vd->incr /= 2;
556
557
/* for the bottom segment, we don't necessarily want
558
** to return raw memory too early. vd->pool has an
559
** approximation of the average size of recently freed
560
** blocks. If this is large, the application is managing
561
** large blocks so we throttle back memory chopping
562
** to avoid thrashing the underlying memory system.
563
*/
564
if(size <= COMPACT*vd->incr || size <= COMPACT*vd->pool)
565
continue;
566
567
vd->wild = NIL(Block_t*);
568
vd->pool = 0;
569
}
570
else REMOVE(vd,bp,INDEX(size),tp,bestsearch);
571
tp = NEXT(bp); /* avoid strict-aliasing pun */
572
CLRPFREE(SIZE(tp));
573
574
if(size < (segsize = seg->size))
575
size += sizeof(Head_t);
576
577
if((size = (*_Vmtruncate)(vm,seg,size,0)) > 0)
578
{ if(size >= segsize) /* entire segment deleted */
579
continue;
580
/**/ASSERT(SEG(BLOCK(seg->baddr)) == seg);
581
582
if((size = (seg->baddr - ((Vmuchar_t*)bp) - sizeof(Head_t))) > 0)
583
SIZE(bp) = size - sizeof(Head_t);
584
else bp = NIL(Block_t*);
585
}
586
587
if(bp)
588
{ /**/ ASSERT(SIZE(bp) >= BODYSIZE);
589
/**/ ASSERT(SEGWILD(bp));
590
/**/ ASSERT(!vd->root || !vmintree(vd->root,bp));
591
SIZE(bp) |= BUSY|JUNK;
592
LINK(bp) = CACHE(vd)[C_INDEX(SIZE(bp))];
593
CACHE(vd)[C_INDEX(SIZE(bp))] = bp;
594
}
595
}
596
597
if(!local && _Vmtrace && (vd->mode&VM_TRACE) && VMETHOD(vd) == VM_MTBEST)
598
(*_Vmtrace)(vm, (Vmuchar_t*)0, (Vmuchar_t*)0, 0, 0);
599
600
CLRLOCK(vm, local); /**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
601
602
return 0;
603
}
604
605
#if __STD_C
606
static Void_t* bestalloc(Vmalloc_t* vm, size_t size , int local)
607
#else
608
static Void_t* bestalloc(vm, size, local)
609
Vmalloc_t* vm; /* region allocating from */
610
size_t size; /* desired block size */
611
int local; /* internal call */
612
#endif
613
{
614
reg Vmdata_t* vd = vm->data;
615
reg size_t s;
616
reg int n;
617
reg Block_t *tp, *np, *ap;
618
size_t orgsize = size;
619
620
/**/COUNT(N_alloc);
621
/**/ASSERT(local ? (vd->lock == 1) : 1 );
622
623
SETLOCK(vm,local);
624
625
/**/ ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
626
/**/ ASSERT(HEADSIZE == sizeof(Head_t));
627
/**/ ASSERT(BODYSIZE == sizeof(Body_t));
628
/**/ ASSERT((ALIGN%(BITS+1)) == 0 );
629
/**/ ASSERT((sizeof(Head_t)%ALIGN) == 0 );
630
/**/ ASSERT((sizeof(Body_t)%ALIGN) == 0 );
631
/**/ ASSERT((BODYSIZE%ALIGN) == 0 );
632
/**/ ASSERT(sizeof(Block_t) == (sizeof(Body_t)+sizeof(Head_t)) );
633
634
/* for ANSI requirement that malloc(0) returns non-NULL pointer */
635
size = size <= BODYSIZE ? BODYSIZE : ROUND(size,ALIGN);
636
637
if((tp = vd->free) ) /* reuse last free piece if appropriate */
638
{ /**/ASSERT(ISBUSY(SIZE(tp)) );
639
/**/ASSERT(ISJUNK(SIZE(tp)) );
640
/**/COUNT(N_last);
641
642
vd->free = NIL(Block_t*);
643
if((s = SIZE(tp)) >= size && s < (size << 1) )
644
{ if(s >= size + (sizeof(Head_t)+BODYSIZE) )
645
{ SIZE(tp) = size;
646
np = NEXT(tp);
647
SEG(np) = SEG(tp);
648
SIZE(np) = ((s&~BITS) - (size+sizeof(Head_t)))|JUNK|BUSY;
649
vd->free = np;
650
SIZE(tp) |= s&BITS;
651
}
652
CLRJUNK(SIZE(tp));
653
goto done;
654
}
655
656
LINK(tp) = CACHE(vd)[S_CACHE];
657
CACHE(vd)[S_CACHE] = tp;
658
}
659
660
for(n = S_CACHE; n >= 0; --n) /* best-fit except for coalescing */
661
{ bestreclaim(vd,NIL(Block_t*),n);
662
if(vd->root && (tp = bestsearch(vd,size,NIL(Block_t*))) )
663
goto got_block;
664
}
665
666
/**/ASSERT(!vd->free);
667
if((tp = vd->wild) && SIZE(tp) >= size)
668
{ /**/COUNT(N_wild);
669
vd->wild = NIL(Block_t*);
670
goto got_block;
671
}
672
673
/* need to extend the arena */
674
KPVCOMPACT(vm,bestcompact);
675
if((tp = (*_Vmextend)(vm,size,bestsearch)) )
676
{ got_block:
677
/**/ ASSERT(!ISBITS(SIZE(tp)));
678
/**/ ASSERT(SIZE(tp) >= size);
679
/**/ ASSERT((SIZE(tp)%ALIGN) == 0);
680
/**/ ASSERT(!vd->free);
681
682
/* tell next block that we are no longer a free block */
683
np = NEXT(tp);
684
CLRPFREE(SIZE(np)); /**/ ASSERT(ISBUSY(SIZE(np)));
685
686
if((s = SIZE(tp)-size) >= (sizeof(Head_t)+BODYSIZE) )
687
{ SIZE(tp) = size;
688
689
np = NEXT(tp);
690
SEG(np) = SEG(tp);
691
SIZE(np) = (s - sizeof(Head_t)) | BUSY|JUNK;
692
693
if(VMWILD(vd,np))
694
{ SIZE(np) &= ~BITS;
695
SELF(np) = np;
696
ap = NEXT(np); /**/ASSERT(ISBUSY(SIZE(ap)));
697
SETPFREE(SIZE(ap));
698
vd->wild = np;
699
}
700
else vd->free = np;
701
}
702
703
SETBUSY(SIZE(tp));
704
}
705
706
done:
707
if(tp && !local && (vd->mode&VM_TRACE) && _Vmtrace && VMETHOD(vd) == VM_MTBEST)
708
(*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)DATA(tp),orgsize,0);
709
710
CLRLOCK(vm,local); /**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
711
712
return tp ? DATA(tp) : NIL(Void_t*);
713
}
714
715
#if __STD_C
716
static long bestaddr(Vmalloc_t* vm, Void_t* addr, int local )
717
#else
718
static long bestaddr(vm, addr, local)
719
Vmalloc_t* vm; /* region allocating from */
720
Void_t* addr; /* address to check */
721
int local;
722
#endif
723
{
724
reg Seg_t* seg;
725
reg Block_t *b, *endb;
726
reg long offset;
727
reg Vmdata_t* vd = vm->data;
728
729
/**/ASSERT(local ? (vd->lock == 1) : 1 );
730
SETLOCK(vm, local);
731
732
offset = -1L; b = endb = NIL(Block_t*);
733
for(seg = vd->seg; seg; seg = seg->next)
734
{ b = SEGBLOCK(seg);
735
endb = (Block_t*)(seg->baddr - sizeof(Head_t));
736
if((Vmuchar_t*)addr > (Vmuchar_t*)b &&
737
(Vmuchar_t*)addr < (Vmuchar_t*)endb)
738
break;
739
}
740
741
if(local ) /* from bestfree or bestresize */
742
{ b = BLOCK(addr);
743
if(seg && SEG(b) == seg && ISBUSY(SIZE(b)) && !ISJUNK(SIZE(b)) )
744
offset = 0;
745
}
746
else if(seg)
747
{ while(b < endb)
748
{ reg Vmuchar_t* data = (Vmuchar_t*)DATA(b);
749
reg size_t size = SIZE(b)&~BITS;
750
751
if((Vmuchar_t*)addr >= data && (Vmuchar_t*)addr < data+size)
752
{ if(ISJUNK(SIZE(b)) || !ISBUSY(SIZE(b)))
753
offset = -1L;
754
else offset = (long)((Vmuchar_t*)addr - data);
755
goto done;
756
}
757
758
b = (Block_t*)((Vmuchar_t*)DATA(b) + size);
759
}
760
}
761
762
done:
763
CLRLOCK(vm,local);
764
return offset;
765
}
766
767
#if __STD_C
768
static int bestfree(Vmalloc_t* vm, Void_t* data, int local )
769
#else
770
static int bestfree(vm, data, local )
771
Vmalloc_t* vm;
772
Void_t* data;
773
int local;
774
#endif
775
{
776
reg Vmdata_t* vd = vm->data;
777
reg Block_t *bp;
778
reg size_t s;
779
780
#ifdef DEBUG
781
if(((char*)data - (char*)0) <= 1)
782
{ _Vmassert |= VM_check;
783
_vmbestcheck(vd, NIL(Block_t*));
784
if (!data)
785
_Vmassert &= ~VM_check;
786
return 0;
787
}
788
#else
789
if(!data) /* ANSI-ism */
790
return 0;
791
#endif
792
793
/**/COUNT(N_free);
794
/**/ASSERT(local ? (vd->lock == 1) : 1 );
795
796
SETLOCK(vm, local);
797
798
/**/ASSERT(KPVADDR(vm, data, bestaddr) == 0);
799
/**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
800
bp = BLOCK(data); s = SIZE(bp);
801
802
/* Keep an approximate average free block size.
803
** This is used in bestcompact() to decide when to release
804
** raw memory back to the underlying memory system.
805
*/
806
vd->pool = (vd->pool + (s&~BITS))/2;
807
808
if(ISBUSY(s) && !ISJUNK(s))
809
{ SETJUNK(SIZE(bp));
810
if(s < MAXCACHE)
811
{ /**/ASSERT(!vmonlist(CACHE(vd)[INDEX(s)], bp) );
812
LINK(bp) = CACHE(vd)[INDEX(s)];
813
CACHE(vd)[INDEX(s)] = bp;
814
}
815
else if(!vd->free)
816
vd->free = bp;
817
else
818
{ /**/ASSERT(!vmonlist(CACHE(vd)[S_CACHE], bp) );
819
LINK(bp) = CACHE(vd)[S_CACHE];
820
CACHE(vd)[S_CACHE] = bp;
821
}
822
823
/* coalesce on freeing large blocks to avoid fragmentation */
824
if(SIZE(bp) >= 2*vd->incr)
825
{ bestreclaim(vd,NIL(Block_t*),0);
826
if(vd->wild && SIZE(vd->wild) >= COMPACT*vd->incr)
827
KPVCOMPACT(vm,bestcompact);
828
}
829
}
830
831
if(!local && _Vmtrace && (vd->mode&VM_TRACE) && VMETHOD(vd) == VM_MTBEST )
832
(*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*), (s&~BITS), 0);
833
834
CLRLOCK(vm, local); /**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
835
836
return 0;
837
}
838
839
#if __STD_C
840
static Void_t* bestresize(Vmalloc_t* vm, Void_t* data, reg size_t size, int type, int local)
841
#else
842
static Void_t* bestresize(vm, data, size, type, local)
843
Vmalloc_t* vm; /* region allocating from */
844
Void_t* data; /* old block of data */
845
reg size_t size; /* new size */
846
int type; /* !=0 to move, <0 for not copy */
847
int local;
848
#endif
849
{
850
reg Block_t *rp, *np, *t;
851
size_t s, bs;
852
size_t oldz = 0, orgsize = size;
853
Void_t *oldd = 0, *orgdata = data;
854
Vmdata_t *vd = vm->data;
855
856
/**/COUNT(N_resize);
857
/**/ASSERT(local ? (vd->lock == 1) : 1);
858
859
if(!data) /* resizing a NULL block is the same as allocating */
860
{ data = bestalloc(vm, size, local);
861
if(data && (type&VM_RSZERO) )
862
memset((Void_t*)data, 0, size);
863
return data;
864
}
865
if(size == 0) /* resizing to zero size is the same as freeing */
866
{ (void)bestfree(vm, data, local);
867
return NIL(Void_t*);
868
}
869
870
SETLOCK(vm, local);
871
872
/**/ASSERT(KPVADDR(vm, data, bestaddr) == 0);
873
/**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
874
size = size <= BODYSIZE ? BODYSIZE : ROUND(size,ALIGN);
875
rp = BLOCK(data); /**/ASSERT(ISBUSY(SIZE(rp)) && !ISJUNK(SIZE(rp)));
876
oldz = SIZE(rp); CLRBITS(oldz);
877
if(oldz < size)
878
{ np = (Block_t*)((Vmuchar_t*)rp + oldz + sizeof(Head_t));
879
do /* forward merge as much as possible */
880
{ s = SIZE(np); /**/ASSERT(!ISPFREE(s));
881
if(np == vd->free)
882
{ vd->free = NIL(Block_t*);
883
CLRBITS(s);
884
}
885
else if(ISJUNK(s) )
886
{ if(!bestreclaim(vd,np,(int)C_INDEX(s)) )
887
/**/ASSERT(0); /* oops: did not see np! */
888
s = SIZE(np); /**/ASSERT(s%ALIGN == 0);
889
}
890
else if(!ISBUSY(s) )
891
{ if(np == vd->wild)
892
vd->wild = NIL(Block_t*);
893
else REMOVE(vd,np,INDEX(s),t,bestsearch);
894
}
895
else break;
896
897
SIZE(rp) += (s += sizeof(Head_t)); /**/ASSERT((s%ALIGN) == 0);
898
np = (Block_t*)((Vmuchar_t*)np + s);
899
CLRPFREE(SIZE(np));
900
} while(SIZE(rp) < size);
901
902
if(SIZE(rp) < size && size > vd->incr && SEGWILD(rp) )
903
{ reg Seg_t* seg;
904
905
s = (size - SIZE(rp)) + sizeof(Head_t); s = ROUND(s,vd->incr);
906
seg = SEG(rp);
907
if((*vm->disc->memoryf)(vm,seg->addr,seg->extent,seg->extent+s,
908
vm->disc) == seg->addr )
909
{ SIZE(rp) += s;
910
seg->extent += s;
911
seg->size += s;
912
seg->baddr += s;
913
s = (SIZE(rp)&~BITS) + sizeof(Head_t);
914
np = (Block_t*)((Vmuchar_t*)rp + s);
915
SEG(np) = seg;
916
SIZE(np) = BUSY;
917
}
918
}
919
}
920
921
if((s = SIZE(rp)) >= (size + (BODYSIZE+sizeof(Head_t))) )
922
{ SIZE(rp) = size;
923
np = NEXT(rp);
924
SEG(np) = SEG(rp);
925
SIZE(np) = (((s&~BITS)-size) - sizeof(Head_t))|BUSY|JUNK;
926
CPYBITS(SIZE(rp),s);
927
rp = np;
928
goto do_free;
929
}
930
else if((bs = s&~BITS) < size)
931
{ if(!(type&(VM_RSMOVE|VM_RSCOPY)) )
932
data = NIL(Void_t*); /* old data is not moveable */
933
else
934
{ oldd = data;
935
if((data = KPVALLOC(vm,size,bestalloc)) )
936
{ if(type&VM_RSCOPY)
937
memcpy(data, oldd, bs);
938
939
do_free: /* reclaim these right away */
940
SETJUNK(SIZE(rp));
941
LINK(rp) = CACHE(vd)[S_CACHE];
942
CACHE(vd)[S_CACHE] = rp;
943
bestreclaim(vd, NIL(Block_t*), S_CACHE);
944
}
945
}
946
}
947
948
if(data && (type&VM_RSZERO) && (size = SIZE(BLOCK(data))&~BITS) > oldz )
949
memset((Void_t*)((Vmuchar_t*)data + oldz), 0, size-oldz);
950
951
if(!local && _Vmtrace && data && (vd->mode&VM_TRACE) && VMETHOD(vd) == VM_MTBEST)
952
(*_Vmtrace)(vm, (Vmuchar_t*)orgdata, (Vmuchar_t*)data, orgsize, 0);
953
954
CLRLOCK(vm, local); /**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
955
956
return data;
957
}
958
959
#if __STD_C
960
static long bestsize(Vmalloc_t* vm, Void_t* addr, int local )
961
#else
962
static long bestsize(vm, addr, local)
963
Vmalloc_t* vm; /* region allocating from */
964
Void_t* addr; /* address to check */
965
int local;
966
#endif
967
{
968
Seg_t *seg;
969
Block_t *b, *endb;
970
long size;
971
Vmdata_t *vd = vm->data;
972
973
SETLOCK(vm, local);
974
975
size = -1L;
976
for(seg = vd->seg; seg; seg = seg->next)
977
{ b = SEGBLOCK(seg);
978
endb = (Block_t*)(seg->baddr - sizeof(Head_t));
979
if((Vmuchar_t*)addr <= (Vmuchar_t*)b ||
980
(Vmuchar_t*)addr >= (Vmuchar_t*)endb)
981
continue;
982
while(b < endb)
983
{ if(addr == DATA(b))
984
{ if(!ISBUSY(SIZE(b)) || ISJUNK(SIZE(b)) )
985
size = -1L;
986
else size = (long)SIZE(b)&~BITS;
987
goto done;
988
}
989
else if((Vmuchar_t*)addr <= (Vmuchar_t*)b)
990
break;
991
992
b = (Block_t*)((Vmuchar_t*)DATA(b) + (SIZE(b)&~BITS) );
993
}
994
}
995
996
done:
997
CLRLOCK(vm, local);
998
return size;
999
}
1000
1001
#if __STD_C
1002
static Void_t* bestalign(Vmalloc_t* vm, size_t size, size_t align, int local)
1003
#else
1004
static Void_t* bestalign(vm, size, align, local)
1005
Vmalloc_t* vm;
1006
size_t size;
1007
size_t align;
1008
int local;
1009
#endif
1010
{
1011
Vmuchar_t *data;
1012
Block_t *tp, *np;
1013
Seg_t *seg;
1014
size_t s, extra;
1015
size_t orgsize = size, orgalign = align;
1016
Vmdata_t *vd = vm->data;
1017
1018
if(size <= 0 || align <= 0)
1019
return NIL(Void_t*);
1020
1021
SETLOCK(vm, local);
1022
1023
/**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
1024
size = size <= BODYSIZE ? BODYSIZE : ROUND(size,ALIGN);
1025
align = MULTIPLE(align,ALIGN);
1026
1027
/* hack so that dbalign() can store header data */
1028
if(VMETHOD(vd) != VM_MTDEBUG)
1029
extra = 0;
1030
else
1031
{ extra = DB_HEAD;
1032
while(align < extra || (align - extra) < sizeof(Block_t))
1033
align *= 2;
1034
}
1035
1036
/* reclaim all free blocks now to avoid fragmentation */
1037
bestreclaim(vd,NIL(Block_t*),0);
1038
1039
s = size + 2*(align+sizeof(Head_t)+extra);
1040
if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,bestalloc)) )
1041
goto done;
1042
1043
tp = BLOCK(data);
1044
seg = SEG(tp);
1045
1046
/* get an aligned address that we can live with */
1047
if((s = (size_t)((VLONG(data)+extra)%align)) != 0)
1048
data += align-s; /**/ASSERT(((VLONG(data)+extra)%align) == 0);
1049
1050
if((np = BLOCK(data)) != tp ) /* need to free left part */
1051
{ if(((Vmuchar_t*)np - (Vmuchar_t*)tp) < (ssize_t)(sizeof(Block_t)+extra) )
1052
{ data += align;
1053
np = BLOCK(data);
1054
} /**/ASSERT(((VLONG(data)+extra)%align) == 0);
1055
1056
s = (Vmuchar_t*)np - (Vmuchar_t*)tp;
1057
SIZE(np) = ((SIZE(tp)&~BITS) - s)|BUSY;
1058
SEG(np) = seg;
1059
1060
SIZE(tp) = (s - sizeof(Head_t)) | (SIZE(tp)&BITS) | JUNK;
1061
/**/ ASSERT(SIZE(tp) >= sizeof(Body_t) );
1062
LINK(tp) = CACHE(vd)[C_INDEX(SIZE(tp))];
1063
CACHE(vd)[C_INDEX(SIZE(tp))] = tp;
1064
}
1065
1066
/* free left-over if too big */
1067
if((s = SIZE(np) - size) >= sizeof(Block_t))
1068
{ SIZE(np) = size;
1069
1070
tp = NEXT(np);
1071
SIZE(tp) = ((s & ~BITS) - sizeof(Head_t)) | BUSY | JUNK;
1072
SEG(tp) = seg;
1073
LINK(tp) = CACHE(vd)[C_INDEX(SIZE(tp))];
1074
CACHE(vd)[C_INDEX(SIZE(tp))] = tp;
1075
1076
SIZE(np) |= s&BITS;
1077
}
1078
1079
bestreclaim(vd,NIL(Block_t*),0); /* coalesce all free blocks */
1080
1081
if(!local && _Vmtrace && (vd->mode&VM_TRACE) )
1082
(*_Vmtrace)(vm,NIL(Vmuchar_t*),data,orgsize,orgalign);
1083
1084
done:
1085
CLRLOCK(vm, local); /**/ASSERT(_vmbestcheck(vd, NIL(Block_t*)) == 0);
1086
1087
return (Void_t*)data;
1088
}
1089
1090
/* The below implements the discipline Vmdcsbrk and the heap region Vmheap.
1091
** There are 5 alternative ways to get raw memory:
1092
** win32, sbrk, mmap_anon, mmap_zero and reusing the native malloc
1093
** The selection of method done here is to enable our malloc implementation
1094
** to work with concurrent threads. The sbrk/brk interface is unfortunately
1095
** not atomic. Thus, we prefer mmap_anon or mmap_zero if they are available.
1096
*/
1097
#if _mem_win32
1098
#undef _mem_mmap_anon
1099
#undef _mem_mmap_zero
1100
#undef _mem_sbrk
1101
#endif
1102
#if _mem_mmap_anon
1103
#undef _mem_mmap_zero
1104
#if !_PACKAGE_ast
1105
#undef _mem_sbrk
1106
#endif
1107
#endif
1108
#if _mem_mmap_zero
1109
#if !_PACKAGE_ast
1110
#undef _mem_sbrk
1111
#endif
1112
#endif
1113
1114
#if __linux__
1115
1116
/* make sure that allocated memory is addressable */
1117
1118
#include <signal.h>
1119
typedef void (*Sig_f)(int);
1120
static int Gotsegv = 0;
1121
1122
static void sigsegv(int sig)
1123
{
1124
if(sig == SIGSEGV)
1125
Gotsegv = 1;
1126
}
1127
static int chkaddr(Vmuchar_t* addr, size_t nsize)
1128
{
1129
Sig_f segv;
1130
int rv;
1131
1132
Gotsegv = 0; /* catch segment fault */
1133
segv = signal(SIGSEGV, sigsegv);
1134
1135
rv = *(addr+nsize-1);
1136
rv = Gotsegv ? -1 : rv;
1137
1138
signal(SIGSEGV, segv); /* restore signal catcher */
1139
Gotsegv = 0;
1140
1141
return rv;
1142
}
1143
#else
1144
1145
/* known !__linux__ guarantee that brk-addresses are valid */
1146
1147
#define chkaddr(a,n) (0)
1148
1149
#endif /*__linux__*/
1150
1151
#if _mem_win32 /* getting memory on a window system */
1152
#if _PACKAGE_ast
1153
#include <ast_windows.h>
1154
#else
1155
#include <windows.h>
1156
#endif
1157
1158
static Void_t* win32mem(Void_t* caddr, size_t csize, size_t nsize)
1159
{ /**/ ASSERT(csize > 0 || nsize > 0)
1160
if(csize == 0)
1161
{ caddr = (Void_t*)VirtualAlloc(0,nsize,MEM_COMMIT,PAGE_READWRITE);
1162
return caddr;
1163
}
1164
else if(nsize == 0)
1165
{ (void)VirtualFree((LPVOID)caddr,0,MEM_RELEASE);
1166
return caddr;
1167
}
1168
else return NIL(Void_t*);
1169
}
1170
#endif /* _mem_win32 */
1171
1172
#if _mem_sbrk /* getting space via brk/sbrk - not concurrent-ready */
1173
static Void_t* sbrkmem(Void_t* caddr, size_t csize, size_t nsize)
1174
{
1175
Vmuchar_t *addr = (Vmuchar_t*)sbrk(0);
1176
1177
if(!addr || addr == (Vmuchar_t*)(-1) )
1178
return NIL(Void_t*);
1179
1180
if(csize > 0 && addr != (Vmuchar_t*)caddr+csize)
1181
return NIL(Void_t*);
1182
else if(csize == 0)
1183
caddr = addr;
1184
1185
/**/ASSERT(addr == (Vmuchar_t*)caddr+csize);
1186
if(nsize < csize)
1187
addr -= csize-nsize;
1188
else if((addr += nsize-csize) < (Vmuchar_t*)caddr )
1189
return NIL(Void_t*);
1190
1191
if(brk(addr) != 0 )
1192
return NIL(Void_t*);
1193
else if(nsize > csize && chkaddr(caddr, nsize) < 0 )
1194
{ (void)brk((Vmuchar_t*)caddr+csize);
1195
return NIL(Void_t*);
1196
}
1197
else return caddr;
1198
}
1199
#endif /* _mem_sbrk */
1200
1201
#if _mem_mmap_anon || _mem_mmap_zero /* get space using mmap */
1202
#include <fcntl.h>
1203
#include <sys/mman.h>
1204
1205
#ifndef MAP_ANON
1206
#ifdef MAP_ANONYMOUS
1207
#define MAP_ANON MAP_ANONYMOUS
1208
#else
1209
#define MAP_ANON 0
1210
#endif
1211
#endif /*MAP_ANON*/
1212
1213
#ifndef OPEN_MAX
1214
#define OPEN_MAX 64
1215
#endif
1216
#define FD_INIT (-1) /* uninitialized file desc */
1217
#define FD_NONE (-2) /* no mapping with file desc */
1218
1219
typedef struct _mmdisc_s
1220
{ Vmdisc_t disc;
1221
int fd;
1222
off_t offset;
1223
} Mmdisc_t;
1224
1225
static Void_t* mmapmem(Void_t* caddr, size_t csize, size_t nsize, Mmdisc_t* mmdc)
1226
{
1227
#if _mem_mmap_zero
1228
if(mmdc) /* /dev/zero mapping */
1229
{ if(mmdc->fd == FD_INIT ) /* open /dev/zero for mapping */
1230
{ int fd;
1231
if((fd = open("/dev/zero", O_RDONLY)) < 0 )
1232
{ mmdc->fd = FD_NONE;
1233
return NIL(Void_t*);
1234
}
1235
mmdc->fd = _vmfd(fd);
1236
}
1237
1238
if(mmdc->fd == FD_NONE)
1239
return NIL(Void_t*);
1240
}
1241
#endif /* _mem_mmap_zero */
1242
1243
/**/ASSERT(csize > 0 || nsize > 0);
1244
if(csize == 0)
1245
{ nsize = ROUND(nsize, _Vmpagesize);
1246
caddr = NIL(Void_t*);
1247
#if _mem_mmap_zero
1248
if(mmdc && mmdc->fd >= 0 )
1249
caddr = mmap(0, nsize, PROT_READ|PROT_WRITE, MAP_PRIVATE, mmdc->fd, mmdc->offset);
1250
#endif
1251
#if _mem_mmap_anon
1252
if(!mmdc )
1253
caddr = mmap(0, nsize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
1254
#endif
1255
if(!caddr || caddr == (Void_t*)(-1))
1256
return NIL(Void_t*);
1257
else if(chkaddr((Vmuchar_t*)caddr, nsize) < 0 )
1258
{ (void)munmap(caddr, nsize);
1259
return NIL(Void_t*);
1260
}
1261
else
1262
{ if(mmdc)
1263
mmdc->offset += nsize;
1264
return caddr;
1265
}
1266
}
1267
else if(nsize == 0)
1268
{ Vmuchar_t *addr = (Vmuchar_t*)sbrk(0);
1269
if(addr < (Vmuchar_t*)caddr ) /* in sbrk space */
1270
return NIL(Void_t*);
1271
else
1272
{ (void)munmap(caddr, csize);
1273
return caddr;
1274
}
1275
}
1276
else return NIL(Void_t*);
1277
}
1278
#endif /* _mem_map_anon || _mem_mmap_zero */
1279
1280
#if _std_malloc /* using native malloc as a last resource */
1281
static Void_t* mallocmem(Void_t* caddr, size_t csize, size_t nsize)
1282
{
1283
/**/ASSERT(csize > 0 || nsize > 0);
1284
if(csize == 0)
1285
return (Void_t*)malloc(nsize);
1286
else if(nsize == 0)
1287
{ free(caddr);
1288
return caddr;
1289
}
1290
else return NIL(Void_t*);
1291
}
1292
#endif
1293
1294
/* A discipline to get raw memory using VirtualAlloc/mmap/sbrk */
1295
static Void_t* getmemory(Vmalloc_t* vm, Void_t* caddr, size_t csize, size_t nsize, Vmdisc_t* disc)
1296
{
1297
Vmuchar_t *addr;
1298
1299
if((csize > 0 && !caddr) || (csize == 0 && nsize == 0) )
1300
return NIL(Void_t*);
1301
1302
#if _mem_win32
1303
if((addr = win32mem(caddr, csize, nsize)) )
1304
return (Void_t*)addr;
1305
#endif
1306
#if _mem_sbrk
1307
#if 1 /* no sbrk() unless explicit VM_break */
1308
if((_Vmassert & VM_break) && (addr = sbrkmem(caddr, csize, nsize)) )
1309
#else /* asoinit(0,0,0)==0 => the application did not request a specific aso method => sbrk() ok */
1310
if(((_Vmassert & VM_break) || !(_Vmassert & VM_mmap) && !asoinit(0, 0, 0)) && (addr = sbrkmem(caddr, csize, nsize)) )
1311
#endif
1312
return (Void_t*)addr;
1313
#endif
1314
#if _mem_mmap_anon
1315
if((addr = mmapmem(caddr, csize, nsize, (Mmdisc_t*)0)) )
1316
return (Void_t*)addr;
1317
#endif
1318
#if _mem_mmap_zero
1319
if((addr = mmapmem(caddr, csize, nsize, (Mmdisc_t*)disc)) )
1320
return (Void_t*)addr;
1321
#endif
1322
#if _mem_sbrk
1323
if(!(_Vmassert & VM_break) && (addr = sbrkmem(caddr, csize, nsize)) )
1324
return (Void_t*)addr;
1325
#endif
1326
#if _std_malloc
1327
if((addr = mallocmem(caddr, csize, nsize)) )
1328
return (Void_t*)addr;
1329
#endif
1330
return NIL(Void_t*);
1331
}
1332
1333
#if _mem_mmap_zero || _mem_mmap_anon
1334
static Mmdisc_t _Vmdcsystem = { { getmemory, NIL(Vmexcept_f), 64*1024, sizeof(Mmdisc_t) }, FD_INIT, 0 };
1335
#else
1336
static Vmdisc_t _Vmdcsystem = { getmemory, NIL(Vmexcept_f), 0, sizeof(Vmdisc_t) };
1337
#endif
1338
1339
static Vmethod_t _Vmbest =
1340
{
1341
bestalloc,
1342
bestresize,
1343
bestfree,
1344
bestaddr,
1345
bestsize,
1346
bestcompact,
1347
bestalign,
1348
VM_MTBEST
1349
};
1350
1351
/* The heap region */
1352
static Vmdata_t _Vmdata =
1353
{
1354
0, /* lock */
1355
VM_MTBEST|VM_SHARE, /* mode */
1356
0, /* incr */
1357
0, /* pool */
1358
NIL(Seg_t*), /* seg */
1359
NIL(Block_t*), /* free */
1360
NIL(Block_t*), /* wild */
1361
NIL(Block_t*) /* root */
1362
/* tiny[] */
1363
/* cache[] */
1364
};
1365
Vmalloc_t _Vmheap =
1366
{
1367
{ bestalloc,
1368
bestresize,
1369
bestfree,
1370
bestaddr,
1371
bestsize,
1372
bestcompact,
1373
bestalign,
1374
VM_MTBEST
1375
},
1376
NIL(char*), /* file */
1377
0, /* line */
1378
0, /* func */
1379
(Vmdisc_t*)(&_Vmdcsystem), /* disc */
1380
&_Vmdata, /* data */
1381
NIL(Vmalloc_t*) /* next */
1382
};
1383
1384
__DEFINE__(Vmalloc_t*, Vmheap, &_Vmheap);
1385
__DEFINE__(Vmalloc_t*, Vmregion, &_Vmheap);
1386
__DEFINE__(Vmethod_t*, Vmbest, &_Vmbest);
1387
__DEFINE__(Vmdisc_t*, Vmdcsystem, (Vmdisc_t*)(&_Vmdcsystem) );
1388
__DEFINE__(Vmdisc_t*, Vmdcsbrk, (Vmdisc_t*)(&_Vmdcsystem) );
1389
1390
#ifdef NoF
1391
NoF(vmbest)
1392
#endif
1393
1394
#endif
1395
1396