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

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

cleanup/resync

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