source: trunk/src/kernel32/mmapview.cpp@ 10369

Last change on this file since 10369 was 10369, checked in by sandervl, 22 years ago

fix

File size: 14.2 KB
Line 
1/* $Id: mmapview.cpp,v 1.4 2003-12-29 12:29:20 sandervl Exp $ */
2
3/*
4 * Win32 Memory mapped file & view classes
5 *
6 * Copyright 1999-2003 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 * TODO: Memory mapped files with views that extend the file (not 100% correct now)
19 * TODO: Suspend all threads when a page is committed (possible that another thread
20 * accesses the same memory before the page is read from disk
21 * TODO: File maps for new files (must select an initial size)!
22 *
23 * Project Odin Software License can be found in LICENSE.TXT
24 *
25 */
26#include <os2win.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <win\virtual.h>
31#include <odincrt.h>
32#include <handlemanager.h>
33#include "mmap.h"
34#include "oslibdos.h"
35#include "oslibmem.h"
36#include <winimagepeldr.h>
37#include <custombuild.h>
38
39#define DBG_LOCALLOG DBG_mmapview
40#include "dbglocal.h"
41
42Win32MemMapView *Win32MemMapView::mapviews = NULL;
43
44//******************************************************************************
45// Class Win32MemMapView
46//
47// Memory map view
48//
49// View parent = memory map that contains the original memory map
50// View owner = duplicate memory map that created this view (can be NULL)
51//
52//******************************************************************************
53Win32MemMapView::Win32MemMapView(Win32MemMap *map, ULONG offset, ULONG size,
54 ULONG fdwAccess, Win32MemMap *owner)
55{
56 LPVOID viewaddr = (LPVOID)((ULONG)map->getMappingAddr()+offset);
57 ULONG accessAttr = 0;
58
59 errorState = 0;
60 mParentMap = map;
61 mOwnerMap = NULL;
62 pCOWBitmap = NULL;
63 mSize = size;
64 mOffset = offset;
65 mProcessId = GetCurrentProcessId();
66 pShareViewAddr = NULL;
67
68 switch(fdwAccess) {
69 case FILE_MAP_READ:
70 accessAttr = PAG_READ;
71 mfAccess = MEMMAP_ACCESS_READ;
72 break;
73 case FILE_MAP_ALL_ACCESS:
74 case FILE_MAP_WRITE:
75 case FILE_MAP_WRITE|FILE_MAP_READ:
76 accessAttr = (PAG_READ|PAG_WRITE);
77 mfAccess = MEMMAP_ACCESS_READ | MEMMAP_ACCESS_WRITE;
78 break;
79 case FILE_MAP_COPY:
80 accessAttr = (PAG_READ|PAG_WRITE);
81 mfAccess = MEMMAP_ACCESS_READ | MEMMAP_ACCESS_WRITE | MEMMAP_ACCESS_COPYONWRITE;
82 break;
83 }
84 //Named file mappings from other processes are always shared;
85 //map into our address space
86 if(map->getMemName() != NULL && map->getProcessId() != mProcessId)
87 {
88 //shared memory map, so map it into our address space
89 if(OSLibDosGetNamedSharedMem((LPVOID *)&viewaddr, map->getMemName()) != OSLIB_NOERROR)
90 {
91 dprintf(("new OSLibDosGetNamedSharedMem FAILED"));
92 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
93 errorState = 1;
94 return;
95 }
96 pShareViewAddr = viewaddr;
97 viewaddr = (LPVOID)((char *)viewaddr + mOffset);
98 }
99
100 //view == memory mapping for executable images (only used internally)
101 if(map->getImage()) {
102 pMapView = map->getMappingAddr();
103 pMapView = (LPVOID)((char *)pMapView + mOffset);
104 }
105 else {
106 if(mfAccess & MEMMAP_ACCESS_COPYONWRITE)
107 {
108 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
109 errorState = 1;
110 return;
111 }
112 else
113 if(OSLibDosAliasMem(viewaddr, size, &pMapView, accessAttr) != OSLIB_NOERROR) {
114 dprintf(("new OSLibDosAliasMem FAILED"));
115 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
116 errorState = 1;
117 return;
118 }
119 }
120
121 dprintf(("Win32MemMapView::Win32MemMapView: created %x (alias for %x), size %d", pMapView, viewaddr, size));
122 mParentMap->AddRef();
123 mParentMap->AddView();
124
125 DosEnterCriticalSection(&globalmapcritsect);
126 Win32MemMapView *tmpview = mapviews;
127
128 if(tmpview == NULL || tmpview->getViewAddr() > pMapView) {
129 next = mapviews;
130 mapviews = this;
131 }
132 else {
133 while(tmpview->next) {
134 if(tmpview->next->getViewAddr() > pMapView) {
135 break;
136 }
137 tmpview = tmpview->next;
138 }
139 next = tmpview->next;
140 tmpview->next = this;
141 }
142 DosLeaveCriticalSection(&globalmapcritsect);
143
144 if(owner) {
145 mOwnerMap = owner;
146 mOwnerMap->AddRef();
147 mOwnerMap->AddView();
148 }
149}
150//******************************************************************************
151//******************************************************************************
152Win32MemMapView::~Win32MemMapView()
153{
154 if(errorState != 0)
155 return;
156
157 dprintf(("Win32MemMapView dtor: deleting view %x %x", mOffset, mSize));
158
159 if(mfAccess & MEMMAP_ACCESS_WRITE)
160 mParentMap->flushView(MMAP_FLUSHVIEW_ALL, mOffset, mSize);
161
162 //Don't free memory for executable image map views (only used internally)
163 if(!mParentMap->getImage())
164 OSLibDosFreeMem(pMapView);
165
166 if(pShareViewAddr) {
167 OSLibDosFreeMem(pShareViewAddr);
168 }
169 if(pCOWBitmap) free(pCOWBitmap);
170
171 DosEnterCriticalSection(&globalmapcritsect);
172 Win32MemMapView *view = mapviews;
173
174 if(view == this) {
175 mapviews = next;
176 }
177 else {
178 while(view->next) {
179 if(view->next == this)
180 break;
181 view = view->next;
182 }
183 if(view->next) {
184 view->next = next;
185 }
186 else dprintf(("Win32MemMapView::~Win32MemMapView: map not found!! (%x)", this));
187 }
188 DosLeaveCriticalSection(&globalmapcritsect);
189
190 mParentMap->RemoveView();
191 mParentMap->Release();
192 if(mOwnerMap) {
193 mOwnerMap->RemoveView();
194 mOwnerMap->Release();
195 }
196}
197//******************************************************************************
198// Win32MemMapView::markCOWPages
199//
200// Mark pages as private in the COW page bitmap
201//
202// Parameters:
203//
204// int startpage - start page
205// int nrpages - number of pages
206//
207//
208//******************************************************************************
209void Win32MemMapView::markCOWPages(int startpage, int nrpages)
210{
211 int viewpagestart, nrviewpages;
212
213 if(pCOWBitmap == NULL) {
214 //not a COW view; ignore
215 return;
216 }
217 //check if this page is part of our view
218 viewpagestart = mOffset >> PAGE_SHIFT;
219 nrviewpages = mSize >> PAGE_SHIFT;
220 if(mSize & 0xFFF)
221 nrviewpages++;
222
223 if(startpage < viewpagestart || startpage >= viewpagestart+nrviewpages) {
224 return; //outside this view
225 }
226 if(startpage + nrpages > viewpagestart + nrviewpages) {
227 nrpages -= ((startpage + nrpages) - (viewpagestart + nrviewpages));
228 }
229
230 for(int i=startpage;i<startpage+nrpages;i++) {
231 set_bit(i, pCOWBitmap);
232 }
233}
234//******************************************************************************
235// Win32MemMapView::changePageFlags
236//
237// Change the protection flags of our alias. Called when a range of pages has
238// been committed.
239//
240// Parameters:
241//
242// ULONG offset - offset in memory map (page aligned!)
243// ULONG size - size of committed page range
244// PAGEVIEW flags - page flags
245// PAGEVIEW_READONLY -> set page flags to readonly
246// PAGEVIEW_VIEW -> set page flags to view default
247//
248// Returns:
249// TRUE - success
250// FALSE - failure
251//
252//******************************************************************************
253BOOL Win32MemMapView::changePageFlags(ULONG offset, ULONG size, PAGEVIEW flags)
254{
255 ULONG accessAttr = 0, rc;
256
257 //offset must be page aligned
258 if(offset & 0xFFF) {
259 DebugInt3();
260 return FALSE;
261 }
262
263 if( ( (mfAccess & MEMMAP_ACCESS_COPYONWRITE) && (flags != PAGEVIEW_GUARD) ) ||
264 ( (flags == PAGEVIEW_GUARD) && !(mfAccess & MEMMAP_ACCESS_COPYONWRITE) ) )
265 {
266 //PAGEVIEW_VIEW/READONLY does not apply to COW views
267 return TRUE;
268 }
269 if(mOffset + mSize <= offset || mOffset >= offset + size) {
270 return TRUE; //not part of this view
271 }
272 if(offset < mOffset) {
273 size -= mOffset - offset;
274 offset = mOffset;
275 }
276 if(mOffset + mSize < offset + size) {
277 size -= ((offset + size) - (mOffset + mSize));
278 }
279
280 if(flags == PAGEVIEW_READONLY) {
281 accessAttr = PAG_READ;
282 }
283 else
284 {//use view attributes
285 if(mfAccess & MEMMAP_ACCESS_READ) {
286 accessAttr |= PAG_READ;
287 }
288 if(mfAccess & MEMMAP_ACCESS_WRITE) {
289 accessAttr |= PAG_WRITE;
290 }
291 }
292
293 {
294 rc = OSLibDosSetMem((char *)pMapView+(offset - mOffset), size, accessAttr);
295 if(rc) {
296 dprintf(("Win32MemMapView::changePageFlags: OSLibDosSetMem %x %x %x failed with %d", (char *)pMapView+(offset - mOffset), size, accessAttr, rc));
297 return FALSE;
298 }
299 }
300 return TRUE;
301}
302//******************************************************************************
303//******************************************************************************
304int Win32MemMapView::findViews(Win32MemMap *map, int nrViews,
305 Win32MemMapView *viewarray[])
306{
307 int i=0;
308
309 DosEnterCriticalSection(&globalmapcritsect);
310 Win32MemMapView *view = mapviews, *nextview;
311
312 if(view != NULL)
313 {
314 while(view && i < nrViews)
315 {
316 if(view->getParentMap() == map)
317 {
318 viewarray[i] = view;
319 i++;
320 }
321 view = view->next;
322 }
323 }
324 DosLeaveCriticalSection(&globalmapcritsect);
325 return i;
326}
327//******************************************************************************
328//******************************************************************************
329void Win32MemMapView::deleteViews(Win32MemMap *map)
330{
331 DosEnterCriticalSection(&globalmapcritsect);
332 Win32MemMapView *view = mapviews, *nextview;
333
334 if(view != NULL)
335 {
336 while(view)
337 {
338 nextview = view->next;
339 if(view->getParentMap() == map)
340 {
341 DosLeaveCriticalSection(&globalmapcritsect);
342 delete view;
343 DosEnterCriticalSection(&globalmapcritsect);
344 }
345 view = nextview;
346 }
347 }
348 DosLeaveCriticalSection(&globalmapcritsect);
349}
350//******************************************************************************
351//******************************************************************************
352// Win32MemMap::findMapByView
353//
354// Find the map of the view that contains the specified starting address
355// and has the specified access type
356//
357// Parameters:
358//
359// ULONG address - view address
360// ULONG *offset - address of ULONG that receives the offset
361// in the returned memory map
362// ULONG accessType - access type:
363// MEMMAP_ACCESS_READ
364// MEMMAP_ACCESS_WRITE
365// MEMMAP_ACCESS_EXECUTE
366//
367// Returns:
368// <> NULL - success, address of parent map object
369// NULL - failure
370//
371//******************************************************************************
372//******************************************************************************
373Win32MemMap *Win32MemMapView::findMapByView(ULONG address,
374 ULONG *offset,
375 ULONG accessType)
376{
377 Win32MemMap *map = NULL;
378 ULONG ulOffset;
379
380 if(mapviews == NULL) return NULL;
381
382 DosEnterCriticalSection(&globalmapcritsect);
383 Win32MemMapView *view = mapviews;
384 ULONG ulViewAddr;
385
386 if(!offset) offset = &ulOffset;
387
388 *offset = 0;
389
390 if(view != NULL)
391 {
392 do
393 {
394 ulViewAddr = (ULONG)view->getViewAddr();
395
396 // if ulViewAddr is > address, we've exhausted
397 // the sorted list already and can abort search.
398 if(ulViewAddr <= address)
399 {
400 if(ulViewAddr + view->getSize() > address &&
401 view->getAccessFlags() >= accessType)
402 {
403 *offset = view->getOffset() + (address - ulViewAddr);
404 goto success;
405 }
406
407 // Not found yet, continue search with next map
408 view = view->next;
409 }
410 else
411 {
412 // list is exhausted, abort loop
413 view = NULL;
414 }
415 }
416 while(view);
417
418 //failure if we get here
419 view = NULL;
420 }
421success:
422#ifdef DEBUG
423 if(view && !view->getParentMap()->isImageMap())
424 dprintf(("findMapByView %x %x -> %x off %x",
425 address,
426 accessType,
427 view->getViewAddr(),
428 *offset));
429#endif
430
431 if(view) {
432 //first look at the owner (duplicate map), then the real parent
433 map = view->getOwnerMap();
434 if(!map) map = view->getParentMap();
435
436 if(map) map->AddRef();
437 }
438
439 DosLeaveCriticalSection(&globalmapcritsect);
440
441 return map;
442}
443//******************************************************************************
444// Win32MemMap::findView
445//
446// Find the view that contains the specified starting address
447//
448// Parameters:
449//
450// LPVOID address - view address
451//
452// Returns:
453// <> NULL - success, address view object
454// NULL - failure
455//
456//******************************************************************************
457Win32MemMapView *Win32MemMapView::findView(ULONG address)
458{
459 ULONG ulViewAddr;
460
461 DosEnterCriticalSection(&globalmapcritsect);
462 Win32MemMapView *view = mapviews;
463
464 if(view != NULL) {
465 while(view) {
466 ulViewAddr = (ULONG)view->getViewAddr();
467 if(ulViewAddr <= address && ulViewAddr + view->getSize() > address)
468 {
469 break;
470 }
471 view = view->next;
472 }
473 }
474 DosLeaveCriticalSection(&globalmapcritsect);
475 return view;
476}
477//******************************************************************************
478//******************************************************************************
Note: See TracBrowser for help on using the repository browser.