1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1991-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * zmalloc	- use mmap(2) to allocate memory from /dev/zero.
31  * zfree	- use munmap(2) to unmap (free) memory.
32  *
33  * These functions should be better than malloc(3) for large memory allocation.
34  */
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 
44 #include <zmalloc.h>
45 
46 /*
47  * a utility structure to keep track of the (possibly) multiple mmaps
48  * that we have done...
49  */
50 struct buffer_map {
51 	struct buffer_map *bm_next;
52 	char *bm_buffer;
53 	int bm_size;
54 };
55 
56 static  void *bm_empty = (void *) "";		/* special buffer */
57 static	struct buffer_map *bm_list;		/* NULL by default */
58 
59 static struct buffer_map *
60 insert_bm(char *buf, size_t size)
61 {
62 	struct buffer_map *bm;
63 
64 	bm = (struct buffer_map *)malloc(sizeof (struct buffer_map));
65 	bm->bm_buffer = buf;
66 	bm->bm_size = size;
67 	bm->bm_next = bm_list;
68 
69 	bm_list = bm;
70 
71 	return (bm_list);
72 }
73 
74 static size_t
75 delete_bm(char *buf)
76 {
77 	size_t size;
78 	register struct buffer_map *p_curr;
79 	register struct buffer_map *p_prev;
80 
81 	p_prev = NULL;
82 	p_curr = bm_list;
83 	while (p_curr != NULL) {
84 		if (p_curr->bm_buffer == buf) {
85 			if (p_prev == NULL)
86 				bm_list = p_curr->bm_next;
87 			else
88 				p_prev->bm_next = p_curr->bm_next;
89 			size = p_curr->bm_size;
90 			free(p_curr);
91 			return (size);
92 		}
93 
94 		p_prev = p_curr;
95 		p_curr = p_curr->bm_next;
96 	}
97 	return (0);
98 }
99 
100 void *
101 zmalloc(size_t size)
102 {
103 	int	fd;
104 	caddr_t	mbuf;
105 
106 	/* XXX - Special case: never allocate 0 bytes, use a special buffer */
107 	if (size == 0)
108 	    return ((void *)NULL); /* return (bm_empty); */
109 
110 	if ((fd = open("/dev/zero", O_RDWR)) < 0) {
111 		perror("/dev/zero");
112 		return ((void *) NULL);
113 	}
114 
115 	mbuf = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
116 	(void) close(fd);
117 
118 	if (mbuf == (caddr_t)-1) {
119 		perror("zmalloc: mmap");
120 		return ((void *) NULL);
121 	}
122 
123 	(void) insert_bm(mbuf, size);
124 
125 	return ((void *) mbuf);
126 }
127 
128 void
129 zfree(void* mbuf)
130 {
131 	size_t size;
132 
133 	if (mbuf == bm_empty)
134 	    return;
135 
136 	if (mbuf != NULL) {
137 		if (size = delete_bm((caddr_t)mbuf)) {
138 			if (munmap((char *)mbuf, size) < 0)
139 			    perror("zfree: munmap");
140 		}
141 	}
142 }
143