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

Last change on this file since 9824 was 9824, checked in by sandervl, 23 years ago

Cleaned up memory map code

File size: 30.6 KB
Line 
1/* $Id: mmap.cpp,v 1.61 2003-02-18 18:48:55 sandervl Exp $ */
2
3/*
4 * Win32 Memory mapped file & view classes
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 * 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_mmap
40#include "dbglocal.h"
41
42//Global DLL Data
43#pragma data_seg(_GLOBALDATA)
44Win32MemMap *Win32MemMap::memmaps = NULL;
45CRITICAL_SECTION_OS2 globalmapcritsect = {0};
46#pragma data_seg()
47Win32MemMapView *Win32MemMapView::mapviews = NULL;
48
49
50static char *pszMMapSemName = MEMMAP_CRITSECTION_NAME;
51
52//******************************************************************************
53//******************************************************************************
54void WIN32API SetCustomMMapSemName(LPSTR pszSemName)
55{
56 pszMMapSemName = pszSemName;
57}
58//******************************************************************************
59//******************************************************************************
60void InitializeMemMaps()
61{
62 if(globalmapcritsect.hmtxLock == 0) {
63 dprintf(("InitializeMemMaps -> create shared critical section"));
64 DosInitializeCriticalSection(&globalmapcritsect, pszMMapSemName);
65 }
66 else {
67 dprintf(("InitializeMemMaps -> access shared critical section"));
68 DosAccessCriticalSection(&globalmapcritsect, pszMMapSemName);
69 }
70}
71//******************************************************************************
72//******************************************************************************
73Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
74 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), image(0)
75{
76 DosEnterCriticalSection(&globalmapcritsect);
77 next = memmaps;
78 memmaps = this;
79 DosLeaveCriticalSection(&globalmapcritsect);
80
81 hMemFile = hOrgMemFile = hfile;
82
83 mSize = size;
84 mProtFlags = fdwProtect;
85 mProcessId = GetCurrentProcessId();
86
87 if(lpszName) {
88 lpszMapName = (char *)_smalloc(strlen(lpszName)+1);
89 strcpy(lpszMapName, lpszName);
90 }
91 else lpszMapName = NULL;
92}
93//******************************************************************************
94//Map constructor used for executable image maps (only used internally)
95//******************************************************************************
96Win32MemMap::Win32MemMap(Win32PeLdrImage *pImage, ULONG baseAddress, ULONG size)
97 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0), image(0)
98{
99 DosEnterCriticalSection(&globalmapcritsect);
100 next = memmaps;
101 memmaps = this;
102 DosLeaveCriticalSection(&globalmapcritsect);
103
104 hMemFile = hOrgMemFile = -1;
105
106 mSize = size;
107 mProtFlags = PAGE_READWRITE;
108 mProcessId = GetCurrentProcessId();
109
110 pMapping = (LPVOID)baseAddress;
111
112 image = pImage;
113 lpszMapName= NULL;
114}
115//******************************************************************************
116//******************************************************************************
117BOOL Win32MemMap::Init(DWORD aMSize)
118{
119 mapMutex.enter();
120 if(hMemFile != -1)
121 {
122#if 0
123 if(DuplicateHandle(GetCurrentProcess(), hMemFile, GetCurrentProcess(),
124 &hMemFile, 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE)
125#else
126 DWORD dwOdinOptions;
127
128 if(!(mProtFlags & PAGE_READWRITE)) {
129 dwOdinOptions = DUPLICATE_ACCESS_READ | DUPLICATE_SHARE_DENYNONE;
130 }
131 else dwOdinOptions = DUPLICATE_ACCESS_READWRITE | DUPLICATE_SHARE_DENYNONE;
132
133 if(HMDuplicateHandleOdin(GetCurrentProcess(), hMemFile, GetCurrentProcess(),
134 &hMemFile, 0, FALSE, DUPLICATE_SAME_ACCESS, dwOdinOptions) == FALSE)
135#endif
136 {
137 dprintf(("Win32MemMap::Init: DuplicateHandle failed!"));
138 goto fail;
139 }
140 mSize = SetFilePointer(hMemFile, 0, NULL, FILE_BEGIN);
141 mSize = SetFilePointer(hMemFile, 0, NULL, FILE_END);
142 if(mSize == -1) {
143 dprintf(("Win32MemMap::init: SetFilePointer failed to set pos end"));
144 goto fail;
145 }
146 if (mSize < aMSize)
147 {
148 dprintf(("Win32MemMap::init: file size %d, memory map size %d", mSize, aMSize));
149 //Froloff: Need to check if exist the possibility of file to memory
150 // mapping not from the beginning of file
151 mSize = SetFilePointer(hMemFile, aMSize, NULL, FILE_BEGIN);
152 // Commit filesize changes onto disk
153 SetEndOfFile(hMemFile);
154 }
155#if 0
156 //SvL: Temporary limitation of size (Warp Server Advanced doesn't allow
157 // one to reserve more than 450 MB (unless you override the virtual
158 // memory max limit) of continuous memory; (Warp 4 much less))
159 if(mSize > 64*1024*1024) {
160 mSize = 64*1024*1024;
161 }
162#endif
163 }
164
165 dprintf(("CreateFileMappingA for file %x, prot %x size %d, name %s", hMemFile, mProtFlags, mSize, lpszMapName));
166 mapMutex.leave();
167 return TRUE;
168fail:
169 mapMutex.leave();
170 return FALSE;
171}
172//******************************************************************************
173//******************************************************************************
174Win32MemMap::~Win32MemMap()
175{
176 Win32MemMapView::deleteViews(this); //delete all views of our memory mapped file
177
178 dprintf(("Win32MemMap dtor: deleting view %x %x", pMapping, mSize));
179
180 mapMutex.enter();
181 if(lpszMapName) {
182 free(lpszMapName);
183 }
184 if(pMapping && !image) {
185 if(lpszMapName) {
186 OSLibDosFreeMem(pMapping);
187 }
188 else VirtualFree(pMapping, 0, MEM_RELEASE);
189
190 pMapping = NULL;
191 }
192 if(hMemFile != -1) {
193 dprintf(("Win32MemMap dtor: closing memory file %x", hMemFile));
194 CloseHandle(hMemFile);
195 hMemFile = -1;
196 }
197 mapMutex.leave();
198
199 DosEnterCriticalSection(&globalmapcritsect);
200 Win32MemMap *map = memmaps;
201
202 if(map == this) {
203 memmaps = next;
204 }
205 else {
206 while(map->next) {
207 if(map->next == this)
208 break;
209 map = map->next;
210 }
211 if(map->next) {
212 map->next = next;
213 }
214 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
215 }
216 DosLeaveCriticalSection(&globalmapcritsect);
217}
218//******************************************************************************
219// Win32MemMap::setProtFlags
220//
221// Change the protection flags of this memory map if required
222// This is currently only used when creating a mapping for a file which already
223// has an existing mapping.
224//
225//
226// Parameters:
227//
228// DWORD dwNewProtect - new protection flags
229//
230// Returns:
231// TRUE - success
232// FALSE - failure
233//
234// NOTE:
235// We're ignoring the SEC_* flags for now
236//
237//******************************************************************************
238BOOL Win32MemMap::setProtFlags(DWORD dwNewProtect)
239{
240 if(!(dwNewProtect & (PAGE_READWRITE|PAGE_WRITECOPY))) return TRUE; //no need for changes
241
242 if(!(mProtFlags & PAGE_READWRITE))
243 {//ok, current mapping is readonly; need to change it to readwrite
244 mProtFlags &= ~PAGE_READONLY;
245 mProtFlags |= PAGE_READWRITE;
246
247 //that's all we need to do for now; memory mappings are readwrite by
248 //default (see mapViewOfFile)
249 }
250 return TRUE;
251}
252//******************************************************************************
253//If memory map has no more views left, then we can safely delete it when
254//it's handle is closed
255//******************************************************************************
256void Win32MemMap::Release()
257{
258 dprintf(("Win32MemMap::Release %s (%d)", lpszMapName, referenced-1));
259 --referenced;
260 if(nrMappings == 0 && referenced == 0) {
261 delete this;
262 }
263}
264//******************************************************************************
265//We determine whether a page has been modified by checking it's protection flags
266//If the write flag is set, this means commitPage had to enable this due to a pagefault
267//(all pages are readonly until the app tries to write to it)
268//******************************************************************************
269BOOL Win32MemMap::commitPage(ULONG offset, BOOL fWriteAccess, int nrpages)
270{
271 MEMORY_BASIC_INFORMATION memInfo;
272 LPVOID lpPageFaultAddr = (LPVOID)((ULONG)pMapping + offset);
273 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
274 DWORD oldProt, newProt, nrBytesRead, size;
275 int i;
276
277// mapMutex.enter();
278
279 if(image) {
280 return image->commitPage(pageAddr, fWriteAccess);
281 }
282 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
283
284 dprintf(("Win32MemMap::commitPage %x (faultaddr %x)", pageAddr, lpPageFaultAddr));
285 if(hMemFile != -1)
286 {
287 int faultsize = nrpages*PAGE_SIZE;
288
289 offset = pageAddr - (ULONG)pMapping;
290 if(offset + faultsize > mSize) {
291 faultsize = mSize - offset;
292 }
293
294 while(faultsize) {
295 if(VirtualQuery((LPSTR)pageAddr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) {
296 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));
297 goto fail;
298 }
299 memInfo.RegionSize = min(memInfo.RegionSize, faultsize);
300 //Only changes the state of the pages with the same attribute flags
301 //(returned in memInfo.RegionSize)
302 //If it's smaller than the mNrPages, it simply means one or more of the
303 //other pages have already been committed
304 if(!(memInfo.State & MEM_COMMIT))
305 {
306 if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE) == FALSE) {
307 goto fail;
308 }
309 offset = pageAddr - (ULONG)pMapping;
310 size = memInfo.RegionSize;
311 if(offset + size > mSize) {
312 dprintf(("Adjusting size from %d to %d", size, mSize - offset));
313 size = mSize - offset;
314 }
315 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
316 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset));
317 goto fail;
318 }
319 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) {
320 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr));
321 goto fail;
322 }
323 if(nrBytesRead != size) {
324 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr));
325 goto fail;
326 }
327 if(newProt != PAGE_READWRITE) {
328 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) {
329 goto fail;
330 }
331 }
332 }
333 faultsize -= memInfo.RegionSize;
334 pageAddr += memInfo.RegionSize;
335 }
336 }
337 else {
338 ULONG sizeleft = nrpages*PAGE_SIZE;
339 while(sizeleft)
340 {
341 if(VirtualQuery((LPSTR)pageAddr, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) {
342 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed", pageAddr, sizeleft));
343 goto fail;
344 }
345 memInfo.RegionSize = min(memInfo.RegionSize, sizeleft);
346
347 if(!(memInfo.State & MEM_COMMIT))
348 {//if it's already committed, then the app tried to write to it
349 if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, newProt) == FALSE)
350 goto fail;
351 }
352 memInfo.RegionSize = (memInfo.RegionSize+PAGE_SIZE-1) & ~0xfff;
353 pageAddr += memInfo.RegionSize;
354 sizeleft -= memInfo.RegionSize;
355 }
356 }
357
358// mapMutex.leave();
359 return TRUE;
360fail:
361// mapMutex.leave();
362 return FALSE;
363}
364//******************************************************************************
365// Win32MemMap::unmapViewOfFile
366//
367// Unmap the view identified by addr
368//
369// Parameters:
370//
371// LPVOID addr - view address; doesn't need to be the address
372// returned by MapViewOfFile(Ex) (as MSDN clearly says);
373// can be any address within the view range
374//
375// Returns:
376// TRUE - success
377// FALSE - failure
378//
379//******************************************************************************
380BOOL Win32MemMap::unmapViewOfFile(LPVOID addr)
381{
382 Win32MemMapView *view;
383
384 dprintf(("Win32MemMap::unmapViewOfFile %x (nrmaps=%d)", addr, nrMappings));
385 mapMutex.enter();
386
387 if(nrMappings == 0)
388 goto fail;
389
390 view = Win32MemMapView::findView((ULONG)addr);
391 if(view == NULL)
392 goto fail;
393
394 delete view;
395
396 if(--nrMappings == 0) {
397 VirtualFree(pMapping, 0, MEM_RELEASE);
398 pMapping = NULL;
399 }
400 mapMutex.leave();
401
402 //if there are no more mappings left and the memory map's handle has been
403 //closed, then delete the object
404 if(nrMappings == 0 && referenced == 0) {
405 delete this;
406 }
407 return TRUE;
408fail:
409 mapMutex.leave();
410 return FALSE;
411}
412//******************************************************************************
413//******************************************************************************
414LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess)
415{
416 DWORD processId = GetCurrentProcessId();
417
418 mapMutex.enter();
419 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
420 ULONG fAlloc = 0;
421 Win32MemMapView *mapview;
422
423 //@@@PH: if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY))
424 // Docs say FILE_MAP_ALL_ACCESS is same as FILE_MAP_WRITE. Doesn't match reality though.
425 if(fdwAccess & ~FILE_MAP_ALL_ACCESS)
426 goto parmfail;
427 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE))
428 goto parmfail;
429 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY)))
430 goto parmfail;
431
432 //@@@PH
433 if (fdwAccess != FILE_MAP_ALL_ACCESS)
434 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY))
435 goto parmfail;
436
437 if(offset+size > mSize && (!(fdwAccess & FILE_MAP_WRITE) || hMemFile == -1))
438 goto parmfail;
439
440 //SvL: TODO: Doesn't work for multiple views
441 if(offset+size > mSize) {
442 mSize = offset+size;
443 }
444
445//TODO: If committed, read file into memory
446#if 0
447 if(mProtFlags & SEC_COMMIT)
448 fAlloc |= MEM_COMMIT;
449 else
450 if(mProtFlags & SEC_RESERVE)
451 fAlloc |= MEM_RESERVE;
452#else
453 fAlloc = MEM_RESERVE;
454#endif
455
456 //Memory has already been allocated for executable image maps (only used internally)
457 if(!pMapping && nrMappings == 0)
458 {//if not mapped, reserve/commit entire view
459 //SvL: Always read/write access or else ReadFile will crash once we
460 // start committing pages.
461 // This is most likely an OS/2 bug and doesn't happen in Aurora
462 // when allocating memory with the PAG_ANY bit set. (without this
463 // flag it will also crash)
464 //NOTE: If this is ever changed, then we must update setProtFlags!!!!
465
466 //All named file mappings are shared (files & memory only)
467 if(lpszMapName) {
468 pMapping = VirtualAllocShared(mSize, fAlloc, PAGE_READWRITE, lpszMapName);
469 }
470 else {
471 pMapping = VirtualAlloc(0, mSize, fAlloc, PAGE_READWRITE);
472 }
473 if(pMapping == NULL) {
474 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
475 goto fail;
476 }
477 //Windows NT seems to commit memory for memory maps, regardsless of the SEC_COMMIT flag
478 if((hMemFile == -1 && !image)) {//commit memory
479 VirtualAlloc(pMapping, mSize, MEM_COMMIT, PAGE_READWRITE);
480 }
481 if(hMemFile != -1 && (mProtFlags & SEC_COMMIT)) {
482 DWORD nrPages = mSize >> PAGE_SHIFT;
483 if(mSize & 0xFFF)
484 nrPages++;
485
486 commitPage(0, FALSE, nrPages);
487 }
488 }
489 mapview = new Win32MemMapView(this, offset, (size == 0) ? (mSize - offset) : size, fdwAccess);
490 if(mapview == NULL) {
491 goto fail;
492 }
493 if(mapview->everythingOk() == FALSE) {
494 dprintf(("Win32MemMap::mapFileView: !mapview->everythingOk"));
495 delete mapview;
496 goto fail;
497 }
498 nrMappings++;
499 mapMutex.leave();
500 return mapview->getViewAddr();
501
502parmfail:
503 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
504 SetLastError(ERROR_INVALID_PARAMETER);
505fail:
506 mapMutex.leave();
507 return 0;
508}
509//******************************************************************************
510//We determine whether a page has been modified by checking it's protection flags
511//If the write flag is set, this means commitPage had to enable this due to a pagefault
512//(all pages are readonly until the app tries to modify the contents of the page)
513//
514//TODO: Are apps allowed to change the protection flags of memory mapped pages?
515// I'm assuming they aren't for now.
516//******************************************************************************
517BOOL Win32MemMap::flushView(ULONG offset, ULONG cbFlush)
518{
519 LPVOID lpvBase = (LPVOID)((ULONG)pMapping+offset);
520 MEMORY_BASIC_INFORMATION memInfo;
521 ULONG nrBytesWritten, size;
522 int i;
523
524 if(image) //no flushing for image maps
525 return TRUE;
526
527 dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush));
528 if(nrMappings == 0)
529 goto parmfail;
530
531 if(cbFlush == 0)
532 cbFlush = mSize;
533
534 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
535 goto parmfail;
536
537 if(mProtFlags & PAGE_READONLY)
538 goto parmfail;
539
540 if(hMemFile == -1)
541 goto success; //TODO: Return an error here?
542
543 while(cbFlush) {
544 if(VirtualQuery((LPSTR)lpvBase, &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0) {
545 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
546 goto fail;
547 }
548 //If a page (or range of pages) is reserved or write protected, we
549 //won't bother flushing it to disk
550 if(memInfo.State & MEM_COMMIT &&
551 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
552 {//committed and allowed for writing?
553 offset = (ULONG)lpvBase - (ULONG)pMapping;
554 size = memInfo.RegionSize;
555 if(size > cbFlush) {
556 size = cbFlush;
557 }
558 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
559
560 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
561 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
562 goto fail;
563 }
564 if(WriteFile(hMemFile, (LPSTR)lpvBase, size, &nrBytesWritten, NULL) == FALSE) {
565 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase));
566 goto fail;
567 }
568 if(nrBytesWritten != size) {
569 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase));
570 goto fail;
571 }
572 }
573 lpvBase = (LPVOID)((ULONG)lpvBase + memInfo.RegionSize);
574
575 if(cbFlush < memInfo.RegionSize)
576 break;
577
578 cbFlush -= memInfo.RegionSize;
579 }
580success:
581 return TRUE;
582parmfail:
583 SetLastError(ERROR_INVALID_PARAMETER);
584 return FALSE;
585fail:
586 return FALSE;
587}
588//******************************************************************************
589//******************************************************************************
590Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
591{
592 if(lpszName == NULL)
593 return NULL;
594
595 DosEnterCriticalSection(&globalmapcritsect);
596 Win32MemMap *map = memmaps;
597
598 if(map != NULL) {
599 while(map) {
600 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
601 break;
602 map = map->next;
603 }
604 }
605 if(map) map->AddRef();
606
607 DosLeaveCriticalSection(&globalmapcritsect);
608 if(!map) dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
609 return map;
610}
611//******************************************************************************
612//******************************************************************************
613Win32MemMap *Win32MemMap::findMapByFile(HANDLE hFile)
614{
615 if(hFile == -1)
616 return NULL;
617
618 DosEnterCriticalSection(&globalmapcritsect);
619 Win32MemMap *map = memmaps;
620
621 if(map != NULL)
622 {
623 while(map) {
624 if(map->hOrgMemFile == hFile)
625 break;
626 map = map->next;
627 }
628 }
629 if(map) map->AddRef();
630 DosLeaveCriticalSection(&globalmapcritsect);
631 if(!map) dprintf(("Win32MemMap::findMapByFile: couldn't find map with file handle %x", hFile));
632 return map;
633}
634//******************************************************************************
635//******************************************************************************
636Win32MemMap *Win32MemMap::findMap(ULONG address)
637{
638 DosEnterCriticalSection(&globalmapcritsect);
639 Win32MemMap *map = memmaps;
640
641 if(map != NULL) {
642 while(map) {
643 if(map->pMapping && (ULONG)map->pMapping <= address &&
644 (ULONG)map->pMapping + map->mSize > address)
645 {
646 break;
647 }
648 map = map->next;
649 }
650 }
651 if(map) map->AddRef();
652 DosLeaveCriticalSection(&globalmapcritsect);
653 return map;
654}
655//******************************************************************************
656//******************************************************************************
657void Win32MemMap::deleteAll()
658{
659 Win32MemMap *map = memmaps, *nextmap;
660 DWORD processId = GetCurrentProcessId();
661
662 //delete all maps created by this process
663 DosEnterCriticalSection(&globalmapcritsect);
664 while(map) {
665 nextmap = map->next;
666 if(map->getProcessId() == processId) {
667 //Delete map directly for executable images (only used internally)
668 if(map->getImage()) {
669 delete map;
670 }
671 else {
672 delete map;
673 }
674 }
675 else {
676 //delete all views created by this process for this map
677 Win32MemMapView::deleteViews(map);
678 }
679 map = nextmap;
680 }
681 DosLeaveCriticalSection(&globalmapcritsect);
682}
683//******************************************************************************
684//******************************************************************************
685Win32MemMapView::Win32MemMapView(Win32MemMap *map, ULONG offset, ULONG size,
686 ULONG fdwAccess)
687{
688 LPVOID viewaddr = (LPVOID)((ULONG)map->getMappingAddr()+offset);
689 ULONG accessAttr = 0;
690 Win32MemMapView *tmpview = mapviews;
691
692 errorState = 0;
693 mParentMap = map;
694 mSize = size;
695 mOffset = offset;
696 mProcessId = GetCurrentProcessId();
697 pShareViewAddr = NULL;
698
699 switch(fdwAccess) {
700 case FILE_MAP_READ:
701 accessAttr = PAG_READ;
702 mfAccess = MEMMAP_ACCESS_READ;
703 break;
704 case FILE_MAP_ALL_ACCESS:
705 case FILE_MAP_WRITE:
706 case FILE_MAP_WRITE|FILE_MAP_READ:
707 case FILE_MAP_COPY:
708 accessAttr = (PAG_READ|PAG_WRITE);
709 mfAccess = MEMMAP_ACCESS_READ | MEMMAP_ACCESS_WRITE;
710 break;
711 }
712 //Named file mappings from other processes are always shared;
713 //map into our address space
714 if(map->getMemName() != NULL && map->getProcessId() != mProcessId)
715 {
716 //shared memory map, so map it into our address space
717 if(OSLibDosGetNamedSharedMem((LPVOID *)&viewaddr, map->getMemName()) != OSLIB_NOERROR) {
718 dprintf(("new OSLibDosGetNamedSharedMem FAILED"));
719 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
720 errorState = 1;
721 return;
722 }
723 pShareViewAddr = viewaddr;
724 }
725
726 //view == memory mapping for executable images (only used internally)
727 if(map->getImage()) {
728 pMapView = map->getMappingAddr();
729 }
730 else {
731 if(OSLibDosAliasMem(viewaddr, size, &pMapView, accessAttr) != OSLIB_NOERROR) {
732 dprintf(("new OSLibDosAliasMem FAILED"));
733 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
734 errorState = 1;
735 return;
736 }
737 }
738 dprintf(("Win32MemMapView::Win32MemMapView: created %x (alias for %x), size %d", pMapView, viewaddr, size));
739
740 DosEnterCriticalSection(&globalmapcritsect);
741 if(tmpview == NULL || tmpview->getViewAddr() > pMapView) {
742 next = mapviews;
743 mapviews = this;
744 }
745 else {
746 while(tmpview->next) {
747 if(tmpview->next->getViewAddr() > pMapView) {
748 break;
749 }
750 tmpview = tmpview->next;
751 }
752 next = tmpview->next;
753 tmpview->next = this;
754 }
755 DosLeaveCriticalSection(&globalmapcritsect);
756}
757//******************************************************************************
758//******************************************************************************
759Win32MemMapView::~Win32MemMapView()
760{
761 if(errorState != 0)
762 return;
763
764 dprintf(("Win32MemMapView dtor: deleting view %x %x", mOffset, mSize));
765
766 if(mfAccess & MEMMAP_ACCESS_WRITE)
767 mParentMap->flushView(mOffset, mSize);
768
769 //Don't free memory for executable image map views (only used internally)
770 if(!mParentMap->getImage())
771 OSLibDosFreeMem(pMapView);
772
773 if(pShareViewAddr) {
774 OSLibDosFreeMem(pShareViewAddr);
775 }
776
777 DosEnterCriticalSection(&globalmapcritsect);
778 Win32MemMapView *view = mapviews;
779
780 if(view == this) {
781 mapviews = next;
782 }
783 else {
784 while(view->next) {
785 if(view->next == this)
786 break;
787 view = view->next;
788 }
789 if(view->next) {
790 view->next = next;
791 }
792 else dprintf(("Win32MemMapView::~Win32MemMapView: map not found!! (%x)", this));
793 }
794 DosLeaveCriticalSection(&globalmapcritsect);
795}
796//******************************************************************************
797//******************************************************************************
798void Win32MemMapView::deleteViews(Win32MemMap *map)
799{
800 DosEnterCriticalSection(&globalmapcritsect);
801 Win32MemMapView *view = mapviews, *nextview;
802
803 if(view != NULL) {
804 while(view) {
805 nextview = view->next;
806 if(view->getParentMap() == map)
807 {
808 DosLeaveCriticalSection(&globalmapcritsect);
809 delete view;
810 DosEnterCriticalSection(&globalmapcritsect);
811 }
812 view = nextview;
813 }
814 }
815 DosLeaveCriticalSection(&globalmapcritsect);
816}
817//******************************************************************************
818//******************************************************************************
819// Win32MemMap::findMapByView
820//
821// Find the map of the view that contains the specified starting address
822// and has the specified access type
823//
824// Parameters:
825//
826// ULONG address - view address
827// ULONG *offset - address of ULONG that receives the offset
828// in the returned memory map
829// ULONG accessType - access type:
830// MEMMAP_ACCESS_READ
831// MEMMAP_ACCESS_WRITE
832// MEMMAP_ACCESS_EXECUTE
833//
834// Returns:
835// <> NULL - success, address of parent map object
836// NULL - failure
837//
838//******************************************************************************
839//******************************************************************************
840Win32MemMap *Win32MemMapView::findMapByView(ULONG address,
841 ULONG *offset,
842 ULONG accessType)
843{
844 Win32MemMap *map = NULL;
845 ULONG ulOffset;
846
847 if(mapviews == NULL) return NULL;
848
849 DosEnterCriticalSection(&globalmapcritsect);
850 Win32MemMapView *view = mapviews;
851 ULONG ulViewAddr;
852
853 if(!offset) offset = &ulOffset;
854
855 *offset = 0;
856
857 if(view != NULL)
858 {
859 do
860 {
861 ulViewAddr = (ULONG)view->getViewAddr();
862
863 // if ulViewAddr is > address, we've exhausted
864 // the sorted list already and can abort search.
865 if(ulViewAddr <= address)
866 {
867 if(ulViewAddr + view->getSize() > address &&
868 view->getAccessFlags() >= accessType)
869 {
870 *offset = view->getOffset() + (address - ulViewAddr);
871 goto success;
872 }
873
874 // Not found yet, continue search with next map
875 view = view->next;
876 }
877 else
878 {
879 // list is exhausted, abort loop
880 view = NULL;
881 }
882 }
883 while(view);
884
885 //failure if we get here
886 view = NULL;
887 }
888success:
889#ifdef DEBUG
890 if(view && !view->getParentMap()->isImageMap())
891 dprintf(("findMapByView %x %x -> %x off %x",
892 address,
893 accessType,
894 view->getViewAddr(),
895 *offset));
896#endif
897
898 if(view) {
899 map = view->getParentMap();
900 if(map) map->AddRef();
901 }
902
903 DosLeaveCriticalSection(&globalmapcritsect);
904
905 return map;
906}
907//******************************************************************************
908// Win32MemMap::findView
909//
910// Find the view that contains the specified starting address
911//
912// Parameters:
913//
914// LPVOID address - view address
915//
916// Returns:
917// <> NULL - success, address view object
918// NULL - failure
919//
920//******************************************************************************
921Win32MemMapView *Win32MemMapView::findView(ULONG address)
922{
923 ULONG ulViewAddr;
924
925 DosEnterCriticalSection(&globalmapcritsect);
926 Win32MemMapView *view = mapviews;
927
928 if(view != NULL) {
929 while(view) {
930 ulViewAddr = (ULONG)view->getViewAddr();
931 if(ulViewAddr <= address && ulViewAddr + view->getSize() > address)
932 {
933 break;
934 }
935 view = view->next;
936 }
937 }
938 DosLeaveCriticalSection(&globalmapcritsect);
939 return view;
940}
941//******************************************************************************
942//******************************************************************************
Note: See TracBrowser for help on using the repository browser.