diff options
Diffstat (limited to 'src/w_mmap.c')
-rw-r--r-- | src/w_mmap.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/src/w_mmap.c b/src/w_mmap.c new file mode 100644 index 0000000..51094b4 --- /dev/null +++ b/src/w_mmap.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
5 | * PrBoom: a Doom port merged with LxDoom and LSDLDoom | ||
6 | * based on BOOM, a modified and improved DOOM engine | ||
7 | * Copyright (C) 2001 by | ||
8 | * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze | ||
9 | * Copyright 2005, 2006 by | ||
10 | * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
25 | * 02111-1307, USA. | ||
26 | * | ||
27 | * DESCRIPTION: | ||
28 | * Transparent access to data in WADs using mmap | ||
29 | * | ||
30 | *----------------------------------------------------------------------------- | ||
31 | */ | ||
32 | |||
33 | #ifdef HAVE_CONFIG_H | ||
34 | #include "config.h" | ||
35 | #endif | ||
36 | |||
37 | #ifdef HAVE_UNISTD_H | ||
38 | #include <unistd.h> | ||
39 | #endif | ||
40 | #ifdef _WIN32 | ||
41 | #define WIN32_LEAN_AND_MEAN | ||
42 | #include <windows.h> | ||
43 | #else | ||
44 | #include <sys/mman.h> | ||
45 | #endif | ||
46 | |||
47 | #include "doomstat.h" | ||
48 | #include "doomtype.h" | ||
49 | |||
50 | #ifdef __GNUG__ | ||
51 | #pragma implementation "w_wad.h" | ||
52 | #endif | ||
53 | #include "w_wad.h" | ||
54 | #include "z_zone.h" | ||
55 | #include "lprintf.h" | ||
56 | #include "i_system.h" | ||
57 | |||
58 | static struct { | ||
59 | void *cache; | ||
60 | #ifdef TIMEDIAG | ||
61 | int locktic; | ||
62 | #endif | ||
63 | int locks; | ||
64 | } *cachelump; | ||
65 | |||
66 | #ifdef HEAPDUMP | ||
67 | void W_PrintLump(FILE* fp, void* p) { | ||
68 | int i; | ||
69 | for (i=0; i<numlumps; i++) | ||
70 | if (cachelump[i].cache == p) { | ||
71 | fprintf(fp, " %8.8s %6u %2d %6d", lumpinfo[i].name, | ||
72 | W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic); | ||
73 | return; | ||
74 | } | ||
75 | fprintf(fp, " not found"); | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | #ifdef TIMEDIAG | ||
80 | static void W_ReportLocks(void) | ||
81 | { | ||
82 | int i; | ||
83 | lprintf(LO_DEBUG, "W_ReportLocks:\nLump Size Locks Tics\n"); | ||
84 | for (i=0; i<numlumps; i++) { | ||
85 | if (cachelump[i].locks > 0) | ||
86 | lprintf(LO_DEBUG, "%8.8s %6u %2d %6d\n", lumpinfo[i].name, | ||
87 | W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic); | ||
88 | } | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | #ifdef _WIN32 | ||
93 | typedef struct { | ||
94 | HANDLE hnd; | ||
95 | OFSTRUCT fileinfo; | ||
96 | HANDLE hnd_map; | ||
97 | void *data; | ||
98 | } mmap_info_t; | ||
99 | |||
100 | mmap_info_t *mapped_wad; | ||
101 | |||
102 | void W_DoneCache(void) | ||
103 | { | ||
104 | size_t i; | ||
105 | |||
106 | if (cachelump) { | ||
107 | free(cachelump); | ||
108 | cachelump = NULL; | ||
109 | } | ||
110 | |||
111 | if (!mapped_wad) | ||
112 | return; | ||
113 | for (i=0; i<numwadfiles; i++) | ||
114 | { | ||
115 | if (mapped_wad[i].data) | ||
116 | { | ||
117 | UnmapViewOfFile(mapped_wad[i].data); | ||
118 | mapped_wad[i].data=NULL; | ||
119 | } | ||
120 | if (mapped_wad[i].hnd_map) | ||
121 | { | ||
122 | CloseHandle(mapped_wad[i].hnd_map); | ||
123 | mapped_wad[i].hnd_map=NULL; | ||
124 | } | ||
125 | if (mapped_wad[i].hnd) | ||
126 | { | ||
127 | CloseHandle(mapped_wad[i].hnd); | ||
128 | mapped_wad[i].hnd=NULL; | ||
129 | } | ||
130 | } | ||
131 | free(mapped_wad); | ||
132 | } | ||
133 | |||
134 | void W_InitCache(void) | ||
135 | { | ||
136 | // set up caching | ||
137 | cachelump = calloc(numlumps, sizeof *cachelump); | ||
138 | if (!cachelump) | ||
139 | I_Error ("W_Init: Couldn't allocate lumpcache"); | ||
140 | |||
141 | #ifdef TIMEDIAG | ||
142 | atexit(W_ReportLocks); | ||
143 | #endif | ||
144 | |||
145 | mapped_wad = calloc(numwadfiles,sizeof(mmap_info_t)); | ||
146 | memset(mapped_wad,0,sizeof(mmap_info_t)*numwadfiles); | ||
147 | { | ||
148 | int i; | ||
149 | for (i=0; i<numlumps; i++) | ||
150 | { | ||
151 | int wad_index = (int)(lumpinfo[i].wadfile-wadfiles); | ||
152 | |||
153 | cachelump[i].locks = -1; | ||
154 | |||
155 | if (!lumpinfo[i].wadfile) | ||
156 | continue; | ||
157 | #ifdef RANGECHECK | ||
158 | if ((wad_index<0)||((size_t)wad_index>=numwadfiles)) | ||
159 | I_Error("W_InitCache: wad_index out of range"); | ||
160 | #endif | ||
161 | if (!mapped_wad[wad_index].data) | ||
162 | { | ||
163 | mapped_wad[wad_index].hnd = | ||
164 | (HANDLE)OpenFile( | ||
165 | wadfiles[wad_index].name, | ||
166 | &mapped_wad[wad_index].fileinfo, | ||
167 | OF_READ | ||
168 | ); | ||
169 | if (mapped_wad[wad_index].hnd==(HANDLE)HFILE_ERROR) | ||
170 | I_Error("W_InitCache: OpenFile for memory mapping failed (LastError %i)",GetLastError()); | ||
171 | mapped_wad[wad_index].hnd_map = | ||
172 | CreateFileMapping( | ||
173 | mapped_wad[wad_index].hnd, | ||
174 | NULL, | ||
175 | PAGE_READONLY, | ||
176 | 0, | ||
177 | 0, | ||
178 | NULL | ||
179 | ); | ||
180 | if (mapped_wad[wad_index].hnd_map==NULL) | ||
181 | I_Error("W_InitCache: CreateFileMapping for memory mapping failed (LastError %i)",GetLastError()); | ||
182 | mapped_wad[wad_index].data = | ||
183 | MapViewOfFile( | ||
184 | mapped_wad[wad_index].hnd_map, | ||
185 | FILE_MAP_READ, | ||
186 | 0, | ||
187 | 0, | ||
188 | 0 | ||
189 | ); | ||
190 | if (mapped_wad[wad_index].hnd_map==NULL) | ||
191 | I_Error("W_InitCache: MapViewOfFile for memory mapping failed (LastError %i)",GetLastError()); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | const void* W_CacheLumpNum(int lump) | ||
198 | { | ||
199 | int wad_index = (int)(lumpinfo[lump].wadfile-wadfiles); | ||
200 | #ifdef RANGECHECK | ||
201 | if ((wad_index<0)||((size_t)wad_index>=numwadfiles)) | ||
202 | I_Error("W_CacheLumpNum: wad_index out of range"); | ||
203 | if ((unsigned)lump >= (unsigned)numlumps) | ||
204 | I_Error ("W_CacheLumpNum: %i >= numlumps",lump); | ||
205 | #endif | ||
206 | if (!lumpinfo[lump].wadfile) | ||
207 | return NULL; | ||
208 | return (void*)((unsigned char *)mapped_wad[wad_index].data+lumpinfo[lump].position); | ||
209 | } | ||
210 | |||
211 | #else | ||
212 | |||
213 | void ** mapped_wad; | ||
214 | |||
215 | void W_InitCache(void) | ||
216 | { | ||
217 | int maxfd = 0; | ||
218 | // set up caching | ||
219 | cachelump = calloc(numlumps, sizeof *cachelump); | ||
220 | if (!cachelump) | ||
221 | I_Error ("W_Init: Couldn't allocate lumpcache"); | ||
222 | |||
223 | #ifdef TIMEDIAG | ||
224 | atexit(W_ReportLocks); | ||
225 | #endif | ||
226 | |||
227 | { | ||
228 | int i; | ||
229 | for (i=0; i<numlumps; i++) | ||
230 | if (lumpinfo[i].wadfile) | ||
231 | if (lumpinfo[i].wadfile->handle > maxfd) maxfd = lumpinfo[i].wadfile->handle; | ||
232 | } | ||
233 | mapped_wad = calloc(maxfd+1,sizeof *mapped_wad); | ||
234 | { | ||
235 | int i; | ||
236 | for (i=0; i<numlumps; i++) { | ||
237 | cachelump[i].locks = -1; | ||
238 | if (lumpinfo[i].wadfile) { | ||
239 | int fd = lumpinfo[i].wadfile->handle; | ||
240 | if (!mapped_wad[fd]) | ||
241 | if ((mapped_wad[fd] = mmap(NULL,I_Filelength(fd),PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED) | ||
242 | I_Error("W_InitCache: failed to mmap"); | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | void W_DoneCache(void) | ||
249 | { | ||
250 | { | ||
251 | int i; | ||
252 | for (i=0; i<numlumps; i++) | ||
253 | if (lumpinfo[i].wadfile) { | ||
254 | int fd = lumpinfo[i].wadfile->handle; | ||
255 | if (mapped_wad[fd]) { | ||
256 | if (munmap(mapped_wad[fd],I_Filelength(fd))) | ||
257 | I_Error("W_DoneCache: failed to munmap"); | ||
258 | mapped_wad[fd] = NULL; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | free(mapped_wad); | ||
263 | } | ||
264 | |||
265 | const void* W_CacheLumpNum(int lump) | ||
266 | { | ||
267 | #ifdef RANGECHECK | ||
268 | if ((unsigned)lump >= (unsigned)numlumps) | ||
269 | I_Error ("W_CacheLumpNum: %i >= numlumps",lump); | ||
270 | #endif | ||
271 | if (!lumpinfo[lump].wadfile) | ||
272 | return NULL; | ||
273 | return (mapped_wad[lumpinfo[lump].wadfile->handle]+lumpinfo[lump].position); | ||
274 | } | ||
275 | #endif | ||
276 | |||
277 | /* | ||
278 | * W_LockLumpNum | ||
279 | * | ||
280 | * This copies the lump into a malloced memory region and returns its address | ||
281 | * instead of returning a pointer into the memory mapped area | ||
282 | * | ||
283 | */ | ||
284 | const void* W_LockLumpNum(int lump) | ||
285 | { | ||
286 | size_t len = W_LumpLength(lump); | ||
287 | const void *data = W_CacheLumpNum(lump); | ||
288 | |||
289 | if (!cachelump[lump].cache) { | ||
290 | // read the lump in | ||
291 | Z_Malloc(len, PU_CACHE, &cachelump[lump].cache); | ||
292 | memcpy(cachelump[lump].cache, data, len); | ||
293 | } | ||
294 | |||
295 | /* cph - if wasn't locked but now is, tell z_zone to hold it */ | ||
296 | if (cachelump[lump].locks <= 0) { | ||
297 | Z_ChangeTag(cachelump[lump].cache,PU_STATIC); | ||
298 | #ifdef TIMEDIAG | ||
299 | cachelump[lump].locktic = gametic; | ||
300 | #endif | ||
301 | // reset lock counter | ||
302 | cachelump[lump].locks = 1; | ||
303 | } else { | ||
304 | // increment lock counter | ||
305 | cachelump[lump].locks += 1; | ||
306 | } | ||
307 | |||
308 | #ifdef SIMPLECHECKS | ||
309 | if (!((cachelump[lump].locks+1) & 0xf)) | ||
310 | lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n", | ||
311 | lumpinfo[lump].name, cachelump[lump].locks); | ||
312 | #endif | ||
313 | |||
314 | return cachelump[lump].cache; | ||
315 | } | ||
316 | |||
317 | void W_UnlockLumpNum(int lump) { | ||
318 | if (cachelump[lump].locks == -1) | ||
319 | return; // this lump is memory mapped | ||
320 | |||
321 | #ifdef SIMPLECHECKS | ||
322 | if (cachelump[lump].locks == 0) | ||
323 | lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s\n", | ||
324 | lumpinfo[lump].name); | ||
325 | #endif | ||
326 | cachelump[lump].locks -= 1; | ||
327 | /* cph - Note: must only tell z_zone to make purgeable if currently locked, | ||
328 | * else it might already have been purged | ||
329 | */ | ||
330 | if (cachelump[lump].locks == 0) | ||
331 | Z_ChangeTag(cachelump[lump].cache, PU_CACHE); | ||
332 | } | ||
333 | |||