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

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

Cleanup

File size: 12.5 KB
Line 
1/* $Id: mmap.cpp,v 1.14 1999-08-26 12:55:36 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: Are apps allowed to change the protection flags of memory mapped pages?
14 * I'm assuming they aren't for now.
15 *
16 * TODO: Handles returned should be usable by all apis that accept file handles
17 * TODO: Sharing memory mapped files between multiple processes
18 *
19 * Project Odin Software License can be found in LICENSE.TXT
20 *
21 */
22#include <os2win.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <win\virtual.h>
27#include <vmutex.h>
28#include <handlemanager.h>
29#include "mmap.h"
30
31VMutex globalmapMutex;
32
33
34//******************************************************************************
35//TODO: sharing between processes
36//******************************************************************************
37Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
38 : fMapped(FALSE), pMapping(NULL), mMapAccess(0), referenced(0)
39{
40 globalmapMutex.enter();
41 next = memmaps;
42 memmaps = this;
43 globalmapMutex.leave();
44
45 hMemFile = hfile;
46
47 mSize = size;
48 mProtFlags = fdwProtect;
49
50 if(lpszName) {
51 lpszMapName = (char *)malloc(strlen(lpszName)+1);
52 strcpy(lpszMapName, lpszName);
53 }
54 else lpszMapName = NULL;
55}
56//******************************************************************************
57//******************************************************************************
58BOOL Win32MemMap::Init(HANDLE hMemMap)
59{
60 mapMutex.enter();
61 if(hMemFile != -1)
62 {
63#if 0
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#endif
71 mSize = SetFilePointer(hMemFile, 0, NULL, FILE_END);
72 if(mSize == -1) {
73 dprintf(("Win32MemMap::init: SetFilePointer failed to set pos end"));
74 goto fail;
75 }
76 }
77 this->hMemMap = hMemMap;
78 mapMutex.leave();
79 return TRUE;
80fail:
81 mapMutex.leave();
82 return FALSE;
83}
84//******************************************************************************
85//******************************************************************************
86Win32MemMap::~Win32MemMap()
87{
88 unmapViewOfFile();
89 if(lpszMapName) {
90 free(lpszMapName);
91 }
92 mapMutex.enter();
93 if(pMapping) {
94 VirtualFree(pMapping, mSize, MEM_RELEASE);
95 pMapping = NULL;
96 }
97 if(hMemFile != -1) {
98 CloseHandle(hMemFile);
99 hMemFile = -1;
100 }
101 mapMutex.leave();
102
103 globalmapMutex.enter();
104 Win32MemMap *map = memmaps;
105
106 if(map == this) {
107 memmaps = next;
108 }
109 else {
110 while(map->next) {
111 if(map->next == this)
112 break;
113 map = map->next;
114 }
115 if(map->next) {
116 map->next = next;
117 }
118 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
119 }
120 globalmapMutex.leave();
121}
122//******************************************************************************
123//******************************************************************************
124BOOL Win32MemMap::hasReadAccess()
125{
126 return TRUE; //should have at least this
127}
128//******************************************************************************
129//******************************************************************************
130BOOL Win32MemMap::hasWriteAccess()
131{
132 return !(mProtFlags & PAGE_READONLY);
133}
134//******************************************************************************
135//Might want to add this feature for memory mapping executable & dll files in
136//the loader (done in Win32 with the SEC_IMAGE flag?)
137//******************************************************************************
138BOOL Win32MemMap::hasExecuteAccess()
139{
140 return FALSE;
141}
142//******************************************************************************
143//We determine whether a page has been modified by checking it's protection flags
144//If the write flag is set, this means commitPage had to enable this due to a pagefault
145//(all pages are readonly until the app tries to write to it)
146//******************************************************************************
147BOOL Win32MemMap::commitPage(LPVOID lpPageFaultAddr, ULONG nrpages, BOOL fWriteAccess)
148{
149 MEMORY_BASIC_INFORMATION memInfo;
150 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
151 DWORD oldProt, newProt, nrBytesRead, offset, size;
152
153// mapMutex.enter();
154 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
155
156 dprintf(("Win32MemMap::commitPage %x (faultaddr %x), nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));
157 if(hMemFile != -1) {
158 if(VirtualQuery((LPSTR)pageAddr, &memInfo, nrpages*PAGE_SIZE) == 0) {
159 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
160 goto fail;
161 }
162 if(memInfo.State & MEM_COMMIT)
163 {//if it's already committed, then the app tried to write to it
164 if(!fWriteAccess) {
165 dprintf(("Win32MemMap::commitPage: Huh? Already committed and not trying to write (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
166 goto fail;
167 }
168 if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
169 dprintf(("Win32MemMap::commitPage: Failed to set write flag on page (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
170 goto fail;
171 }
172 }
173 else {
174 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE) == FALSE) {
175 goto fail;
176 }
177 offset = pageAddr - (ULONG)pMapping;
178 size = nrpages*PAGE_SIZE;
179 if(offset + size > mSize) {
180 size = mSize - offset;
181 }
182 *(char *)pageAddr = 0; //testestestest
183 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
184 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset));
185 goto fail;
186 }
187 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) {
188 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr));
189 goto fail;
190 }
191 if(nrBytesRead != size) {
192 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr));
193 goto fail;
194 }
195 if(mProtFlags & PAGE_READONLY) {
196//DosSetMem returns flags with EXECUTE bit set, even though the initial allocation is without this bit set!
197//Also returns access denied when trying to set it back to READONLY
198 VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt);
199// if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
200// goto fail;
201// }
202 }
203 }
204 }
205 else {
206 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, newProt) == FALSE) {
207 goto fail;
208 }
209 }
210
211// mapMutex.leave();
212 return TRUE;
213fail:
214// mapMutex.leave();
215 return FALSE;
216}
217//******************************************************************************
218//******************************************************************************
219BOOL Win32MemMap::unmapViewOfFile()
220{
221 if(fMapped == FALSE)
222 return FALSE;
223
224 flushView(pMapping, mSize);
225 mapMutex.enter();
226 if(pMapping) {
227 VirtualFree(pMapping, mSize, MEM_RELEASE);
228 }
229 pMapping = NULL;
230 fMapped = FALSE;
231 mapMutex.leave();
232 return TRUE;
233}
234//******************************************************************************
235//******************************************************************************
236LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess)
237{
238 mapMutex.enter();
239 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
240 ULONG fAlloc = 0;
241 LPVOID mapview;
242
243 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE))
244 goto parmfail;
245 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY)))
246 goto parmfail;
247 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY))
248 goto parmfail;
249
250//TODO: If committed, read file into memory
251#if 0
252 if(mProtFlags & SEC_COMMIT)
253 fAlloc |= MEM_COMMIT;
254 else
255 if(mProtFlags & SEC_RESERVE)
256 fAlloc |= MEM_RESERVE;
257#else
258 fAlloc = MEM_RESERVE;
259#endif
260
261 if(fMapped == FALSE) {//if not mapped, reserve/commit entire view
262 pMapping = VirtualAlloc(0, mSize, fAlloc, memFlags);
263 if(pMapping == NULL) {
264 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
265 goto fail;
266 }
267 fMapped = TRUE;
268 }
269 mapview = (LPVOID)((ULONG)pMapping + offset);
270 mapMutex.leave();
271 return mapview;
272
273parmfail:
274 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
275 SetLastError(ERROR_INVALID_PARAMETER);
276fail:
277 mapMutex.leave();
278 return 0;
279}
280//******************************************************************************
281//We determine whether a page has been modified by checking it's protection flags
282//If the write flag is set, this means commitPage had to enable this due to a pagefault
283//(all pages are readonly until the app tries to modify it)
284//
285//TODO: Are apps allowed to change the protection flags of memory mapped pages?
286// I'm assuming they aren't for now.
287//******************************************************************************
288BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
289{
290 MEMORY_BASIC_INFORMATION memInfo;
291 ULONG nrpages, nrBytesWritten, offset, size;
292 int i;
293
294// mapMutex.enter();
295 dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush));
296 if(fMapped == FALSE)
297 goto parmfail;
298
299 if(cbFlush == 0)
300 cbFlush = mSize;
301
302 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
303 goto parmfail;
304
305 if(mProtFlags & PAGE_READONLY)
306 goto parmfail;
307
308 if(hMemFile == -1)
309 goto success; //TODO: Return an error here?
310
311 nrpages = cbFlush/PAGE_SIZE;
312 if(cbFlush & 0xFFF) nrpages++;
313
314 for(i=0;i<nrpages;i++) {
315 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
316 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
317 goto fail;
318 }
319 //If a page is reserved or write protected, we won't bother flushing it to disk
320 if(memInfo.State & MEM_COMMIT &&
321 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
322 {//committed and allowed for writing?
323 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
324 size = PAGE_SIZE;
325 if(offset + size > mSize) {
326 size = mSize - offset;
327 }
328 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
329
330 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
331 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
332 goto fail;
333 }
334 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
335 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
336 goto fail;
337 }
338 if(nrBytesWritten != size) {
339 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
340 goto fail;
341 }
342 }
343 }
344success:
345// mapMutex.leave();
346 return TRUE;
347parmfail:
348 SetLastError(ERROR_INVALID_PARAMETER);
349// mapMutex.leave();
350 return FALSE;
351fail:
352// mapMutex.leave();
353 return FALSE;
354}
355//******************************************************************************
356//******************************************************************************
357Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
358{
359 globalmapMutex.enter();
360 Win32MemMap *map = memmaps;
361
362 if(map != NULL) {
363 while(map) {
364 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
365 break;
366 map = map->next;
367 }
368 }
369 globalmapMutex.leave();
370 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
371 return map;
372}
373//******************************************************************************
374//******************************************************************************
375Win32MemMap *Win32MemMap::findMap(ULONG address)
376{
377 globalmapMutex.enter();
378 Win32MemMap *map = memmaps;
379
380 if(map != NULL) {
381 while(map) {
382 if(map->pMapping && (ULONG)map->pMapping <= address &&
383 (ULONG)map->pMapping + map->mSize > address)
384 {
385 break;
386 }
387 map = map->next;
388 }
389 }
390 globalmapMutex.leave();
391 return map;
392}
393//******************************************************************************
394//******************************************************************************
395void Win32MemMap::deleteAll()
396{
397 while(memmaps) {
398 CloseHandle(memmaps->hMemMap);
399 }
400}
401//******************************************************************************
402//******************************************************************************
403Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.