Changeset 712 for trunk/src/kernel32/mmap.cpp
- Timestamp:
- Aug 27, 1999, 6:51:01 PM (26 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kernel32/mmap.cpp
r708 r712 1 /* $Id: mmap.cpp,v 1.1 6 1999-08-26 17:56:25sandervl Exp $ */1 /* $Id: mmap.cpp,v 1.17 1999-08-27 16:51:00 sandervl Exp $ */ 2 2 3 3 /* 4 * Win32 Memory mapped file class4 * Win32 Memory mapped file & view classes 5 5 * 6 6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl) … … 28 28 #include <handlemanager.h> 29 29 #include "mmap.h" 30 #include "oslibdos.h" 30 31 31 32 VMutex globalmapMutex; 33 VMutex globalviewMutex; 32 34 33 35 //****************************************************************************** … … 35 37 //****************************************************************************** 36 38 Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName) 37 : fMapped(FALSE), pMapping(NULL), mMapAccess(0), referenced(0)39 : nrMappings(0), pMapping(NULL), mMapAccess(0), referenced(0) 38 40 { 39 41 globalmapMutex.enter(); … … 72 74 } 73 75 } 76 77 dprintf(("CreateFileMappingA for file %x, prot %x size %d, name %s", hMemFile, mProtFlags, mSize, lpszMapName)); 74 78 this->hMemMap = hMemMap; 75 79 mapMutex.leave(); … … 83 87 Win32MemMap::~Win32MemMap() 84 88 { 85 unmapViewOfFile(); 89 for(int i=0;i<nrMappings;i++) { 90 Win32MemMapView::deleteView(this); //delete all views of our memory mapped file 91 } 92 mapMutex.enter(); 86 93 if(lpszMapName) { 87 94 free(lpszMapName); 88 95 } 89 mapMutex.enter();90 96 if(pMapping) { 91 97 VirtualFree(pMapping, mSize, MEM_RELEASE); … … 118 124 } 119 125 //****************************************************************************** 120 //******************************************************************************121 BOOL Win32MemMap::hasReadAccess()122 {123 return TRUE; //should have at least this124 }125 //******************************************************************************126 //******************************************************************************127 BOOL Win32MemMap::hasWriteAccess()128 {129 return !(mProtFlags & PAGE_READONLY);130 }131 //******************************************************************************132 //Might want to add this feature for memory mapping executable & dll files in133 //the loader (done in Win32 with the SEC_IMAGE flag?)134 //******************************************************************************135 BOOL Win32MemMap::hasExecuteAccess()136 {137 return FALSE;138 }139 //******************************************************************************140 126 //We determine whether a page has been modified by checking it's protection flags 141 127 //If the write flag is set, this means commitPage had to enable this due to a pagefault 142 128 //(all pages are readonly until the app tries to write to it) 143 129 //****************************************************************************** 144 BOOL Win32MemMap::commitPage( LPVOID lpPageFaultAddr, ULONG nrpages, BOOL fWriteAccess)130 BOOL Win32MemMap::commitPage(ULONG offset, BOOL fWriteAccess) 145 131 { 146 132 MEMORY_BASIC_INFORMATION memInfo; 147 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF; 148 DWORD oldProt, newProt, nrBytesRead, offset, size; 149 133 LPVOID lpPageFaultAddr = (LPVOID)((ULONG)pMapping + offset); 134 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF; 135 DWORD oldProt, newProt, nrBytesRead, size; 136 150 137 // mapMutex.enter(); 138 151 139 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY); 152 140 153 dprintf(("Win32MemMap::commitPage %x (faultaddr %x) , nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));141 dprintf(("Win32MemMap::commitPage %x (faultaddr %x)", pageAddr, lpPageFaultAddr)); 154 142 if(hMemFile != -1) { 155 if(VirtualQuery((LPSTR)pageAddr, &memInfo, nrpages*PAGE_SIZE) == 0) { 156 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE)); 157 goto fail; 158 } 143 if(VirtualQuery((LPSTR)pageAddr, &memInfo, NRPAGES_TOCOMMIT*PAGE_SIZE) == 0) { 144 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, NRPAGES_TOCOMMIT*PAGE_SIZE)); 145 goto fail; 146 } 147 //Only changes the state of the pages with the same attribute flags 148 //(returned in memInfo.RegionSize) 149 //If it's smaller than the mNrPages, it simply means one or more of the 150 //other pages have already been committed 159 151 if(memInfo.State & MEM_COMMIT) 160 152 {//if it's already committed, then the app tried to write to it 161 153 if(!fWriteAccess) { 162 dprintf(("Win32MemMap::commitPage: Huh? Already committed and not trying to write (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));163 goto fail; 164 } 165 if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {166 dprintf(("Win32MemMap::commitPage: Failed to set write flag on page (%x,%x) failed for %x", pageAddr, nrpages*PAGE_SIZE));154 dprintf(("Win32MemMap::commitPage: Huh? Already committed and not trying to write (%x,%x) failed for %x", pageAddr, memInfo.RegionSize)); 155 goto fail; 156 } 157 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) { 158 dprintf(("Win32MemMap::commitPage: Failed to set write flag on page (%x,%x) failed for %x", pageAddr, memInfo.RegionSize)); 167 159 goto fail; 168 160 } 169 161 } 170 162 else { 171 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE) == FALSE) {163 if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE) == FALSE) { 172 164 goto fail; 173 165 } 174 166 offset = pageAddr - (ULONG)pMapping; 175 size = nrpages*PAGE_SIZE;167 size = memInfo.RegionSize; 176 168 if(offset + size > mSize) { 169 dprintf(("Adjusting size from %d to %d", size, mSize - offset)); 177 170 size = mSize - offset; 178 171 } … … 190 183 } 191 184 if(mProtFlags & PAGE_READONLY) { 192 if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {185 if(VirtualProtect((LPVOID)pageAddr, memInfo.RegionSize, newProt, &oldProt) == FALSE) { 193 186 goto fail; 194 187 } … … 197 190 } 198 191 else { 199 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, newProt) == FALSE) { 192 if(VirtualQuery((LPSTR)pageAddr, &memInfo, NRPAGES_TOCOMMIT*PAGE_SIZE) == 0) { 193 dprintf(("Win32MemMap::commitPage: VirtualQuery (%x,%x) failed for %x", pageAddr, NRPAGES_TOCOMMIT*PAGE_SIZE)); 194 goto fail; 195 } 196 if(VirtualAlloc((LPVOID)pageAddr, memInfo.RegionSize, MEM_COMMIT, newProt) == FALSE) { 200 197 goto fail; 201 198 } … … 209 206 } 210 207 //****************************************************************************** 211 //****************************************************************************** 212 BOOL Win32MemMap::unmapViewOfFile() 213 { 214 if(fMapped == FALSE) 215 return FALSE; 216 217 flushView(pMapping, mSize); 208 //todo: unalias memory 209 //****************************************************************************** 210 BOOL Win32MemMap::unmapViewOfFile(Win32MemMapView *view) 211 { 218 212 mapMutex.enter(); 219 if(pMapping) { 213 214 if(nrMappings == 0) 215 goto fail; 216 217 delete view; 218 219 if(--nrMappings) { 220 220 VirtualFree(pMapping, mSize, MEM_RELEASE); 221 } 222 pMapping = NULL; 223 fMapped = FALSE; 221 pMapping = NULL; 222 } 224 223 mapMutex.leave(); 225 224 return TRUE; 225 fail: 226 mapMutex.leave(); 227 return FALSE; 226 228 } 227 229 //****************************************************************************** … … 232 234 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY)); 233 235 ULONG fAlloc = 0; 234 LPVOID mapview; 235 236 Win32MemMapView *mapview; 237 238 if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY)) 239 goto parmfail; 236 240 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE)) 237 241 goto parmfail; … … 240 244 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY)) 241 245 goto parmfail; 246 if(offset+size > mSize) 247 goto parmfail; 242 248 243 249 //TODO: If committed, read file into memory 244 #if 0 250 #if 0 245 251 if(mProtFlags & SEC_COMMIT) 246 252 fAlloc |= MEM_COMMIT; … … 252 258 #endif 253 259 254 if( fMapped == FALSE) {//if not mapped, reserve/commit entire view260 if(nrMappings == 0) {//if not mapped, reserve/commit entire view 255 261 //SvL: Always read/write access or else ReadFile will crash once we 256 // start decommitting pages.262 // start committing pages. 257 263 // This is most likely an OS/2 bug and doesn't happen in Aurora 258 264 // when allocating memory with the PAG_ANY bit set. (without this … … 263 269 goto fail; 264 270 } 265 fMapped = TRUE; 266 } 267 mapview = (LPVOID)((ULONG)pMapping + offset); 268 mapMutex.leave(); 269 return mapview; 271 } 272 mapview = new Win32MemMapView(this, offset, (size == 0) ? mSize : size, fdwAccess); 273 if(mapview == NULL) { 274 goto fail; 275 } 276 if(mapview->everythingOk() == FALSE) { 277 delete mapview; 278 goto fail; 279 } 280 nrMappings++; 281 mapMutex.leave(); 282 return mapview->getViewAddr(); 270 283 271 284 parmfail: … … 279 292 //We determine whether a page has been modified by checking it's protection flags 280 293 //If the write flag is set, this means commitPage had to enable this due to a pagefault 281 //(all pages are readonly until the app tries to modify it)294 //(all pages are readonly until the app tries to modify the contents of the page) 282 295 // 283 296 //TODO: Are apps allowed to change the protection flags of memory mapped pages? 284 297 // I'm assuming they aren't for now. 285 298 //****************************************************************************** 286 BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush) 287 { 299 BOOL Win32MemMap::flushView(ULONG offset, ULONG cbFlush) 300 { 301 LPVOID lpvBase = (LPVOID)((ULONG)pMapping+offset); 288 302 MEMORY_BASIC_INFORMATION memInfo; 289 ULONG nr pages, nrBytesWritten, offset, size;303 ULONG nrBytesWritten, size; 290 304 int i; 291 305 292 // mapMutex.enter();293 306 dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush)); 294 if( fMapped == FALSE)307 if(nrMappings == 0) 295 308 goto parmfail; 296 309 … … 307 320 goto success; //TODO: Return an error here? 308 321 309 nrpages = cbFlush/PAGE_SIZE; 310 if(cbFlush & 0xFFF) nrpages++; 311 312 for(i=0;i<nrpages;i++) { 313 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) { 322 while(cbFlush) { 323 if(VirtualQuery((LPSTR)lpvBase, &memInfo, cbFlush) == 0) { 314 324 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE)); 315 325 goto fail; 316 326 } 317 //If a page is reserved or write protected, we won't bother flushing it to disk 327 //If a page (or range of pages) is reserved or write protected, we 328 //won't bother flushing it to disk 318 329 if(memInfo.State & MEM_COMMIT && 319 330 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY)) 320 331 {//committed and allowed for writing? 321 offset = (ULONG)lpvBase +i*PAGE_SIZE- (ULONG)pMapping;322 size = PAGE_SIZE;323 if( offset + size > mSize) {324 size = mSize - offset;332 offset = (ULONG)lpvBase - (ULONG)pMapping; 333 size = memInfo.RegionSize; 334 if(size > cbFlush) { 335 size = cbFlush; 325 336 } 326 337 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size)); … … 330 341 goto fail; 331 342 } 332 if(WriteFile(hMemFile, (LPSTR)lpvBase +i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {333 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase +i*PAGE_SIZE));343 if(WriteFile(hMemFile, (LPSTR)lpvBase, size, &nrBytesWritten, NULL) == FALSE) { 344 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase)); 334 345 goto fail; 335 346 } 336 347 if(nrBytesWritten != size) { 337 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE)); 338 goto fail; 339 } 340 } 348 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase)); 349 goto fail; 350 } 351 } 352 lpvBase = (LPVOID)((ULONG)lpvBase + memInfo.RegionSize); 353 354 if(cbFlush < memInfo.RegionSize) 355 break; 356 357 cbFlush -= memInfo.RegionSize; 341 358 } 342 359 success: 343 // mapMutex.leave();344 360 return TRUE; 345 361 parmfail: 346 362 SetLastError(ERROR_INVALID_PARAMETER); 347 // mapMutex.leave();348 363 return FALSE; 349 364 fail: 350 // mapMutex.leave();351 365 return FALSE; 352 366 } … … 390 404 } 391 405 //****************************************************************************** 406 //Assumes mutex has been acquired 392 407 //****************************************************************************** 393 408 void Win32MemMap::deleteAll() … … 400 415 //****************************************************************************** 401 416 Win32MemMap *Win32MemMap::memmaps = NULL; 417 418 //****************************************************************************** 419 //****************************************************************************** 420 Win32MemMapView::Win32MemMapView(Win32MemMap *map, ULONG offset, ULONG size, 421 ULONG fdwAccess) 422 { 423 LPVOID viewaddr = (LPVOID)((ULONG)map->getMappingAddr()+offset); 424 ULONG accessAttr = 0; 425 Win32MemMapView *tmpview = mapviews; 426 427 errorState = 0; 428 mParentMap = map; 429 mSize = size; 430 mOffset = offset; 431 432 switch(fdwAccess) { 433 case FILE_MAP_READ: 434 accessAttr = PAG_READ; 435 mfAccess = MEMMAP_ACCESS_READ; 436 break; 437 case FILE_MAP_WRITE: 438 case FILE_MAP_COPY: 439 accessAttr = (PAG_READ|PAG_WRITE); 440 mfAccess = MEMMAP_ACCESS_WRITE; 441 break; 442 } 443 if(OSLibDosAliasMem(viewaddr, size, &pMapView, accessAttr) != OSLIB_NOERROR) { 444 dprintf(("new OSLibDosAliasMem FAILED")); 445 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 446 errorState = 1; 447 return; 448 } 449 450 dprintf(("Win32MemMapView::Win32MemMapView: created %x (alias for %x), size %d", pMapView, viewaddr, size)); 451 452 globalviewMutex.enter(); 453 if(tmpview == NULL || tmpview->getViewAddr() > pMapView) { 454 next = mapviews; 455 mapviews = this; 456 } 457 else { 458 while(tmpview->next) { 459 if(tmpview->next->getViewAddr() > pMapView) { 460 break; 461 } 462 tmpview = tmpview->next; 463 } 464 next = tmpview->next; 465 tmpview->next = this; 466 } 467 globalviewMutex.leave(); 468 } 469 //****************************************************************************** 470 //****************************************************************************** 471 Win32MemMapView::~Win32MemMapView() 472 { 473 if(errorState != 0) 474 return; 475 476 if(mfAccess != MEMMAP_ACCESS_READ) 477 mParentMap->flushView(mOffset, mSize); 478 479 OSLibDosFreeMem(pMapView); 480 481 globalviewMutex.enter(); 482 Win32MemMapView *view = mapviews; 483 484 if(view == this) { 485 mapviews = next; 486 } 487 else { 488 while(view->next) { 489 if(view->next == this) 490 break; 491 view = view->next; 492 } 493 if(view->next) { 494 view->next = next; 495 } 496 else dprintf(("Win32MemMapView::~Win32MemMapView: map not found!! (%x)", this)); 497 } 498 globalviewMutex.leave(); 499 } 500 //****************************************************************************** 501 //****************************************************************************** 502 void Win32MemMapView::deleteView(Win32MemMap *map) 503 { 504 globalviewMutex.enter(); 505 Win32MemMapView *view = mapviews; 506 507 if(view != NULL) { 508 while(view) { 509 if(view->getParentMap() == map) 510 { 511 globalviewMutex.leave(); 512 delete view; 513 return; 514 } 515 view = view->next; 516 } 517 } 518 globalviewMutex.leave(); 519 } 520 //****************************************************************************** 521 //****************************************************************************** 522 Win32MemMap *Win32MemMapView::findMapByView(ULONG address, ULONG *offset, 523 ULONG accessType, 524 Win32MemMapView **pView) 525 { 526 globalviewMutex.enter(); 527 Win32MemMapView *view = mapviews; 528 529 *offset = 0; 530 531 if(view != NULL) { 532 while(view && (ULONG)view->getViewAddr() <= address) { 533 if((ULONG)view->getViewAddr() <= address && 534 (ULONG)view->getViewAddr() + view->getSize() >= address && 535 view->getAccessFlags() >= accessType) 536 { 537 *offset = view->getOffset() + (address - (ULONG)view->getViewAddr()); 538 goto success; 539 } 540 view = view->next; 541 } 542 //failure if we get here 543 view = NULL; 544 } 545 success: 546 globalviewMutex.leave(); 547 if(pView) *pView = view; 548 return (view) ? view->getParentMap() : NULL; 549 } 550 //****************************************************************************** 551 //****************************************************************************** 552 Win32MemMapView *Win32MemMapView::findView(LPVOID address) 553 { 554 Win32MemMapView *view = mapviews; 555 556 if(view != NULL) { 557 while(view) { 558 if(view->getViewAddr() == address) 559 { 560 break; 561 } 562 view = view->next; 563 } 564 } 565 return view; 566 } 567 //****************************************************************************** 568 //****************************************************************************** 569 Win32MemMapView *Win32MemMapView::mapviews = NULL; 570
Note:
See TracChangeset
for help on using the changeset viewer.