source: trunk/src/kernel32/mmap.cpp@ 678

Last change on this file since 678 was 678, checked in by sandervl, 26 years ago

Put back handlemanager changes + memory mapped file changes

File size: 10.7 KB
Line 
1/* $Id: mmap.cpp,v 1.9 1999-08-25 10:28:40 sandervl Exp $ */
2
3/*
4 * Win32 Memory mapped file class
5 *
6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * NOTE: Memory mapping DOES NOT work when kernel-mode code causes
9 * a pagefault in the memory mapped object. (exceptions aren't
10 * dispatched to our exception handler until after the kernel mode
11 * call returns (too late))
12 *
13 * NOTE: There's no easy way to determine which pages were modified. Temporary
14 * solution is to write all paged-in memory to disk.
15 *
16 * NOTE: Are apps allowed to change the protection flags of memory mapped pages?
17 * I'm assuming they aren't for now.
18 *
19 * TODO: Handles returned should be usable by all apis that accept file handles
20 * TODO: Sharing memory mapped files between multiple processes
21 *
22 * Project Odin Software License can be found in LICENSE.TXT
23 *
24 */
25#include <os2win.h>
26#include <stdlib.h>
27#include <string.h>
28#include <win\virtual.h>
29#include <vmutex.h>
30#include <handlemanager.h>
31#include "mmap.h"
32
33VMutex globalmapMutex;
34
35//******************************************************************************
36//TODO: sharing between processes
37//******************************************************************************
38Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
39 : fMapped(FALSE), pMapping(NULL), mMapAccess(0), referenced(0)
40{
41 globalmapMutex.enter();
42 memmaps = this;
43 next = memmaps;
44 globalmapMutex.leave();
45
46 hMemFile = hfile;
47
48 mSize = size;
49 mProtFlags = fdwProtect;
50
51 if(lpszName) {
52 lpszMapName = (char *)malloc(strlen(lpszName)+1);
53 strcpy(lpszMapName, lpszName);
54 }
55 else lpszMapName = NULL;
56}
57//******************************************************************************
58//******************************************************************************
59BOOL Win32MemMap::Init(HANDLE hMemMap)
60{
61 mapMutex.enter();
62 if(hMemFile != -1)
63 {
64 if(DuplicateHandle(GetCurrentProcess(), hMemFile, GetCurrentProcess(),
65 &hMemFile, 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE)
66 {
67 dprintf(("Win32MemMap::Init: DuplicateHandle failed!"));
68 goto fail;
69 }
70 }
71 this->hMemMap = hMemMap;
72 mapMutex.leave();
73 return TRUE;
74fail:
75 mapMutex.leave();
76 return FALSE;
77}
78//******************************************************************************
79//******************************************************************************
80Win32MemMap::~Win32MemMap()
81{
82 unmapViewOfFile();
83 if(lpszMapName) {
84 free(lpszMapName);
85 }
86 mapMutex.enter();
87 if(pMapping) {
88 VirtualFree(pMapping, mSize, MEM_RELEASE);
89 pMapping = NULL;
90 }
91 if(hMemFile != -1) {
92 CloseHandle(hMemFile);
93 hMemFile = -1;
94 }
95 mapMutex.leave();
96
97 globalmapMutex.enter();
98 Win32MemMap *map = memmaps;
99
100 if(map == this) {
101 memmaps = next;
102 }
103 else {
104 while(map->next) {
105 if(map->next == this)
106 break;
107 map = map->next;
108 }
109 if(map->next) {
110 map->next = next;
111 }
112 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
113 }
114 globalmapMutex.leave();
115}
116//******************************************************************************
117//******************************************************************************
118BOOL Win32MemMap::hasReadAccess()
119{
120 return TRUE; //should have at least this
121}
122//******************************************************************************
123//******************************************************************************
124BOOL Win32MemMap::hasWriteAccess()
125{
126 return !(mProtFlags & PAGE_READONLY);
127}
128//******************************************************************************
129//Might want to add this feature for memory mapping executable & dll files in
130//the loader (done in Win32 with the SEC_IMAGE flag?)
131//******************************************************************************
132BOOL Win32MemMap::hasExecuteAccess()
133{
134 return FALSE;
135}
136//******************************************************************************
137//******************************************************************************
138BOOL Win32MemMap::commitPage(LPVOID lpPageFaultAddr, ULONG nrpages)
139{
140 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
141 DWORD oldProt, newProt, nrBytesRead, offset, size;
142
143// mapMutex.enter();
144 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
145 newProt |= MEM_COMMIT;
146
147 dprintf(("Win32MemMap::commitPage %x (faultaddr %x), nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));
148 if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
149 goto fail;
150 }
151 if(hMemFile != -1) {
152 offset = pageAddr - (ULONG)pMapping;
153 size = nrpages*PAGE_SIZE;
154 if(offset + size > mSize) {
155 size = mSize - offset;
156 }
157 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
158 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset));
159 goto fail;
160 }
161 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) {
162 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr));
163 goto fail;
164 }
165 if(nrBytesRead != size) {
166 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr));
167 goto fail;
168 }
169 }
170
171// mapMutex.leave();
172 return TRUE;
173fail:
174// mapMutex.leave();
175 return FALSE;
176}
177//******************************************************************************
178//******************************************************************************
179BOOL Win32MemMap::unmapViewOfFile()
180{
181 if(fMapped == FALSE)
182 return FALSE;
183
184 flushView(pMapping, mSize);
185 mapMutex.enter();
186 if(pMapping) {
187 VirtualFree(pMapping, mSize, MEM_RELEASE);
188 }
189 pMapping = NULL;
190 fMapped = FALSE;
191 mapMutex.leave();
192 return TRUE;
193}
194//******************************************************************************
195//******************************************************************************
196LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess)
197{
198 mapMutex.enter();
199 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
200 ULONG fAlloc = 0;
201 LPVOID mapview;
202
203 if(fdwAccess & (FILE_MAP_WRITE|FILE_MAP_ALL_ACCESS) && !(mProtFlags & PAGE_READWRITE))
204 goto parmfail;
205 if(fdwAccess & FILE_MAP_READ && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY)))
206 goto parmfail;
207 if(fdwAccess & FILE_MAP_COPY && !(mProtFlags & PAGE_WRITECOPY))
208 goto parmfail;
209
210//TODO: If committed, read file into memory
211#if 0
212 if(mProtFlags & SEC_COMMIT)
213 fAlloc |= MEM_COMMIT;
214 else
215 if(mProtFlags & SEC_RESERVE)
216 fAlloc |= MEM_RESERVE;
217#else
218 fAlloc = MEM_RESERVE;
219#endif
220
221 if(fMapped == FALSE) {//if not mapped, reserve/commit entire view
222 pMapping = VirtualAlloc(0, mSize, fAlloc, mProtFlags);
223 if(pMapping == NULL) {
224 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
225 goto fail;
226 }
227 fMapped = TRUE;
228 }
229 mapview = (LPVOID)((ULONG)pMapping + offset);
230 mapMutex.leave();
231 return mapview;
232
233parmfail:
234 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
235 SetLastError(ERROR_INVALID_PARAMETER);
236fail:
237 mapMutex.leave();
238 return 0;
239}
240//******************************************************************************
241// NOTE: There's no easy way to determine which pages were modified. Temporary
242// solution is to write all paged-in memory to disk.
243//TODO: Are apps allowed to change the protection flags of memory mapped pages?
244// I'm assuming they aren't for now.
245//******************************************************************************
246BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
247{
248 MEMORY_BASIC_INFORMATION memInfo;
249 ULONG nrpages, nrBytesWritten, offset, size;
250 int i;
251
252// mapMutex.enter();
253 if(fMapped == FALSE)
254 goto parmfail;
255
256 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
257 goto parmfail;
258
259 if(mProtFlags & PAGE_READONLY)
260 goto parmfail;
261
262 nrpages = cbFlush/PAGE_SIZE;
263 if(cbFlush & 0xFFF) nrpages++;
264
265 for(i=0;i<nrpages;i++) {
266 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
267 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
268 goto fail;
269 }
270 //If a page is reserved or write protected, we won't bother flushing it to disk
271 if(memInfo.State & MEM_COMMIT &&
272 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
273 {//committed and allowed for writing?
274 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
275 size = PAGE_SIZE;
276 if(offset + size > mSize) {
277 size = mSize - offset;
278 }
279 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
280
281 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
282 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
283 goto fail;
284 }
285 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
286 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
287 goto fail;
288 }
289 if(nrBytesWritten != size) {
290 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
291 goto fail;
292 }
293 }
294 }
295// mapMutex.leave();
296 return TRUE;
297parmfail:
298 SetLastError(ERROR_INVALID_PARAMETER);
299// mapMutex.leave();
300 return FALSE;
301fail:
302// mapMutex.leave();
303 return FALSE;
304}
305//******************************************************************************
306//******************************************************************************
307Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
308{
309 globalmapMutex.enter();
310 Win32MemMap *map = memmaps;
311
312 if(map != NULL) {
313 while(map) {
314 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
315 break;
316 map = map->next;
317 }
318 }
319 globalmapMutex.leave();
320 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
321 return map;
322}
323//******************************************************************************
324//******************************************************************************
325Win32MemMap *Win32MemMap::findMap(ULONG address)
326{
327 globalmapMutex.enter();
328 Win32MemMap *map = memmaps;
329
330 if(map != NULL) {
331 while(map) {
332 if(map->pMapping && (ULONG)map->pMapping <= address &&
333 (ULONG)map->pMapping + map->mSize > address)
334 {
335 break;
336 }
337 map = map->next;
338 }
339 }
340 globalmapMutex.leave();
341 return map;
342}
343//******************************************************************************
344//******************************************************************************
345void Win32MemMap::deleteAll()
346{
347 while(memmaps) {
348 CloseHandle(memmaps->hMemMap);
349 }
350}
351//******************************************************************************
352//******************************************************************************
353Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.