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

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

VirtualQuery implemented + preliminary memory mapped code

File size: 7.7 KB
Line 
1/* $Id: mmap.cpp,v 1.7 1999-08-24 12:23:54 sandervl Exp $ */
2
3/*
4 * Win32 Memory mapped file class
5 *
6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * NOTE: Memory mapping DOES NOT work when kernel-mode code causes
9 * a pagefault in the memory mapped object. (exceptions aren't
10 * dispatched to our exception handler until after the kernel mode
11 * call returns (too late))
12 *
13 * NOTE: There's no easy way to determine which pages were modified. Temporary
14 * solution is to write all paged-in memory to disk.
15 *
16 * NOTE: Are apps allowed to change the protection flags of memory mapped pages?
17 * I'm assuming they aren't for now.
18 *
19 * TODO: Handles returned should be usable by all apis that accept file handles
20 *
21 * Project Odin Software License can be found in LICENSE.TXT
22 *
23 */
24#include <os2win.h>
25#include <stdlib.h>
26#include <string.h>
27#include <win\virtual.h>
28#include <vmutex.h>
29#include <handlemanager.h>
30#include "mmap.h"
31
32VMutex globalmapMutex;
33
34//******************************************************************************
35//TODO: sharing between processes
36//******************************************************************************
37Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
38 : fMapped(FALSE), pMapping(NULL), mMapAccess(0)
39{
40 globalmapMutex.enter();
41 memmaps = this;
42 next = memmaps;
43 globalmapMutex.leave();
44
45 hMemFile = hfile;
46
47 mSize = size;
48 mProtFlags = fdwProtect;
49
50 if(lpszName) {
51 lpszMapName = (char *)malloc(strlen(lpszName)+1);
52 strcpy(lpszMapName, lpszName);
53 }
54 else lpszMapName = NULL;
55}
56//******************************************************************************
57//******************************************************************************
58HANDLE Win32MemMap::Init()
59{
60 mapMutex.enter();
61 if(hMemFile != -1)
62 {
63 if(DuplicateHandle(GetCurrentProcess(), hMemFile, GetCurrentProcess(),
64 &hMemFile, 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE)
65 {
66 dprintf(("Win32MemMap::Init: DuplicateHandle failed!"));
67 goto fail;
68 }
69 }
70 if(HMHandleAllocate(&hMemMap, (ULONG)this) != 0)
71 {
72 dprintf(("Win32MemMap::Init HMHandleAllocate failed!!"));
73 DebugInt3();
74 goto fail;
75 }
76 mapMutex.leave();
77 return hMemMap;
78fail:
79 mapMutex.leave();
80 return 0;
81}
82//******************************************************************************
83//******************************************************************************
84Win32MemMap::~Win32MemMap()
85{
86 unmapFileView();
87 if(lpszMapName) {
88 free(lpszMapName);
89 }
90 mapMutex.enter();
91 if(pMapping) {
92 VirtualFree(pMapping, mSize, MEM_RELEASE);
93 pMapping = NULL;
94 }
95 if(hMemFile != -1) {
96 CloseHandle(hMemFile);
97 hMemFile = -1;
98 }
99 mapMutex.leave();
100
101 globalmapMutex.enter();
102 Win32MemMap *map = memmaps;
103
104 if(map == this) {
105 memmaps = next;
106 }
107 else {
108 while(map->next) {
109 if(map->next == this)
110 break;
111 map = map->next;
112 }
113 if(map->next) {
114 map->next = next;
115 }
116 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
117 }
118 globalmapMutex.leave();
119}
120//******************************************************************************
121//******************************************************************************
122BOOL Win32MemMap::unmapFileView()
123{
124 if(fMapped == FALSE)
125 return FALSE;
126
127 flushView(pMapping, mSize);
128 mapMutex.enter();
129 if(pMapping) {
130 VirtualFree(pMapping, mSize, MEM_RELEASE);
131 }
132 pMapping = NULL;
133 fMapped = FALSE;
134 mapMutex.leave();
135 return TRUE;
136}
137//******************************************************************************
138//******************************************************************************
139LPVOID Win32MemMap::mapFileView(ULONG size, ULONG offset, ULONG fdwAccess)
140{
141 mapMutex.enter();
142 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
143 ULONG fAlloc = 0;
144
145 if(fdwAccess & FILE_MAP_WRITE && mProtFlags & (PAGE_READONLY|PAGE_WRITECOPY))
146 goto parmfail;
147 if(fdwAccess & FILE_MAP_READ && mProtFlags & PAGE_WRITECOPY)
148 goto parmfail;
149 if(fdwAccess & FILE_MAP_ALL_ACCESS && mProtFlags & (PAGE_READONLY|PAGE_WRITECOPY))
150 goto parmfail;
151 if(fdwAccess & FILE_MAP_COPY && mProtFlags & PAGE_WRITECOPY)
152 goto parmfail;
153
154 if(mProtFlags & SEC_COMMIT)
155 fAlloc |= MEM_COMMIT;
156 if(mProtFlags & SEC_RESERVE)
157 fAlloc |= MEM_RESERVE;
158
159 pMapping = VirtualAlloc(0, mSize, fAlloc, memFlags);
160 if(pMapping == NULL) {
161 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
162 goto fail;
163 }
164 mapMutex.leave();
165 return pMapping;
166
167parmfail:
168 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
169 SetLastError(ERROR_INVALID_PARAMETER);
170fail:
171 mapMutex.leave();
172 return 0;
173}
174//******************************************************************************
175// NOTE: There's no easy way to determine which pages were modified. Temporary
176// solution is to write all paged-in memory to disk.
177//TODO: Are apps allowed to change the protection flags of memory mapped pages?
178// I'm assuming they aren't for now.
179//******************************************************************************
180BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
181{
182 MEMORY_BASIC_INFORMATION memInfo;
183 ULONG nrpages, nrBytesWritten;
184 int i;
185
186 mapMutex.enter();
187 if(fMapped == FALSE)
188 goto parmfail;
189
190 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
191 goto parmfail;
192
193 if(mProtFlags & PAGE_READONLY)
194 goto parmfail;
195
196 nrpages = cbFlush/PAGE_SIZE;
197 if(cbFlush & 0xFFF) nrpages++;
198
199 for(i=0;i<nrpages;i++) {
200 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
201 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
202 goto fail;
203 }
204 //If a page is reserved or write protected, we won't bother flushing it to disk
205 if(memInfo.State & MEM_COMMIT &&
206 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
207 {//committed and allowed for writing?
208 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, PAGE_SIZE, &nrBytesWritten, NULL) == FALSE) {
209 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
210 goto fail;
211 }
212 if(nrBytesWritten != PAGE_SIZE) {
213 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
214 goto fail;
215 }
216 }
217 }
218 mapMutex.leave();
219 return TRUE;
220parmfail:
221 SetLastError(ERROR_INVALID_PARAMETER);
222 mapMutex.leave();
223 return FALSE;
224fail:
225 mapMutex.leave();
226 return FALSE;
227}
228//******************************************************************************
229//******************************************************************************
230Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
231{
232 globalmapMutex.enter();
233 Win32MemMap *map = memmaps;
234
235 if(map != NULL) {
236 while(map) {
237 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
238 break;
239 map = map->next;
240 }
241 }
242 globalmapMutex.leave();
243 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
244 return map;
245}
246//******************************************************************************
247//******************************************************************************
248Win32MemMap *Win32MemMap::findMap(ULONG address)
249{
250 globalmapMutex.enter();
251 Win32MemMap *map = memmaps;
252
253 if(map != NULL) {
254 while(map) {
255 if(map->pMapping && (ULONG)map->pMapping <= address &&
256 (ULONG)map->pMapping + map->mSize > address)
257 {
258 break;
259 }
260 map = map->next;
261 }
262 }
263 globalmapMutex.leave();
264 return map;
265}
266//******************************************************************************
267//******************************************************************************
268Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.