w_mmap.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. #ifdef HAVE_CONFIG_H
  33. #include "config.h"
  34. #endif
  35. #ifdef HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38. #ifdef _WIN32
  39. #define WIN32_LEAN_AND_MEAN
  40. #include <windows.h>
  41. #else
  42. #include <sys/mman.h>
  43. #endif
  44. #include "doomstat.h"
  45. #include "doomtype.h"
  46. #ifdef __GNUG__
  47. #pragma implementation "w_wad.h"
  48. #endif
  49. #include "w_wad.h"
  50. #include "z_zone.h"
  51. #include "lprintf.h"
  52. #include "i_system.h"
  53. static struct {
  54. void *cache;
  55. #ifdef TIMEDIAG
  56. int locktic;
  57. #endif
  58. int locks;
  59. } *cachelump;
  60. #ifdef HEAPDUMP
  61. void W_PrintLump(FILE* fp, void* p) {
  62. int i;
  63. for (i=0; i<numlumps; i++)
  64. if (cachelump[i].cache == p) {
  65. fprintf(fp, " %8.8s %6u %2d %6d", lumpinfo[i].name,
  66. W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic);
  67. return;
  68. }
  69. fprintf(fp, " not found");
  70. }
  71. #endif
  72. #ifdef TIMEDIAG
  73. static void W_ReportLocks(void)
  74. {
  75. int i;
  76. lprintf(LO_DEBUG, "W_ReportLocks:\nLump Size Locks Tics\n");
  77. for (i=0; i<numlumps; i++) {
  78. if (cachelump[i].locks > 0)
  79. lprintf(LO_DEBUG, "%8.8s %6u %2d %6d\n", lumpinfo[i].name,
  80. W_LumpLength(i), cachelump[i].locks, gametic - cachelump[i].locktic);
  81. }
  82. }
  83. #endif
  84. #ifdef _WIN32
  85. typedef struct {
  86. HANDLE hnd;
  87. OFSTRUCT fileinfo;
  88. HANDLE hnd_map;
  89. void *data;
  90. } mmap_info_t;
  91. mmap_info_t *mapped_wad;
  92. void W_DoneCache(void)
  93. {
  94. size_t i;
  95. if (cachelump) {
  96. free(cachelump);
  97. cachelump = NULL;
  98. }
  99. if (!mapped_wad)
  100. return;
  101. for (i=0; i<numwadfiles; i++)
  102. {
  103. if (mapped_wad[i].data)
  104. {
  105. UnmapViewOfFile(mapped_wad[i].data);
  106. mapped_wad[i].data=NULL;
  107. }
  108. if (mapped_wad[i].hnd_map)
  109. {
  110. CloseHandle(mapped_wad[i].hnd_map);
  111. mapped_wad[i].hnd_map=NULL;
  112. }
  113. if (mapped_wad[i].hnd)
  114. {
  115. CloseHandle(mapped_wad[i].hnd);
  116. mapped_wad[i].hnd=NULL;
  117. }
  118. }
  119. free(mapped_wad);
  120. }
  121. void W_InitCache(void)
  122. {
  123. // set up caching
  124. cachelump = calloc(numlumps, sizeof *cachelump);
  125. if (!cachelump)
  126. I_Error ("W_Init: Couldn't allocate lumpcache");
  127. #ifdef TIMEDIAG
  128. atexit(W_ReportLocks);
  129. #endif
  130. mapped_wad = calloc(numwadfiles,sizeof(mmap_info_t));
  131. memset(mapped_wad,0,sizeof(mmap_info_t)*numwadfiles);
  132. {
  133. int i;
  134. for (i=0; i<numlumps; i++)
  135. {
  136. int wad_index = (int)(lumpinfo[i].wadfile-wadfiles);
  137. cachelump[i].locks = -1;
  138. if (!lumpinfo[i].wadfile)
  139. continue;
  140. #ifdef RANGECHECK
  141. if ((wad_index<0)||((size_t)wad_index>=numwadfiles))
  142. I_Error("W_InitCache: wad_index out of range");
  143. #endif
  144. if (!mapped_wad[wad_index].data)
  145. {
  146. mapped_wad[wad_index].hnd =
  147. (HANDLE)OpenFile(
  148. wadfiles[wad_index].name,
  149. &mapped_wad[wad_index].fileinfo,
  150. OF_READ
  151. );
  152. if (mapped_wad[wad_index].hnd==(HANDLE)HFILE_ERROR)
  153. I_Error("W_InitCache: OpenFile for memory mapping failed (LastError %i)",GetLastError());
  154. mapped_wad[wad_index].hnd_map =
  155. CreateFileMapping(
  156. mapped_wad[wad_index].hnd,
  157. NULL,
  158. PAGE_READONLY,
  159. 0,
  160. 0,
  161. NULL
  162. );
  163. if (mapped_wad[wad_index].hnd_map==NULL)
  164. I_Error("W_InitCache: CreateFileMapping for memory mapping failed (LastError %i)",GetLastError());
  165. mapped_wad[wad_index].data =
  166. MapViewOfFile(
  167. mapped_wad[wad_index].hnd_map,
  168. FILE_MAP_READ,
  169. 0,
  170. 0,
  171. 0
  172. );
  173. if (mapped_wad[wad_index].hnd_map==NULL)
  174. I_Error("W_InitCache: MapViewOfFile for memory mapping failed (LastError %i)",GetLastError());
  175. }
  176. }
  177. }
  178. }
  179. const void* W_CacheLumpNum(int lump)
  180. {
  181. int wad_index = (int)(lumpinfo[lump].wadfile-wadfiles);
  182. #ifdef RANGECHECK
  183. if ((wad_index<0)||((size_t)wad_index>=numwadfiles))
  184. I_Error("W_CacheLumpNum: wad_index out of range");
  185. if ((unsigned)lump >= (unsigned)numlumps)
  186. I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
  187. #endif
  188. if (!lumpinfo[lump].wadfile)
  189. return NULL;
  190. return (void*)((unsigned char *)mapped_wad[wad_index].data+lumpinfo[lump].position);
  191. }
  192. #else
  193. void ** mapped_wad;
  194. void W_InitCache(void)
  195. {
  196. int maxfd = 0;
  197. // set up caching
  198. cachelump = calloc(numlumps, sizeof *cachelump);
  199. if (!cachelump)
  200. I_Error ("W_Init: Couldn't allocate lumpcache");
  201. #ifdef TIMEDIAG
  202. atexit(W_ReportLocks);
  203. #endif
  204. {
  205. int i;
  206. for (i=0; i<numlumps; i++)
  207. if (lumpinfo[i].wadfile)
  208. if (lumpinfo[i].wadfile->handle > maxfd) maxfd = lumpinfo[i].wadfile->handle;
  209. }
  210. mapped_wad = calloc(maxfd+1,sizeof *mapped_wad);
  211. {
  212. int i;
  213. for (i=0; i<numlumps; i++) {
  214. cachelump[i].locks = -1;
  215. if (lumpinfo[i].wadfile) {
  216. int fd = lumpinfo[i].wadfile->handle;
  217. if (!mapped_wad[fd])
  218. if ((mapped_wad[fd] = mmap(NULL,I_Filelength(fd),PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED)
  219. I_Error("W_InitCache: failed to mmap");
  220. }
  221. }
  222. }
  223. }
  224. void W_DoneCache(void)
  225. {
  226. {
  227. int i;
  228. for (i=0; i<numlumps; i++)
  229. if (lumpinfo[i].wadfile) {
  230. int fd = lumpinfo[i].wadfile->handle;
  231. if (mapped_wad[fd]) {
  232. if (munmap(mapped_wad[fd],I_Filelength(fd)))
  233. I_Error("W_DoneCache: failed to munmap");
  234. mapped_wad[fd] = NULL;
  235. }
  236. }
  237. }
  238. free(mapped_wad);
  239. }
  240. const void* W_CacheLumpNum(int lump)
  241. {
  242. #ifdef RANGECHECK
  243. if ((unsigned)lump >= (unsigned)numlumps)
  244. I_Error ("W_CacheLumpNum: %i >= numlumps",lump);
  245. #endif
  246. // printf( "W_CacheLumpNum( %i ) = %s\n", lump, lumpinfo[lump].name ); // JDC tracking hitches
  247. if (!lumpinfo[lump].wadfile)
  248. return NULL;
  249. return ((unsigned char*)mapped_wad[lumpinfo[lump].wadfile->handle]+lumpinfo[lump].position);
  250. }
  251. #endif
  252. /*
  253. * W_LockLumpNum
  254. *
  255. * This copies the lump into a malloced memory region and returns its address
  256. * instead of returning a pointer into the memory mapped area
  257. *
  258. */
  259. const void* W_LockLumpNum(int lump)
  260. {
  261. size_t len = W_LumpLength(lump);
  262. const void *data = W_CacheLumpNum(lump);
  263. if (!cachelump[lump].cache) {
  264. // read the lump in
  265. Z_Malloc(len, PU_CACHE, &cachelump[lump].cache);
  266. memcpy(cachelump[lump].cache, data, len);
  267. }
  268. /* cph - if wasn't locked but now is, tell z_zone to hold it */
  269. if (cachelump[lump].locks <= 0) {
  270. Z_ChangeTag(cachelump[lump].cache,PU_STATIC);
  271. #ifdef TIMEDIAG
  272. cachelump[lump].locktic = gametic;
  273. #endif
  274. // reset lock counter
  275. cachelump[lump].locks = 1;
  276. } else {
  277. // increment lock counter
  278. cachelump[lump].locks += 1;
  279. }
  280. #ifdef SIMPLECHECKS
  281. if (!((cachelump[lump].locks+1) & 0xf))
  282. lprintf(LO_DEBUG, "W_CacheLumpNum: High lock on %8s (%d)\n",
  283. lumpinfo[lump].name, cachelump[lump].locks);
  284. #endif
  285. return cachelump[lump].cache;
  286. }
  287. void W_UnlockLumpNum(int lump) {
  288. if (cachelump[lump].locks == -1)
  289. return; // this lump is memory mapped
  290. #ifdef SIMPLECHECKS
  291. if (cachelump[lump].locks == 0)
  292. lprintf(LO_DEBUG, "W_UnlockLumpNum: Excess unlocks on %8s\n",
  293. lumpinfo[lump].name);
  294. #endif
  295. cachelump[lump].locks -= 1;
  296. /* cph - Note: must only tell z_zone to make purgeable if currently locked,
  297. * else it might already have been purged
  298. */
  299. if (cachelump[lump].locks == 0)
  300. Z_ChangeTag(cachelump[lump].cache, PU_CACHE);
  301. }