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

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

handle manager changes for DuplicateHandle + memory mapped file changes/bugfixes

File size: 10.9 KB
Line 
1/* $Id: mmap.cpp,v 1.11 1999-08-25 14:27:07 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 next = memmaps;
43 memmaps = this;
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 mSize = SetFilePointer(hMemFile, 0, NULL, FILE_END);
71 if(mSize == -1) {
72 dprintf(("Win32MemMap::init: SetFilePointer failed to set pos end"));
73 goto fail;
74 }
75 }
76 this->hMemMap = hMemMap;
77 mapMutex.leave();
78 return TRUE;
79fail:
80 mapMutex.leave();
81 return FALSE;
82}
83//******************************************************************************
84//******************************************************************************
85Win32MemMap::~Win32MemMap()
86{
87 unmapViewOfFile();
88 if(lpszMapName) {
89 free(lpszMapName);
90 }
91 mapMutex.enter();
92 if(pMapping) {
93 VirtualFree(pMapping, mSize, MEM_RELEASE);
94 pMapping = NULL;
95 }
96 if(hMemFile != -1) {
97 CloseHandle(hMemFile);
98 hMemFile = -1;
99 }
100 mapMutex.leave();
101
102 globalmapMutex.enter();
103 Win32MemMap *map = memmaps;
104
105 if(map == this) {
106 memmaps = next;
107 }
108 else {
109 while(map->next) {
110 if(map->next == this)
111 break;
112 map = map->next;
113 }
114 if(map->next) {
115 map->next = next;
116 }
117 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
118 }
119 globalmapMutex.leave();
120}
121//******************************************************************************
122//******************************************************************************
123BOOL Win32MemMap::hasReadAccess()
124{
125 return TRUE; //should have at least this
126}
127//******************************************************************************
128//******************************************************************************
129BOOL Win32MemMap::hasWriteAccess()
130{
131 return !(mProtFlags & PAGE_READONLY);
132}
133//******************************************************************************
134//Might want to add this feature for memory mapping executable & dll files in
135//the loader (done in Win32 with the SEC_IMAGE flag?)
136//******************************************************************************
137BOOL Win32MemMap::hasExecuteAccess()
138{
139 return FALSE;
140}
141//******************************************************************************
142//******************************************************************************
143BOOL Win32MemMap::commitPage(LPVOID lpPageFaultAddr, ULONG nrpages)
144{
145 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
146 DWORD oldProt, newProt, nrBytesRead, offset, size;
147
148// mapMutex.enter();
149 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
150
151 dprintf(("Win32MemMap::commitPage %x (faultaddr %x), nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));
152 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, newProt) == FALSE) {
153 goto fail;
154 }
155 if(hMemFile != -1) {
156 offset = pageAddr - (ULONG)pMapping;
157 size = nrpages*PAGE_SIZE;
158 if(offset + size > mSize) {
159 size = mSize - offset;
160 }
161 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
162 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset));
163 goto fail;
164 }
165 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) {
166 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr));
167 goto fail;
168 }
169 if(nrBytesRead != size) {
170 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr));
171 goto fail;
172 }
173 }
174
175// mapMutex.leave();
176 return TRUE;
177fail:
178// mapMutex.leave();
179 return FALSE;
180}
181//******************************************************************************
182//******************************************************************************
183BOOL Win32MemMap::unmapViewOfFile()
184{
185 if(fMapped == FALSE)
186 return FALSE;
187
188 flushView(pMapping, mSize);
189 mapMutex.enter();
190 if(pMapping) {
191 VirtualFree(pMapping, mSize, MEM_RELEASE);
192 }
193 pMapping = NULL;
194 fMapped = FALSE;
195 mapMutex.leave();
196 return TRUE;
197}
198//******************************************************************************
199//******************************************************************************
200LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess)
201{
202 mapMutex.enter();
203 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
204 ULONG fAlloc = 0;
205 LPVOID mapview;
206
207 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE))
208 goto parmfail;
209 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY)))
210 goto parmfail;
211 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY))
212 goto parmfail;
213
214//TODO: If committed, read file into memory
215#if 0
216 if(mProtFlags & SEC_COMMIT)
217 fAlloc |= MEM_COMMIT;
218 else
219 if(mProtFlags & SEC_RESERVE)
220 fAlloc |= MEM_RESERVE;
221#else
222 fAlloc = MEM_RESERVE;
223#endif
224
225 if(fMapped == FALSE) {//if not mapped, reserve/commit entire view
226 pMapping = VirtualAlloc(0, mSize, fAlloc, mProtFlags);
227 if(pMapping == NULL) {
228 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
229 goto fail;
230 }
231 fMapped = TRUE;
232 }
233 mapview = (LPVOID)((ULONG)pMapping + offset);
234 mapMutex.leave();
235 return mapview;
236
237parmfail:
238 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
239 SetLastError(ERROR_INVALID_PARAMETER);
240fail:
241 mapMutex.leave();
242 return 0;
243}
244//******************************************************************************
245// NOTE: There's no easy way to determine which pages were modified. Temporary
246// solution is to write all paged-in memory to disk.
247//TODO: Are apps allowed to change the protection flags of memory mapped pages?
248// I'm assuming they aren't for now.
249//******************************************************************************
250BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
251{
252 MEMORY_BASIC_INFORMATION memInfo;
253 ULONG nrpages, nrBytesWritten, offset, size;
254 int i;
255
256// mapMutex.enter();
257 if(fMapped == FALSE)
258 goto parmfail;
259
260 if(cbFlush == 0)
261 cbFlush = mSize;
262
263 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
264 goto parmfail;
265
266 if(mProtFlags & PAGE_READONLY)
267 goto parmfail;
268
269 if(hMemFile == -1)
270 goto success; //TODO: Return an error here?
271
272 nrpages = cbFlush/PAGE_SIZE;
273 if(cbFlush & 0xFFF) nrpages++;
274
275 for(i=0;i<nrpages;i++) {
276 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
277 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
278 goto fail;
279 }
280 //If a page is reserved or write protected, we won't bother flushing it to disk
281 if(memInfo.State & MEM_COMMIT &&
282 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
283 {//committed and allowed for writing?
284 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
285 size = PAGE_SIZE;
286 if(offset + size > mSize) {
287 size = mSize - offset;
288 }
289 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
290
291 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
292 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
293 goto fail;
294 }
295 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
296 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
297 goto fail;
298 }
299 if(nrBytesWritten != size) {
300 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
301 goto fail;
302 }
303 }
304 }
305success:
306// mapMutex.leave();
307 return TRUE;
308parmfail:
309 SetLastError(ERROR_INVALID_PARAMETER);
310// mapMutex.leave();
311 return FALSE;
312fail:
313// mapMutex.leave();
314 return FALSE;
315}
316//******************************************************************************
317//******************************************************************************
318Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
319{
320 globalmapMutex.enter();
321 Win32MemMap *map = memmaps;
322
323 if(map != NULL) {
324 while(map) {
325 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
326 break;
327 map = map->next;
328 }
329 }
330 globalmapMutex.leave();
331 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
332 return map;
333}
334//******************************************************************************
335//******************************************************************************
336Win32MemMap *Win32MemMap::findMap(ULONG address)
337{
338 globalmapMutex.enter();
339 Win32MemMap *map = memmaps;
340
341 if(map != NULL) {
342 while(map) {
343 if(map->pMapping && (ULONG)map->pMapping <= address &&
344 (ULONG)map->pMapping + map->mSize > address)
345 {
346 break;
347 }
348 map = map->next;
349 }
350 }
351 globalmapMutex.leave();
352 return map;
353}
354//******************************************************************************
355//******************************************************************************
356void Win32MemMap::deleteAll()
357{
358 while(memmaps) {
359 CloseHandle(memmaps->hMemMap);
360 }
361}
362//******************************************************************************
363//******************************************************************************
364Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.