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

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

updates

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