Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/vmalloc/malloc.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_malloc(){}
25
26
#else
27
28
#if _UWIN
29
30
#define calloc ______calloc
31
#define _ast_free ______free
32
#define malloc ______malloc
33
#define mallinfo ______mallinfo
34
#define mallopt ______mallopt
35
#define mstats ______mstats
36
#define realloc ______realloc
37
38
#define _STDLIB_H_ 1
39
40
extern int atexit(void(*)(void));
41
extern char* getenv(const char*);
42
43
#endif
44
45
#include "vmhdr.h"
46
#include <errno.h>
47
48
#if _UWIN
49
50
#include <malloc.h>
51
52
#define _map_malloc 1
53
#define _mal_alloca 1
54
55
#undef calloc
56
#define calloc _ast_calloc
57
#undef _ast_free
58
#define free _ast_free
59
#undef malloc
60
#define malloc _ast_malloc
61
#undef mallinfo
62
typedef struct ______mallinfo Mallinfo_t;
63
#undef mallopt
64
#undef mstats
65
typedef struct ______mstats Mstats_t;
66
#undef realloc
67
#define realloc _ast_realloc
68
69
#endif
70
71
#if __STD_C
72
#define F0(f,t0) f(t0)
73
#define F1(f,t1,a1) f(t1 a1)
74
#define F2(f,t1,a1,t2,a2) f(t1 a1, t2 a2)
75
#else
76
#define F0(f,t0) f()
77
#define F1(f,t1,a1) f(a1) t1 a1;
78
#define F2(f,t1,a1,t2,a2) f(a1, a2) t1 a1; t2 a2;
79
#endif
80
81
/*
82
* define _AST_std_malloc=1 to force the standard malloc
83
* if _map_malloc is also defined then _ast_malloc etc.
84
* will simply call malloc etc.
85
*/
86
87
#if !defined(_AST_std_malloc) && __CYGWIN__
88
#define _AST_std_malloc 1
89
#endif
90
91
/* malloc compatibility functions
92
**
93
** These are aware of debugging/profiling and are driven by the
94
** VMALLOC_OPTIONS environment variable which is a comma or space
95
** separated list of [no]name[=value] options:
96
**
97
** abort if Vmregion==Vmdebug then VM_DBABORT is set,
98
** otherwise _BLD_DEBUG enabled assertions abort()
99
** on failure
100
** break try sbrk() block allocator first
101
** check if Vmregion==Vmbest then the region is checked every op
102
** free disable addfreelist()
103
** keep disable free -- if code works with this enabled then it
104
** probably accesses free'd data
105
** method=m sets Vmregion=m if not defined, m (Vm prefix optional)
106
** may be one of { best debug last profile }
107
** mmap try mmap() block allocator first
108
** period=n sets Vmregion=Vmdebug if not defined, if
109
** Vmregion==Vmdebug the region is checked every n ops
110
** profile=f sets Vmregion=Vmprofile if not set, if
111
** Vmregion==Vmprofile then profile info printed to file f
112
** start=n sets Vmregion=Vmdebug if not defined, if
113
** Vmregion==Vmdebug region checking starts after n ops
114
** trace=f enables tracing to file f
115
** warn=f sets Vmregion=Vmdebug if not defined, if
116
** Vmregion==Vmdebug then warnings printed to file f
117
** watch=a sets Vmregion=Vmdebug if not defined, if
118
** Vmregion==Vmdebug then address a is watched
119
**
120
** Output files are created if they don't exist. &n and /dev/fd/n name
121
** the file descriptor n which must be open for writing. The pattern %p
122
** in a file name is replaced by the process ID.
123
**
124
** VMALLOC_OPTIONS combines the features of these previously used env vars:
125
** { VMCHECK VMDEBUG VMETHOD VMPROFILE VMTRACE }
126
**
127
** Written by Kiem-Phong Vo, [email protected], 01/16/94.
128
*/
129
130
#if _sys_stat
131
#include <sys/stat.h>
132
#endif
133
#include <fcntl.h>
134
135
#ifdef S_IRUSR
136
#define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
137
#else
138
#define CREAT_MODE 0644
139
#endif
140
141
static Vmulong_t _Vmdbstart = 0;
142
static Vmulong_t _Vmdbcheck = 0;
143
static Vmulong_t _Vmdbtime = 0;
144
static int _Vmpffd = -1;
145
146
#if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc
147
148
#if !_map_malloc
149
#undef calloc
150
#undef cfree
151
#undef free
152
#undef mallinfo
153
#undef malloc
154
#undef mallopt
155
#undef memalign
156
#undef mstats
157
#undef realloc
158
#undef valloc
159
160
#if _malloc_hook
161
162
#include <malloc.h>
163
164
#undef calloc
165
#undef cfree
166
#undef free
167
#undef malloc
168
#undef memalign
169
#undef realloc
170
171
#define calloc _ast_calloc
172
#define cfree _ast_cfree
173
#define free _ast_free
174
#define malloc _ast_malloc
175
#define memalign _ast_memalign
176
#define realloc _ast_realloc
177
178
#endif
179
180
#endif
181
182
#if _WINIX
183
184
#include <ast_windows.h>
185
186
#if _UWIN
187
188
#define VMRECORD(p) _vmrecord(p)
189
#define VMBLOCK { int _vmblock = _sigblock();
190
#define VMUNBLOCK _sigunblock(_vmblock); }
191
192
extern int _sigblock(void);
193
extern void _sigunblock(int);
194
extern unsigned long _record[2048];
195
196
__inline Void_t* _vmrecord(Void_t* p)
197
{
198
register unsigned long v = ((unsigned long)p)>>16;
199
200
_record[v>>5] |= 1<<((v&0x1f));
201
return p;
202
}
203
204
#else
205
206
#define getenv(s) lcl_getenv(s)
207
208
static char*
209
lcl_getenv(const char* s)
210
{
211
int n;
212
static char buf[512];
213
214
if (!(n = GetEnvironmentVariable(s, buf, sizeof(buf))) || n > sizeof(buf))
215
return 0;
216
return buf;
217
}
218
219
#endif /* _UWIN */
220
221
#endif /* _WINIX */
222
223
#ifndef VMRECORD
224
#define VMRECORD(p) (p)
225
#define VMBLOCK
226
#define VMUNBLOCK
227
#endif
228
229
#if defined(__EXPORT__)
230
#define extern extern __EXPORT__
231
#endif
232
233
static int _Vmflinit = 0;
234
#define VMFLINIT() \
235
{ if(!_Vmflinit) vmflinit(); \
236
if(_Vmdbcheck) \
237
{ if(_Vmdbtime < _Vmdbstart) _Vmdbtime += 1; \
238
else if((_Vmdbtime += 1) < _Vmdbstart) _Vmdbtime = _Vmdbstart; \
239
if(_Vmdbtime >= _Vmdbstart && (_Vmdbtime % _Vmdbcheck) == 0 && \
240
Vmregion->meth.meth == VM_MTDEBUG) \
241
vmdbcheck(Vmregion); \
242
} \
243
}
244
245
#if __STD_C
246
static int vmflinit(void)
247
#else
248
static int vmflinit()
249
#endif
250
{
251
char* file;
252
int line;
253
Void_t* func;
254
255
/* this must be done now to avoid any inadvertent recursion (more below) */
256
_Vmflinit = 1;
257
VMFLF(Vmregion,file,line,func);
258
259
/* if getenv() calls malloc(), the options may not affect the eventual region */
260
VMOPTIONS();
261
262
/* reset file and line number to correct values for the call */
263
Vmregion->file = file;
264
Vmregion->line = line;
265
Vmregion->func = func;
266
267
return 0;
268
}
269
270
/* use multiple regions to reduce blocking by concurrent threads */
271
#if _mem_mmap_anon || _mem_mmap_zero
272
static Vmalloc_t *Region[64]; /* list of concurrent regions */
273
static unsigned int Regmax = 64; /* max number of regions */
274
#else
275
static Vmalloc_t* Region[1]; /* list of concurrent regions */
276
static unsigned int Regmax = 0;
277
#endif
278
static unsigned int Regnum = 0; /* current #concurrent regions */
279
280
/* statistics */
281
static unsigned int Regopen = 0; /* #allocation calls opened */
282
static unsigned int Reglock = 0; /* #allocation calls locked */
283
static unsigned int Regprobe = 0; /* #probes to find a region */
284
285
int setregmax(int regmax)
286
{
287
int oldmax = Regmax;
288
289
if(regmax >= Regnum && regmax <= sizeof(Region)/sizeof(Region[0]))
290
Regmax = regmax;
291
292
return oldmax;
293
}
294
295
/* return statistics */
296
int _mallocstat(Vmstat_t* st)
297
{
298
Vmstat_t vmst;
299
int k;
300
301
if(vmstat(Vmregion, st) < 0) /* add up all stats */
302
return -1;
303
for(k = 0; k < Regnum; ++k)
304
{ if(!Region[k])
305
continue;
306
if(vmstat(Region[k], &vmst) < 0 )
307
return -1;
308
st->n_busy += vmst.n_busy;
309
st->n_free += vmst.n_free;
310
st->s_busy += vmst.s_busy;
311
st->s_free += vmst.s_free;
312
st->m_busy += vmst.m_busy;
313
st->m_free += vmst.m_free;
314
st->n_seg += vmst.n_seg;
315
st->extent += vmst.extent;
316
}
317
318
st->n_region = Regnum+1;
319
st->n_open = Regopen;
320
st->n_lock = Reglock;
321
st->n_probe = Regprobe;
322
323
return 0;
324
}
325
326
/* find the region that a block was allocated from */
327
static Vmalloc_t* regionof(Void_t* addr)
328
{
329
int k;
330
331
#if USE_NATIVE
332
#define CAUTIOUS 1
333
#else
334
#define CAUTIOUS 0
335
#endif
336
if(CAUTIOUS || Vmregion->meth.meth != VM_MTBEST )
337
{ /* addr will not be dereferenced here */
338
if(vmaddr(Vmregion,addr) == 0 )
339
return Vmregion;
340
for(k = 0; k < Regnum; ++k)
341
if(Region[k] && vmaddr(Region[k], addr) == 0 )
342
return Region[k];
343
return NIL(Vmalloc_t*);
344
}
345
else
346
{ /* fast, but susceptible to bad data */
347
Vmdata_t *vd = SEG(BLOCK(addr))->vmdt;
348
if(Vmregion->data == vd )
349
return Vmregion;
350
for(k = 0; k < Regnum; ++k)
351
if(Region[k] && Region[k]->data == vd)
352
return Region[k];
353
return NIL(Vmalloc_t*);
354
}
355
}
356
357
/* manage a cache of free objects */
358
typedef struct _regfree_s
359
{ struct _regfree_s* next;
360
} Regfree_t;
361
static Regfree_t *Regfree;
362
363
static void addfreelist(Regfree_t* data)
364
{
365
unsigned int k;
366
Regfree_t *head;
367
368
for(k = 0;; ASOLOOP(k) )
369
{ data->next = head = Regfree;
370
if(asocasptr(&Regfree, head, data) == (Void_t*)head )
371
return;
372
}
373
}
374
375
static void clrfreelist()
376
{
377
Regfree_t *list, *next;
378
Vmalloc_t *vm;
379
380
if(!(list = Regfree) )
381
return; /* nothing to do */
382
383
if(asocasptr(&Regfree, list, NIL(Regfree_t*)) != list )
384
return; /* somebody else is doing it */
385
386
for(; list; list = next)
387
{ next = list->next;
388
if(vm = regionof((Void_t*)list))
389
{ if(asocasint(&vm->data->lock, 0, 1) == 0) /* can free this now */
390
{ (void)(*vm->meth.freef)(vm, (Void_t*)list, 1);
391
vm->data->lock = 0;
392
}
393
else addfreelist(list); /* ah well, back in the queue */
394
}
395
}
396
}
397
398
/* get a suitable region to allocate from */
399
typedef struct _regdisc_s
400
{ Vmdisc_t disc;
401
char slop[64]; /* to absorb any extra data in Vmdcsystem */
402
} Regdisc_t;
403
404
static int regexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
405
{
406
if(type == VM_OPEN)
407
{ if(data) /* make vmopen allocate all memory using discipline */
408
*(Void_t**)data = data; /* just make it non-NULL */
409
return 0;
410
}
411
return 0;
412
}
413
414
static Vmalloc_t* getregion(int* local)
415
{
416
Vmalloc_t *vm;
417
int p, pos;
418
419
static unsigned int Rand = 0xdeadbeef; /* a cheap prng */
420
#define RAND() (Rand = Rand*16777617 + 3)
421
422
clrfreelist();
423
424
if(Regmax <= 0 )
425
{ /* uni-process/thread */
426
*local = 1;
427
Vmregion->data->lock = 1;
428
return Vmregion;
429
}
430
else if(asocasint(&Vmregion->data->lock, 0, 1) == 0 )
431
{ /* Vmregion is open, so use it */
432
*local = 1;
433
asoincint(&Regopen);
434
return Vmregion;
435
}
436
437
asoincint(&Regprobe); /* probe Region[] to find an open region */
438
if(Regnum == 0)
439
pos = 0;
440
else for(pos = p = RAND()%Regnum;; )
441
{ if(Region[p] && asocasint(&Region[p]->data->lock, 0, 1) == 0 )
442
{ *local = 1;
443
asoincint(&Regopen);
444
return Region[p];
445
}
446
if((p = (p+1)%Regnum) == pos )
447
break;
448
}
449
450
/* grab the next open slot for a new region */
451
while((p = Regnum) < Regmax)
452
if(asocasint(&Regnum, p, p+1) == p )
453
break;
454
if(p < Regmax) /* this slot is now ours */
455
{ static Regdisc_t Regdisc;
456
if(!Regdisc.disc.exceptf) /* one time initialization */
457
{ GETPAGESIZE(_Vmpagesize);
458
memcpy(&Regdisc, Vmdcsystem, Vmdcsystem->size);
459
Regdisc.disc.round = ROUND(_Vmpagesize, 64*1024);
460
Regdisc.disc.exceptf = regexcept;
461
}
462
463
/**/ASSERT(Region[p] == NIL(Vmalloc_t*));
464
if((vm = vmopen(&Regdisc.disc, Vmbest, VM_SHARE)) != NIL(Vmalloc_t*) )
465
{ vm->data->lock = 1; /* lock new region now */
466
*local = 1;
467
asoincint(&Regopen);
468
return (Region[p] = vm);
469
}
470
else Region[p] = Vmregion; /* better than nothing */
471
}
472
473
/* must return something */
474
vm = Region[pos] ? Region[pos] : Vmregion;
475
if(asocasint(&vm->data->lock, 0, 1) == 0)
476
{ *local = 1;
477
asoincint(&Regopen);
478
}
479
else
480
{ *local = 0;
481
asoincint(&Reglock);
482
}
483
return vm;
484
}
485
486
#if __STD_C
487
extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj)
488
#else
489
extern Void_t* calloc(n_obj, s_obj)
490
reg size_t n_obj;
491
reg size_t s_obj;
492
#endif
493
{
494
Void_t *addr;
495
Vmalloc_t *vm;
496
int local = 0;
497
VMFLINIT();
498
499
vm = getregion(&local);
500
addr = (*vm->meth.resizef)(vm, NIL(Void_t*), n_obj*s_obj, VM_RSZERO, local);
501
if(local)
502
{ /**/ASSERT(vm->data->lock == 1);
503
vm->data->lock = 0;
504
}
505
return VMRECORD(addr);
506
}
507
508
#if __STD_C
509
extern Void_t* malloc(reg size_t size)
510
#else
511
extern Void_t* malloc(size)
512
reg size_t size;
513
#endif
514
{
515
Void_t *addr;
516
Vmalloc_t *vm;
517
int local = 0;
518
VMFLINIT();
519
520
vm = getregion(&local);
521
addr = (*vm->meth.allocf)(vm, size, local);
522
if(local)
523
{ /**/ASSERT(vm->data->lock == 1);
524
vm->data->lock = 0;
525
}
526
return VMRECORD(addr);
527
}
528
529
#if __STD_C
530
extern Void_t* realloc(reg Void_t* data, reg size_t size)
531
#else
532
extern Void_t* realloc(data,size)
533
reg Void_t* data; /* block to be reallocated */
534
reg size_t size; /* new size */
535
#endif
536
{
537
ssize_t copy;
538
Void_t *addr;
539
Vmalloc_t *vm;
540
VMFLINIT();
541
542
if(!data)
543
return malloc(size);
544
else if((vm = regionof(data)) )
545
{ if(vm == Vmregion && vm != Vmheap) /* no multiple region usage here */
546
{ addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0);
547
return VMRECORD(addr);
548
}
549
if(asocasint(&vm->data->lock, 0, 1) == 0 ) /* region is open */
550
{ addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 1);
551
vm->data->lock = 0;
552
return VMRECORD(addr);
553
}
554
else if(Regmax > 0 && Vmregion == Vmheap && (addr = malloc(size)) )
555
{ if((copy = SIZE(BLOCK(data))&~BITS) > size )
556
copy = size;
557
memcpy(addr, data, copy);
558
addfreelist((Regfree_t*)data);
559
return VMRECORD(addr);
560
}
561
else /* this may block but it is the best that we can do now */
562
{ addr = (*vm->meth.resizef)(vm, data, size, VM_RSCOPY|VM_RSMOVE, 0);
563
return VMRECORD(addr);
564
}
565
}
566
else /* not our data */
567
{
568
#if USE_NATIVE
569
#undef realloc /* let the native realloc() take care of it */
570
#if __STD_C
571
extern Void_t* realloc(Void_t*, size_t);
572
#else
573
extern Void_t* realloc();
574
#endif
575
return realloc(data, size);
576
#else
577
return NIL(Void_t*);
578
#endif
579
}
580
}
581
582
#if __STD_C
583
extern void free(reg Void_t* data)
584
#else
585
extern void free(data)
586
reg Void_t* data;
587
#endif
588
{
589
Vmalloc_t *vm;
590
VMFLINIT();
591
592
if(!data || (_Vmassert & VM_keep))
593
return;
594
else if((vm = regionof(data)) )
595
{
596
if(vm == Vmregion && Vmregion != Vmheap || (_Vmassert & VM_free))
597
(void)(*vm->meth.freef)(vm, data, 0);
598
else addfreelist((Regfree_t*)data);
599
return;
600
}
601
else /* not our data */
602
{
603
#if USE_NATIVE
604
#undef free /* let the native free() take care of it */
605
#if __STD_C
606
extern void free(Void_t*);
607
#else
608
extern void free();
609
#endif
610
free(data);
611
#endif
612
return;
613
}
614
}
615
616
#if __STD_C
617
extern void cfree(reg Void_t* data)
618
#else
619
extern void cfree(data)
620
reg Void_t* data;
621
#endif
622
{
623
free(data);
624
}
625
626
#if __STD_C
627
extern Void_t* memalign(reg size_t align, reg size_t size)
628
#else
629
extern Void_t* memalign(align, size)
630
reg size_t align;
631
reg size_t size;
632
#endif
633
{
634
Void_t *addr;
635
Vmalloc_t *vm;
636
int local = 0;
637
VMFLINIT();
638
639
vm = getregion(&local);
640
VMBLOCK
641
addr = (*vm->meth.alignf)(vm, size, align, local);
642
if(local)
643
{ /**/ASSERT(vm->data->lock == 1);
644
vm->data->lock = 0;
645
}
646
VMUNBLOCK
647
return VMRECORD(addr);
648
}
649
650
#if __STD_C
651
extern int posix_memalign(reg Void_t **memptr, reg size_t align, reg size_t size)
652
#else
653
extern int posix_memalign(memptr, align, size)
654
reg Void_t** memptr;
655
reg size_t align;
656
reg size_t size;
657
#endif
658
{
659
Void_t *mem;
660
661
if(align == 0 || (align%sizeof(Void_t*)) != 0 || ((align-1)&align) != 0 )
662
return EINVAL;
663
664
if(!(mem = memalign(align, size)) )
665
return ENOMEM;
666
667
*memptr = mem;
668
return 0;
669
}
670
671
#if __STD_C
672
extern Void_t* valloc(reg size_t size)
673
#else
674
extern Void_t* valloc(size)
675
reg size_t size;
676
#endif
677
{
678
VMFLINIT();
679
680
GETPAGESIZE(_Vmpagesize);
681
return VMRECORD(memalign(_Vmpagesize, size));
682
}
683
684
#if __STD_C
685
extern Void_t* pvalloc(reg size_t size)
686
#else
687
extern Void_t* pvalloc(size)
688
reg size_t size;
689
#endif
690
{
691
VMFLINIT();
692
693
GETPAGESIZE(_Vmpagesize);
694
return VMRECORD(memalign(_Vmpagesize, ROUND(size,_Vmpagesize)) );
695
}
696
697
#if !_PACKAGE_ast
698
#if __STD_C
699
char* strdup(const char* s)
700
#else
701
char* strdup(s)
702
char* s;
703
#endif
704
{
705
char *ns;
706
size_t n;
707
708
if(!s)
709
return NIL(char*);
710
else
711
{ n = strlen(s);
712
if((ns = malloc(n+1)) )
713
memcpy(ns,s,n+1);
714
return ns;
715
}
716
}
717
#endif /* _PACKAGE_ast */
718
719
#if !_lib_alloca || _mal_alloca
720
#ifndef _stk_down
721
#define _stk_down 0
722
#endif
723
typedef struct _alloca_s Alloca_t;
724
union _alloca_u
725
{ struct
726
{ char* addr;
727
Alloca_t* next;
728
} head;
729
char array[ALIGN];
730
};
731
struct _alloca_s
732
{ union _alloca_u head;
733
Vmuchar_t data[1];
734
};
735
736
#if __STD_C
737
extern Void_t* alloca(size_t size)
738
#else
739
extern Void_t* alloca(size)
740
size_t size;
741
#endif
742
{ char array[ALIGN];
743
char* file;
744
int line;
745
Void_t* func;
746
Alloca_t* f;
747
Vmalloc_t *vm;
748
static Alloca_t* Frame;
749
750
VMFLINIT();
751
752
VMFLF(Vmregion,file,line,func); /* save info before freeing frames */
753
754
while(Frame) /* free unused frames */
755
{ if(( _stk_down && &array[0] > Frame->head.head.addr) ||
756
(!_stk_down && &array[0] < Frame->head.head.addr) )
757
{ f = Frame; Frame = f->head.head.next;
758
if((vm = regionof(f)) )
759
(void)(*vm->meth.freef)(vm, f, 0);
760
/* else: something bad happened. just keep going */
761
}
762
else break;
763
}
764
765
Vmregion->file = file; /* restore file/line info before allocation */
766
Vmregion->line = line;
767
Vmregion->func = func;
768
769
f = (Alloca_t*)(*Vmregion->meth.allocf)(Vmregion, size+sizeof(Alloca_t)-1, 0);
770
771
/* if f is NULL, this mimics a stack overflow with a memory error! */
772
f->head.head.addr = &array[0];
773
f->head.head.next = Frame;
774
Frame = f;
775
776
return (Void_t*)f->data;
777
}
778
#endif /*!_lib_alloca || _mal_alloca*/
779
780
#if _map_malloc
781
782
/* not sure of all the implications -- 0 is conservative for now */
783
#define USE_NATIVE 0 /* native free/realloc on non-vmalloc ptrs */
784
785
#else
786
787
#if _malloc_hook
788
789
static void vm_free_hook(void* ptr, const void* caller)
790
{
791
free(ptr);
792
}
793
794
static void* vm_malloc_hook(size_t size, const void* caller)
795
{
796
void* r;
797
798
r = malloc(size);
799
return r;
800
}
801
802
static void* vm_memalign_hook(size_t align, size_t size, const void* caller)
803
{
804
void* r;
805
806
r = memalign(align, size);
807
return r;
808
}
809
810
static void* vm_realloc_hook(void* ptr, size_t size, const void* caller)
811
{
812
void* r;
813
814
r = realloc(ptr, size);
815
return r;
816
}
817
818
static void vm_initialize_hook(void)
819
{
820
__free_hook = vm_free_hook;
821
__malloc_hook = vm_malloc_hook;
822
__memalign_hook = vm_memalign_hook;
823
__realloc_hook = vm_realloc_hook;
824
}
825
826
typeof (__malloc_initialize_hook) __malloc_initialize_hook = vm_initialize_hook;
827
828
#if 0 /* 2012-02-29 this may be needed to cover shared libs */
829
830
void __attribute__ ((constructor)) vm_initialize_initialize_hook(void)
831
{
832
vm_initialize_hook();
833
__malloc_initialize_hook = vm_initialize_hook;
834
}
835
836
#endif
837
838
#else
839
840
/* intercept _* __* __libc_* variants */
841
842
#if __lib__malloc
843
extern Void_t* F2(_calloc, size_t,n, size_t,m) { return calloc(n, m); }
844
extern Void_t F1(_cfree, Void_t*,p) { free(p); }
845
extern Void_t F1(_free, Void_t*,p) { free(p); }
846
extern Void_t* F1(_malloc, size_t,n) { return malloc(n); }
847
#if _lib_memalign
848
extern Void_t* F2(_memalign, size_t,a, size_t,n) { return memalign(a, n); }
849
#endif
850
#if _lib_pvalloc
851
extern Void_t* F1(_pvalloc, size_t,n) { return pvalloc(n); }
852
#endif
853
extern Void_t* F2(_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
854
#if _lib_valloc
855
extern Void_t* F1(_valloc, size_t,n) { return valloc(n); }
856
#endif
857
#endif
858
859
#if _lib___malloc
860
extern Void_t* F2(__calloc, size_t,n, size_t,m) { return calloc(n, m); }
861
extern Void_t F1(__cfree, Void_t*,p) { free(p); }
862
extern Void_t F1(__free, Void_t*,p) { free(p); }
863
extern Void_t* F1(__malloc, size_t,n) { return malloc(n); }
864
#if _lib_memalign
865
extern Void_t* F2(__memalign, size_t,a, size_t,n) { return memalign(a, n); }
866
#endif
867
#if _lib_pvalloc
868
extern Void_t* F1(__pvalloc, size_t,n) { return pvalloc(n); }
869
#endif
870
extern Void_t* F2(__realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
871
#if _lib_valloc
872
extern Void_t* F1(__valloc, size_t,n) { return valloc(n); }
873
#endif
874
#endif
875
876
#if _lib___libc_malloc
877
extern Void_t* F2(__libc_calloc, size_t,n, size_t,m) { return calloc(n, m); }
878
extern Void_t F1(__libc_cfree, Void_t*,p) { free(p); }
879
extern Void_t F1(__libc_free, Void_t*,p) { free(p); }
880
extern Void_t* F1(__libc_malloc, size_t,n) { return malloc(n); }
881
#if _lib_memalign
882
extern Void_t* F2(__libc_memalign, size_t,a, size_t,n) { return memalign(a, n); }
883
#endif
884
#if _lib_pvalloc
885
extern Void_t* F1(__libc_pvalloc, size_t,n) { return pvalloc(n); }
886
#endif
887
extern Void_t* F2(__libc_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
888
#if _lib_valloc
889
extern Void_t* F1(__libc_valloc, size_t,n) { return valloc(n); }
890
#endif
891
#endif
892
893
#endif /* _malloc_hook */
894
895
#endif /* _map_malloc */
896
897
#undef extern
898
899
#if _hdr_malloc /* need the mallint interface for statistics, etc. */
900
901
#undef calloc
902
#define calloc ______calloc
903
#undef cfree
904
#define cfree ______cfree
905
#undef free
906
#define free ______free
907
#undef malloc
908
#define malloc ______malloc
909
#undef pvalloc
910
#define pvalloc ______pvalloc
911
#undef realloc
912
#define realloc ______realloc
913
#undef valloc
914
#define valloc ______valloc
915
916
#if !_UWIN
917
918
#include <malloc.h>
919
920
typedef struct mallinfo Mallinfo_t;
921
typedef struct mstats Mstats_t;
922
923
#endif
924
925
#if defined(__EXPORT__)
926
#define extern __EXPORT__
927
#endif
928
929
#if _lib_mallopt
930
#if __STD_C
931
extern int mallopt(int cmd, int value)
932
#else
933
extern int mallopt(cmd, value)
934
int cmd;
935
int value;
936
#endif
937
{
938
VMFLINIT();
939
return 0;
940
}
941
#endif /*_lib_mallopt*/
942
943
#if _lib_mallinfo && _mem_arena_mallinfo
944
#if __STD_C
945
extern Mallinfo_t mallinfo(void)
946
#else
947
extern Mallinfo_t mallinfo()
948
#endif
949
{
950
Vmstat_t sb;
951
Mallinfo_t mi;
952
953
VMFLINIT();
954
memset(&mi,0,sizeof(mi));
955
if(vmstat(Vmregion,&sb) >= 0)
956
{ mi.arena = sb.extent;
957
mi.ordblks = sb.n_busy+sb.n_free;
958
mi.uordblks = sb.s_busy;
959
mi.fordblks = sb.s_free;
960
}
961
return mi;
962
}
963
#endif /* _lib_mallinfo */
964
965
#if _lib_mstats && _mem_bytes_total_mstats
966
#if __STD_C
967
extern Mstats_t mstats(void)
968
#else
969
extern Mstats_t mstats()
970
#endif
971
{
972
Vmstat_t sb;
973
Mstats_t ms;
974
975
VMFLINIT();
976
memset(&ms,0,sizeof(ms));
977
if(vmstat(Vmregion,&sb) >= 0)
978
{ ms.bytes_total = sb.extent;
979
ms.chunks_used = sb.n_busy;
980
ms.bytes_used = sb.s_busy;
981
ms.chunks_free = sb.n_free;
982
ms.bytes_free = sb.s_free;
983
}
984
return ms;
985
}
986
#endif /*_lib_mstats*/
987
988
#undef extern
989
990
#endif/*_hdr_malloc*/
991
992
#else
993
994
/*
995
* even though there is no malloc override, still provide
996
* _ast_* counterparts for object compatibility
997
*/
998
999
#define setregmax(n)
1000
1001
#undef calloc
1002
extern Void_t* calloc _ARG_((size_t, size_t));
1003
1004
#undef cfree
1005
extern void cfree _ARG_((Void_t*));
1006
1007
#undef free
1008
extern void free _ARG_((Void_t*));
1009
1010
#undef malloc
1011
extern Void_t* malloc _ARG_((size_t));
1012
1013
#if _lib_memalign
1014
#undef memalign
1015
extern Void_t* memalign _ARG_((size_t, size_t));
1016
#endif
1017
1018
#if _lib_pvalloc
1019
#undef pvalloc
1020
extern Void_t* pvalloc _ARG_((size_t));
1021
#endif
1022
1023
#undef realloc
1024
extern Void_t* realloc _ARG_((Void_t*, size_t));
1025
1026
#if _lib_valloc
1027
#undef valloc
1028
extern Void_t* valloc _ARG_((size_t));
1029
#endif
1030
1031
#if defined(__EXPORT__)
1032
#define extern __EXPORT__
1033
#endif
1034
1035
#if !_malloc_hook
1036
1037
extern Void_t F1(_ast_free, Void_t*,p) { free(p); }
1038
extern Void_t* F1(_ast_malloc, size_t,n) { return malloc(n); }
1039
#if _lib_memalign
1040
extern Void_t* F2(_ast_memalign, size_t,a, size_t,n) { return memalign(a, n); }
1041
#endif
1042
extern Void_t* F2(_ast_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
1043
1044
#endif
1045
1046
extern Void_t* F2(_ast_calloc, size_t,n, size_t,m) { return calloc(n, m); }
1047
extern Void_t F1(_ast_cfree, Void_t*,p) { free(p); }
1048
#if _lib_pvalloc
1049
extern Void_t* F1(_ast_pvalloc, size_t,n) { return pvalloc(n); }
1050
#endif
1051
#if _lib_valloc
1052
extern Void_t* F1(_ast_valloc, size_t,n) { return valloc(n); }
1053
#endif
1054
1055
#undef extern
1056
1057
#if _hdr_malloc
1058
1059
#undef mallinfo
1060
#undef mallopt
1061
#undef mstats
1062
1063
#define calloc ______calloc
1064
#define cfree ______cfree
1065
#define free ______free
1066
#define malloc ______malloc
1067
#define pvalloc ______pvalloc
1068
#define realloc ______realloc
1069
#define valloc ______valloc
1070
1071
#if !_UWIN
1072
1073
#if !_malloc_hook
1074
1075
#include <malloc.h>
1076
1077
#endif
1078
1079
typedef struct mallinfo Mallinfo_t;
1080
typedef struct mstats Mstats_t;
1081
1082
#endif
1083
1084
#if defined(__EXPORT__)
1085
#define extern __EXPORT__
1086
#endif
1087
1088
#if _lib_mallopt
1089
extern int F2(_ast_mallopt, int,cmd, int,value) { return mallopt(cmd, value); }
1090
#endif
1091
1092
#if _lib_mallinfo && _mem_arena_mallinfo
1093
extern Mallinfo_t F0(_ast_mallinfo, void) { return mallinfo(); }
1094
#endif
1095
1096
#if _lib_mstats && _mem_bytes_total_mstats
1097
extern Mstats_t F0(_ast_mstats, void) { return mstats(); }
1098
#endif
1099
1100
#undef extern
1101
1102
#endif /*_hdr_malloc*/
1103
1104
#endif /*!_std_malloc*/
1105
1106
#if __STD_C
1107
static Vmulong_t atou(char** sp)
1108
#else
1109
static Vmulong_t atou(sp)
1110
char** sp;
1111
#endif
1112
{
1113
char* s = *sp;
1114
Vmulong_t v = 0;
1115
1116
if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X') )
1117
{ for(s += 2; *s; ++s)
1118
{ if(*s >= '0' && *s <= '9')
1119
v = (v << 4) + (*s - '0');
1120
else if(*s >= 'a' && *s <= 'f')
1121
v = (v << 4) + (*s - 'a') + 10;
1122
else if(*s >= 'A' && *s <= 'F')
1123
v = (v << 4) + (*s - 'A') + 10;
1124
else break;
1125
}
1126
}
1127
else
1128
{ for(; *s; ++s)
1129
{ if(*s >= '0' && *s <= '9')
1130
v = v*10 + (*s - '0');
1131
else break;
1132
}
1133
}
1134
1135
*sp = s;
1136
return v;
1137
}
1138
1139
#if __STD_C
1140
static char* insertpid(char* begs, char* ends)
1141
#else
1142
static char* insertpid(begs,ends)
1143
char* begs;
1144
char* ends;
1145
#endif
1146
{ int pid;
1147
char* s;
1148
1149
if((pid = getpid()) < 0)
1150
return NIL(char*);
1151
1152
s = ends;
1153
do
1154
{ if(s == begs)
1155
return NIL(char*);
1156
*--s = '0' + pid%10;
1157
} while((pid /= 10) > 0);
1158
while(s < ends)
1159
*begs++ = *s++;
1160
1161
return begs;
1162
}
1163
1164
#define FD_PRIVATE (3*OPEN_MAX/4)
1165
1166
#if __STD_C
1167
int _vmfd(int fd)
1168
#else
1169
int _vmfd(fd)
1170
int fd;
1171
#endif
1172
{
1173
int pd;
1174
1175
if (fd >= 0)
1176
{
1177
if (fd < FD_PRIVATE && (pd = fcntl(fd, F_DUPFD, FD_PRIVATE)) >= 0)
1178
{
1179
close(fd);
1180
fd = pd;
1181
}
1182
#ifdef FD_CLOEXEC
1183
fcntl(fd, F_SETFD, FD_CLOEXEC);
1184
#endif
1185
}
1186
return fd;
1187
}
1188
1189
#if __STD_C
1190
static int createfile(char* file)
1191
#else
1192
static int createfile(file)
1193
char* file;
1194
#endif
1195
{
1196
char buf[1024];
1197
char *next, *endb;
1198
int fd;
1199
1200
next = buf;
1201
endb = buf + sizeof(buf);
1202
while(*file)
1203
{ if(*file == '%')
1204
{ switch(file[1])
1205
{
1206
case 'p' :
1207
if(!(next = insertpid(next,endb)) )
1208
return -1;
1209
file += 2;
1210
break;
1211
default :
1212
goto copy;
1213
}
1214
}
1215
else
1216
{ copy:
1217
*next++ = *file++;
1218
}
1219
1220
if(next >= endb)
1221
return -1;
1222
}
1223
1224
*next = '\0';
1225
file = buf;
1226
if (*file == '&' && *(file += 1) || strncmp(file, "/dev/fd/", 8) == 0 && *(file += 8))
1227
fd = dup((int)atou(&file));
1228
else if (*file)
1229
{
1230
#if _PACKAGE_ast
1231
fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, CREAT_MODE);
1232
#else
1233
fd = creat(file, CREAT_MODE);
1234
#endif
1235
fd = _vmfd(fd);
1236
}
1237
else
1238
return -1;
1239
#if _PACKAGE_ast
1240
#ifdef FD_CLOEXEC
1241
if (fd >= 0)
1242
fcntl(fd, F_SETFD, FD_CLOEXEC);
1243
#endif
1244
#endif
1245
return fd;
1246
}
1247
1248
#if __STD_C
1249
static void pfprint(void)
1250
#else
1251
static void pfprint()
1252
#endif
1253
{
1254
if(Vmregion->meth.meth == VM_MTPROFILE)
1255
vmprofile(Vmregion,_Vmpffd);
1256
}
1257
1258
/*
1259
* initialize runtime options from the VMALLOC_OPTIONS env var
1260
*/
1261
1262
#define COPY(t,e,f) while ((*t = *f++) && t < e) t++
1263
1264
#if __STD_C
1265
void _vmoptions(void)
1266
#else
1267
void _vmoptions()
1268
#endif
1269
{
1270
Vmalloc_t* vm = 0;
1271
char* trace = 0;
1272
char* s;
1273
char* t;
1274
char* v;
1275
Vmulong_t n;
1276
int fd;
1277
char buf[1024];
1278
1279
_Vmoptions = 1;
1280
t = buf;
1281
v = &buf[sizeof(buf)-1];
1282
if (s = getenv("VMALLOC_OPTIONS"))
1283
COPY(t, v, s);
1284
if (t > buf)
1285
{
1286
*t = 0;
1287
s = buf;
1288
for (;;)
1289
{
1290
while (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
1291
s++;
1292
if (!*(t = s))
1293
break;
1294
v = 0;
1295
while (*s)
1296
if (*s == ',' || *s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
1297
{
1298
*s++ = 0;
1299
break;
1300
}
1301
else if (!v && *s == '=')
1302
{
1303
*s++ = 0;
1304
if (!*(v = s))
1305
v = 0;
1306
}
1307
else
1308
s++;
1309
if (t[0] == 'n' && t[1] == 'o')
1310
continue;
1311
switch (t[0])
1312
{
1313
case 'a': /* abort */
1314
if (!vm)
1315
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1316
if (vm && vm->meth.meth == VM_MTDEBUG)
1317
vmset(vm, VM_DBABORT, 1);
1318
else
1319
_Vmassert |= VM_abort;
1320
break;
1321
case 'b': /* break */
1322
_Vmassert |= VM_break;
1323
break;
1324
case 'c': /* check */
1325
_Vmassert |= VM_check;
1326
break;
1327
case 'f': /* free */
1328
_Vmassert |= VM_free;
1329
break;
1330
case 'k': /* keep */
1331
_Vmassert |= VM_keep;
1332
break;
1333
case 'm':
1334
if (v)
1335
switch (t[1])
1336
{
1337
case 'e': /* method=METHOD */
1338
if (!vm)
1339
{
1340
if ((v[0] == 'V' || v[0] == 'v') && (v[1] == 'M' || v[1] == 'm'))
1341
v += 2;
1342
if (strcmp(v, "debug") == 0)
1343
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1344
else if (strcmp(v, "profile") == 0)
1345
vm = vmopen(Vmdcsystem, Vmprofile, 0);
1346
else if (strcmp(v, "last") == 0)
1347
vm = vmopen(Vmdcsystem, Vmlast, 0);
1348
else if (strcmp(v, "best") == 0)
1349
vm = Vmheap;
1350
}
1351
break;
1352
case 'm': /* mmap */
1353
_Vmassert |= VM_mmap;
1354
break;
1355
}
1356
break;
1357
case 'p':
1358
if (v)
1359
switch (t[1])
1360
{
1361
case 'e': /* period=<count> */
1362
if (!vm)
1363
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1364
if (vm && vm->meth.meth == VM_MTDEBUG)
1365
_Vmdbcheck = atou(&v);
1366
break;
1367
case 'r': /* profile=<path> */
1368
if (!vm)
1369
vm = vmopen(Vmdcsystem, Vmprofile, 0);
1370
if (v && vm && vm->meth.meth == VM_MTPROFILE)
1371
_Vmpffd = createfile(v);
1372
break;
1373
}
1374
break;
1375
case 's': /* start=<count> */
1376
if (!vm)
1377
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1378
if (v && vm && vm->meth.meth == VM_MTDEBUG)
1379
_Vmdbstart = atou(&v);
1380
break;
1381
case 't': /* trace=<path> */
1382
trace = v;
1383
break;
1384
case 'w':
1385
if (t[1] == 'a')
1386
switch (t[2])
1387
{
1388
case 'r': /* warn=<path> */
1389
if (!vm)
1390
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1391
if (v && vm && vm->meth.meth == VM_MTDEBUG && (fd = createfile(v)) >= 0)
1392
vmdebug(fd);
1393
break;
1394
case 't': /* watch=<addr> */
1395
if (!vm)
1396
vm = vmopen(Vmdcsystem, Vmdebug, 0);
1397
if (v && vm && vm->meth.meth == VM_MTDEBUG && (n = atou(&v)) >= 0)
1398
vmdbwatch((Void_t*)n);
1399
break;
1400
}
1401
break;
1402
}
1403
}
1404
}
1405
1406
/* slip in the new region now so that malloc() will work fine */
1407
1408
if (vm)
1409
{
1410
if (vm->meth.meth == VM_MTDEBUG)
1411
_Vmdbcheck = 1;
1412
Vmregion = vm;
1413
}
1414
1415
/* enable tracing -- this currently disables multiple regions */
1416
1417
if (trace)
1418
{
1419
setregmax(0);
1420
if ((fd = createfile(trace)) >= 0)
1421
{
1422
vmset(Vmregion, VM_TRACE, 1);
1423
vmtrace(fd);
1424
}
1425
}
1426
else if (Vmregion != Vmheap || asometh(0, 0)->type == ASO_SIGNAL)
1427
setregmax(0);
1428
1429
/* make sure that profile data is output upon exiting */
1430
1431
if (vm && vm->meth.meth == VM_MTPROFILE)
1432
{
1433
if (_Vmpffd < 0)
1434
_Vmpffd = 2;
1435
/* this may wind up calling malloc(), but region is ok now */
1436
atexit(pfprint);
1437
}
1438
else if (_Vmpffd >= 0)
1439
{
1440
close(_Vmpffd);
1441
_Vmpffd = -1;
1442
}
1443
}
1444
1445
/*
1446
* ast semi-private workaround for system functions
1447
* that misbehave by passing bogus addresses to free()
1448
*
1449
* not prototyped in any header to keep it ast semi-private
1450
*
1451
* to keep malloc() data by disabling free()
1452
* extern _vmkeep(int);
1453
* int r = _vmkeep(1);
1454
* and to restore to the previous state
1455
* (void)_vmkeep(r);
1456
*/
1457
1458
int
1459
#if __STD_C
1460
_vmkeep(int v)
1461
#else
1462
_vmkeep(v)
1463
int v;
1464
#endif
1465
{
1466
int r;
1467
1468
r = !!(_Vmassert & VM_keep);
1469
if (v)
1470
_Vmassert |= VM_keep;
1471
else
1472
_Vmassert &= ~VM_keep;
1473
return r;
1474
}
1475
1476
#endif /*_UWIN*/
1477
1478