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

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

Memory mapping changes

File size: 10.8 KB
Line 
1/* $Id: mmap.cpp,v 1.10 1999-08-25 11:40:18 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(cbFlush == 0)
257 cbFlush = mSize;
258
259 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
260 goto parmfail;
261
262 if(mProtFlags & PAGE_READONLY)
263 goto parmfail;
264
265 if(hMemFile == -1)
266 goto success; //TODO: Return an error here?
267
268 nrpages = cbFlush/PAGE_SIZE;
269 if(cbFlush & 0xFFF) nrpages++;
270
271 for(i=0;i<nrpages;i++) {
272 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
273 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
274 goto fail;
275 }
276 //If a page is reserved or write protected, we won't bother flushing it to disk
277 if(memInfo.State & MEM_COMMIT &&
278 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
279 {//committed and allowed for writing?
280 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
281 size = PAGE_SIZE;
282 if(offset + size > mSize) {
283 size = mSize - offset;
284 }
285 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
286
287 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
288 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
289 goto fail;
290 }
291 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
292 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
293 goto fail;
294 }
295 if(nrBytesWritten != size) {
296 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
297 goto fail;
298 }
299 }
300 }
301success:
302// mapMutex.leave();
303 return TRUE;
304parmfail:
305 SetLastError(ERROR_INVALID_PARAMETER);
306// mapMutex.leave();
307 return FALSE;
308fail:
309// mapMutex.leave();
310 return FALSE;
311}
312//******************************************************************************
313//******************************************************************************
314Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
315{
316 globalmapMutex.enter();
317 Win32MemMap *map = memmaps;
318
319 if(map != NULL) {
320 while(map) {
321 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
322 break;
323 map = map->next;
324 }
325 }
326 globalmapMutex.leave();
327 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
328 return map;
329}
330//******************************************************************************
331//******************************************************************************
332Win32MemMap *Win32MemMap::findMap(ULONG address)
333{
334 globalmapMutex.enter();
335 Win32MemMap *map = memmaps;
336
337 if(map != NULL) {
338 while(map) {
339 if(map->pMapping && (ULONG)map->pMapping <= address &&
340 (ULONG)map->pMapping + map->mSize > address)
341 {
342 break;
343 }
344 map = map->next;
345 }
346 }
347 globalmapMutex.leave();
348 return map;
349}
350//******************************************************************************
351//******************************************************************************
352void Win32MemMap::deleteAll()
353{
354 while(memmaps) {
355 CloseHandle(memmaps->hMemMap);
356 }
357}
358//******************************************************************************
359//******************************************************************************
360Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.