xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/vmalloc/vmopen.c (revision 1e8d79d21400b4e47d64ce367181e7e5ce992649)
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 <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23 
24 void _STUB_vmopen(){}
25 
26 #else
27 
28 #include	"vmhdr.h"
29 
30 /*	Opening a new region of allocation.
31 **	Note that because of possible exotic memory types,
32 **	all region data must be stored within the space given
33 **	by the discipline.
34 **
35 **	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
36 */
37 
38 /* this structure lives in the top data segment of the region */
39 typedef struct _vminit_s
40 {	union
41 	{ Vmdata_t	vd;		/* root of usable data space  	*/
42 	  Vmuchar_t	a[ROUND(sizeof(Vmdata_t),ALIGN)];
43 	} vd;
44 	union
45 	{ Vmalloc_t	vm;		/* embedded region if needed	*/
46 	  Vmuchar_t	a[ROUND(sizeof(Vmalloc_t),ALIGN)];
47 	} vm;
48 	union
49 	{ Seg_t		seg;		/* space for segment		*/
50 	  Vmuchar_t	a[ROUND(sizeof(Seg_t),ALIGN)];
51 	} seg;
52 	Block_t		block[16];	/* space for a few blocks	*/
53 } Vminit_t;
54 
55 #if __STD_C
56 Vmalloc_t* vmopen(Vmdisc_t* disc, Vmethod_t* meth, int mode)
57 #else
58 Vmalloc_t* vmopen(disc, meth, mode)
59 Vmdisc_t*	disc;	/* discipline to get segments	*/
60 Vmethod_t*	meth;	/* method to manage space	*/
61 int		mode;	/* type of region		*/
62 #endif
63 {
64 	Vmalloc_t	*vm, *vmp, vmproto;
65 	Vmdata_t	*vd;
66 	Vminit_t	*init;
67 	size_t		algn, size, incr;
68 	Block_t		*bp, *np;
69 	Seg_t		*seg;
70 	Vmuchar_t	*addr;
71 	int		rv;
72 
73 	if(!meth || !disc || !disc->memoryf )
74 		return NIL(Vmalloc_t*);
75 
76 	GETPAGESIZE(_Vmpagesize);
77 
78 	vmp = &vmproto; /* avoid memory allocation here! */
79 	memset(vmp, 0, sizeof(Vmalloc_t));
80 	memcpy(&vmp->meth, meth, sizeof(Vmethod_t));
81 	vmp->disc = disc;
82 
83 	mode &= VM_FLAGS; /* start with user-settable flags */
84 	size = 0;
85 
86 	if(disc->exceptf)
87 	{	addr = NIL(Vmuchar_t*);
88 		if((rv = (*disc->exceptf)(vmp,VM_OPEN,(Void_t*)(&addr),disc)) < 0)
89 			return NIL(Vmalloc_t*);
90 		else if(rv == 0 )
91 		{	if(addr) /* vm itself is in memory from disc->memoryf */
92 				mode |= VM_MEMORYF;
93 		}
94 		else if(rv > 0) /* the data section is being restored */
95 		{	if(!(init = (Vminit_t*)addr) )
96 				return NIL(Vmalloc_t*);
97 			size = -1; /* to tell that addr was not from disc->memoryf */
98 			vd = &init->vd.vd; /**/ASSERT(VLONG(vd)%ALIGN == 0);
99 			goto done;
100 		}
101 	}
102 
103 	/* make sure vd->incr is properly rounded and get initial memory */
104 	incr = disc->round <= 0 ? _Vmpagesize : disc->round;
105 	incr = MULTIPLE(incr,ALIGN);
106 	size = ROUND(sizeof(Vminit_t),incr); /* get initial memory */
107 	if(!(addr = (Vmuchar_t*)(*disc->memoryf)(vmp, NIL(Void_t*), 0, size, disc)) )
108 		return NIL(Vmalloc_t*);
109 	memset(addr, 0, size);
110 
111 	/* initialize region data */
112 	algn = (size_t)(VLONG(addr)%ALIGN);
113 	init = (Vminit_t*)(addr + (algn ? ALIGN-algn : 0)); /**/ASSERT(VLONG(init)%ALIGN == 0);
114 	vd = &init->vd.vd; /**/ASSERT(VLONG(vd)%ALIGN == 0);
115 	vd->mode = mode | meth->meth;
116 	vd->incr = incr;
117 	vd->pool = 0;
118 	vd->free = vd->wild = NIL(Block_t*);
119 
120 	if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
121 	{	int	k;
122 		vd->root = NIL(Block_t*);
123 		for(k = S_TINY-1; k >= 0; --k)
124 			TINY(vd)[k] = NIL(Block_t*);
125 		for(k = S_CACHE; k >= 0; --k)
126 			CACHE(vd)[k] = NIL(Block_t*);
127 	}
128 
129 	vd->seg = &init->seg.seg; /**/ ASSERT(VLONG(vd->seg)%ALIGN == 0);
130 	seg = vd->seg;
131 	seg->next = NIL(Seg_t*);
132 	seg->vmdt = vd;
133 	seg->addr = (Void_t*)addr;
134 	seg->extent = size;
135 	seg->baddr = addr + size;
136 	seg->size = size; /* Note: this size is unusually large to mark seg as
137 			   the root segment and can be freed only at closing */
138 	seg->free = NIL(Block_t*);
139 
140 	/* make a data block out of the remainder */
141 	bp = SEGBLOCK(seg);
142 	SEG(bp) = seg;
143 	size = ((seg->baddr - (Vmuchar_t*)bp)/ALIGN) * ALIGN; /**/ ASSERT(size > 0);
144 	SIZE(bp) = size - 2*sizeof(Head_t); /**/ASSERT(SIZE(bp) > 0 && (SIZE(bp)%ALIGN) == 0);
145 	SELF(bp) = bp;
146 	/**/ ASSERT(SIZE(bp)%ALIGN == 0);
147 	/**/ ASSERT(VLONG(bp)%ALIGN == 0);
148 
149 	/* make a fake header for next block in case of noncontiguous segments */
150 	np = NEXT(bp);
151 	SEG(np) = seg;
152 	SIZE(np) = BUSY|PFREE;
153 
154 	if(vd->mode&(VM_MTLAST|VM_MTPOOL))
155 		seg->free = bp;
156 	else	vd->wild = bp;
157 
158 done:	/* now make the region handle */
159 	if(vd->mode&VM_MEMORYF)
160 		vm = &init->vm.vm;
161 	else if(!(vm = vmalloc(Vmheap, sizeof(Vmalloc_t))) )
162 	{	if(size > 0)
163 			(void)(*disc->memoryf)(vmp, addr, size, 0, disc);
164 		return NIL(Vmalloc_t*);
165 	}
166 	memcpy(vm, vmp, sizeof(Vmalloc_t));
167 	vm->data = vd;
168 
169 	if(disc->exceptf) /* signaling that vmopen succeeded */
170 		(void)(*disc->exceptf)(vm, VM_ENDOPEN, NIL(Void_t*), disc);
171 
172 	/* add to the linked list of regions */
173 	_vmlock(NIL(Vmalloc_t*), 1);
174 	vm->next = Vmheap->next; Vmheap->next = vm;
175 	_vmlock(NIL(Vmalloc_t*), 0);
176 
177 	return vm;
178 }
179 
180 #endif
181