1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
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
24void _STUB_vmmopen(){}
25
26#else
27
28#include	"vmhdr.h"
29
30#if _sys_stat
31#include	<sys/stat.h>
32#endif
33#include	<fcntl.h>
34
35#ifdef S_IRUSR
36#define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
37#else
38#define CREAT_MODE	0644
39#endif
40
41#if _lib_mmap
42#include	<sys/mman.h>
43#else
44#define mmap(a,b,c,d,e,f)	MAP_FAILED
45#define munmap(a,b)		MAP_FAILED
46#endif
47
48/* Create a region to allocate based on mmap()
49**
50** Written by Kiem-Phong Vo (kpv@research.att.com)
51*/
52
53#ifndef MAP_FAILED
54#define MAP_FAILED	(void*)(-1)
55#endif
56
57#define	MM_MAGIC	(('V'<<24) | ('M'<<16) | ('A'<<8) | ('P'))
58#define MM_ROUND	(64*1024)
59#define MM_START	ROUND(sizeof(Mmvm_t),ALIGN)
60
61typedef struct _user_s
62{	struct _user_s*	next;	/* link list		*/
63	int		key;	/* identifying key	*/
64	Void_t*		data;	/* data to be returned	*/
65} User_t;
66
67typedef struct _mmvm_s
68{
69	Vmulong_t	magic;	/* magic bytes		*/
70	Void_t*		base;	/* base of the map	*/
71	size_t		size;	/* current size		*/
72	size_t		busy;	/* amount in use	*/
73	size_t		round;	/* amount to round to	*/
74	User_t*		user;	/* some user data	*/
75} Mmvm_t;
76
77typedef struct _mmvmdisc_s
78{
79	Vmdisc_t	disc;	/* Vmalloc discipline	*/
80	int		fd;	/* file descriptor	*/
81	Mmvm_t*		mm;	/* mmap data		*/
82} Mmvmdisc_t;
83
84#if __STD_C
85static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm)
86#else
87static int mmvminit(file, addr, round, mm)
88char*	file;	/* file to map data from	*/
89Void_t*	addr;	/* desired starting address	*/
90size_t	round;	/* amount to round requests 	*/
91Mmvm_t*	mm;	/* to return some mapped info	*/
92#endif
93{
94	int		fd;
95	off_t		size;
96	Void_t		*base;
97	Mmvm_t		*hdr;
98
99	base = NIL(Void_t*);
100	if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0)
101	{	if((size = lseek(fd, (off_t)0, 2)) < 0)
102			goto done;
103		else if(size == 0)
104			goto new_f;
105
106		/* read the header */
107		if(lseek(fd, (off_t)0, 0) != (off_t)0)
108			goto done;
109		if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t))
110			goto done;
111		if(mm->magic != MM_MAGIC || !mm->base ||
112		   (off_t)mm->size != size || mm->busy > mm->size )
113			goto done;
114		base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE,
115				     MAP_FIXED|MAP_SHARED, fd, (off_t)0 );
116		if(base == (Void_t*)MAP_FAILED)
117			base = NIL(Void_t*);
118	}
119	else
120	{	if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0)
121			goto done;
122
123	new_f:	/* create an initial set of data */
124		size = (off_t)round;
125		if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 )
126			goto done;
127
128		base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE,
129				     (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 );
130		if(base == (Void_t*)MAP_FAILED)
131			base = NIL(Void_t*);
132		if(!base)
133			goto done;
134
135		/* write magic number */
136		hdr = (Mmvm_t*)base;
137		hdr->magic = MM_MAGIC;
138		hdr->base  = base;
139		hdr->size  = size;
140		hdr->busy  = MM_START;
141		hdr->round = round;
142		hdr->user  = NIL(User_t*);
143		memcpy(mm, hdr, sizeof(Mmvm_t));
144	}
145
146done:
147	if(!base)
148	{	if(fd >= 0)
149			close(fd);
150		fd = -1;
151	}
152
153	return fd;
154}
155
156
157#if __STD_C
158static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr,
159			size_t csize, size_t nsize, Vmdisc_t* disc)
160#else
161static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc)
162Vmalloc_t*	vm;
163Void_t*		caddr;
164size_t		csize;
165size_t		nsize;
166Vmdisc_t*	disc;
167#endif
168{
169	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
170
171	if(mmdc->fd < 0 || !mmdc->mm)
172		return NIL(Void_t*);
173
174#define MMADDR(b)	((Void_t*)(((Vmuchar_t*)b) + MM_START) )
175	if(caddr && caddr != MMADDR(mmdc->mm->base) )
176		return NIL(Void_t*);
177	if(nsize < csize)
178		return NIL(Void_t*);
179
180	if(nsize > mmdc->mm->size-MM_START)
181	{	/* base and size of new map */
182		caddr = mmdc->mm->base;
183		csize = MM_START + nsize +
184			((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
185		csize = ROUND(csize, disc->round);
186
187		/* make room for new space */
188		if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
189		   write(mmdc->fd, "", 1) != 1 )
190			return NIL(Void_t*);
191
192		/* remap the space */
193		(void)munmap(caddr, mmdc->mm->size);
194		caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE,
195				     MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 );
196		if(caddr == (Void_t*)MAP_FAILED)
197			caddr = NIL(Void_t*);
198		if(caddr)
199			mmdc->mm->size = csize;
200		else	/* bad problem */
201		{	close(mmdc->fd);
202			mmdc->fd = -1;
203			mmdc->mm = NIL(Mmvm_t*);
204			return NIL(Void_t*);
205		}
206	}
207
208	mmdc->mm->busy = nsize+MM_START;
209	return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START);
210}
211
212
213#if __STD_C
214static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
215#else
216static int mmvmexcept(vm, type, data, disc)
217Vmalloc_t*	vm;
218int		type;
219Void_t*		data;
220Vmdisc_t*	disc;
221#endif
222{
223	Mmvmdisc_t	*mmdc = (Mmvmdisc_t*)disc;
224	Vmuchar_t	*base;
225
226	if(type == VM_OPEN)
227	{	if(mmdc->mm->busy > MM_START)
228		{	base = ((Vmuchar_t*)mmdc->mm->base) + MM_START;
229			*((Void_t**)data) = (Void_t*)base;
230			return 1;
231		}
232		else	return 0;
233	}
234	else if(type == VM_CLOSE)
235	{	(void)munmap(mmdc->mm->base, mmdc->mm->size);
236		(void)close(mmdc->fd);
237		vmfree(Vmheap, mmdc);
238		return 1; /* freeing of mapped data is already done */
239	}
240	else	return 0;
241}
242
243
244#if __STD_C
245Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round)
246#else
247Vmalloc_t* vmmopen(file, base, round)
248char*		file;	/* file mapping data from	*/
249Void_t* 	base;	/* desired starting address	*/
250size_t		round;	/* amount to round requests	*/
251#endif
252{
253	Vmalloc_t	*vm;
254	Mmvmdisc_t	*mmdc;
255	Mmvm_t		mm;
256	int		fd;
257
258	if(!file)
259		return NIL(Vmalloc_t*);
260
261	/* set the amount to round up to on each memory request */
262	GETPAGESIZE(_Vmpagesize);
263	if(round < MM_ROUND)
264		round = MM_ROUND;
265	round = ROUND(round, _Vmpagesize);
266
267	if((fd = mmvminit(file, base, round, &mm)) < 0)
268		return NIL(Vmalloc_t*);
269
270	if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) )
271	{	close(fd);
272		return NIL(Vmalloc_t*);
273	}
274
275	mmdc->disc.memoryf = mmvmmemory;
276	mmdc->disc.exceptf = mmvmexcept;
277	mmdc->disc.round   = mm.round;
278	mmdc->fd = fd;
279	mmdc->mm = (Mmvm_t*)mm.base;
280
281	if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) )
282	{	mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc);
283		return NIL(Vmalloc_t*);
284	}
285
286	return vm;
287}
288
289
290#if __STD_C
291Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set)
292#else
293Void_t* vmmset(vm, data, key, set)
294Vmalloc_t*	vm;	/* a region based on vmmmopen	*/
295int		key;	/* key of data to be set	*/
296Void_t*		data;	/* data to be set		*/
297int		set;	/* 1 for setting, 0 for getting	*/
298#endif
299{
300	User_t	*u;
301	Mmvm_t	*mmvm = ((Mmvmdisc_t*)vm->disc)->mm;
302
303	for(u = mmvm->user; u; u = u->next)
304		if(u->key == key)
305			break;
306	if(!set)
307		return u ? u->data : NIL(Void_t*);
308	else if(u)
309	{	Void_t* old = u->data;
310		u->data = data;
311		return old;
312	}
313	else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) )
314		return NIL(Void_t*);
315	else
316	{	u->data = data;
317		u->key  = key;
318		u->next = mmvm->user;
319		mmvm->user = u;
320		return data;
321	}
322}
323
324#endif
325