xref: /titanic_41/usr/src/lib/libast/common/vmalloc/vmopen.c (revision d29f5a711240f866521445b1656d114da090335e)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 typedef struct _vminit_
39 {
40 	Vmdata_t	vd;		/* space for the region itself	*/
41 	Seg_t		seg;		/* space for segment		*/
42 	Block_t		block;		/* space for a block		*/
43 	Head_t		head;		/* space for the fake header	*/
44 	char		a[3*ALIGN];	/* extra to fuss with alignment	*/
45 } Vminit_t;
46 
47 #if __STD_C
48 Vmalloc_t* vmopen(Vmdisc_t* disc, Vmethod_t* meth, int mode)
49 #else
50 Vmalloc_t* vmopen(disc, meth, mode)
51 Vmdisc_t*	disc;	/* discipline to get segments	*/
52 Vmethod_t*	meth;	/* method to manage space	*/
53 int		mode;	/* type of region		*/
54 #endif
55 {
56 	reg Vmalloc_t*	vm;
57 	reg Vmdata_t*	vd;
58 	reg size_t	s, a, incr;
59 	reg Block_t*	b;
60 	reg Seg_t*	seg;
61 	Vmuchar_t*	addr;
62 	reg Vmemory_f	memoryf;
63 	reg int		e;
64 
65 	if(!meth || !disc || !(memoryf = disc->memoryf) )
66 		return NIL(Vmalloc_t*);
67 
68 	GETPAGESIZE(_Vmpagesize);
69 
70 	/* note that Vmalloc_t space must be local to process since that's
71 	   where the meth&disc function addresses are going to be stored */
72 	if(!(vm = (Vmalloc_t*)vmalloc(Vmheap,sizeof(Vmalloc_t))) )
73 		return NIL(Vmalloc_t*);
74 	vm->meth = *meth;
75 	vm->disc = disc;
76 	vm->file = NIL(char*);
77 	vm->line = 0;
78 
79 	if(disc->exceptf)
80 	{	addr = NIL(Vmuchar_t*);
81 		if((e = (*disc->exceptf)(vm,VM_OPEN,(Void_t*)(&addr),disc)) != 0)
82 		{	if(e < 0 || !addr)
83 				goto open_error;
84 
85 			/* align this address */
86 			if((a = (size_t)(VLONG(addr)%ALIGN)) != 0)
87 				addr += ALIGN-a;
88 
89 			/* see if it's a valid region */
90 			vd = (Vmdata_t*)addr;
91 			if((vd->mode&meth->meth) != 0)
92 			{	vm->data = vd;
93 				return vm;
94 			}
95 			else
96 			{ open_error:
97 				vmfree(Vmheap,vm);
98 				return NIL(Vmalloc_t*);
99 			}
100 		}
101 	}
102 
103 	/* make sure vd->incr is properly rounded */
104 	incr = disc->round <= 0 ? _Vmpagesize : disc->round;
105 	incr = MULTIPLE(incr,ALIGN);
106 
107 	/* get space for region data */
108 	s = ROUND(sizeof(Vminit_t),incr);
109 	if(!(addr = (Vmuchar_t*)(*memoryf)(vm,NIL(Void_t*),0,s,disc)) )
110 	{	vmfree(Vmheap,vm);
111 		return NIL(Vmalloc_t*);
112 	}
113 
114 	/* make sure that addr is aligned */
115 	if((a = (size_t)(VLONG(addr)%ALIGN)) != 0)
116 		addr += ALIGN-a;
117 
118 	/* initialize region */
119 	vd = (Vmdata_t*)addr;
120 	vd->mode = (mode&VM_FLAGS) | meth->meth;
121 	vd->incr = incr;
122 	vd->pool = 0;
123 	vd->free = vd->wild = NIL(Block_t*);
124 
125 	if(vd->mode&(VM_TRACE|VM_MTDEBUG))
126 		vd->mode &= ~VM_TRUST;
127 
128 	if(vd->mode&(VM_MTBEST|VM_MTDEBUG|VM_MTPROFILE))
129 	{	vd->root = NIL(Block_t*);
130 		for(e = S_TINY-1; e >= 0; --e)
131 			TINY(vd)[e] = NIL(Block_t*);
132 		for(e = S_CACHE; e >= 0; --e)
133 			CACHE(vd)[e] = NIL(Block_t*);
134 		incr = sizeof(Vmdata_t);
135 	}
136 	else	incr = OFFSET(Vmdata_t,root);
137 
138 	vd->seg = (Seg_t*)(addr + ROUND(incr,ALIGN));
139 	/**/ ASSERT(VLONG(vd->seg)%ALIGN == 0);
140 
141 	seg = vd->seg;
142 	seg->next = NIL(Seg_t*);
143 	seg->vm = vm;
144 	seg->addr = (Void_t*)(addr - (a ? ALIGN-a : 0));
145 	seg->extent = s;
146 	seg->baddr = addr + s - (a ? ALIGN : 0);
147 	seg->size = s;	/* this size is larger than usual so that the segment
148 			   will not be freed until the region is closed. */
149 	seg->free = NIL(Block_t*);
150 
151 	/* make a data block out of the remainder */
152 	b = SEGBLOCK(seg);
153 	SEG(b) = seg;
154 	SIZE(b) = seg->baddr - (Vmuchar_t*)b - 2*sizeof(Head_t);
155 	*SELF(b) = b;
156 	/**/ ASSERT(SIZE(b)%ALIGN == 0);
157 	/**/ ASSERT(VLONG(b)%ALIGN == 0);
158 
159 	/* make a fake header for next block in case of noncontiguous segments */
160 	SEG(NEXT(b)) = seg;
161 	SIZE(NEXT(b)) = BUSY|PFREE;
162 
163 	if(vd->mode&(VM_MTLAST|VM_MTPOOL))
164 		seg->free = b;
165 	else	vd->wild = b;
166 
167 	vm->data = vd;
168 
169 	/* put into linked list of regions */
170 	vm->next = Vmheap->next;
171 	Vmheap->next = vm;
172 
173 	return vm;
174 }
175 
176 #endif
177