Commit e3144513cacff511fe7c9374ae4daabe4728b7b3

  • avatar
  • Petr Ovtchenkov (Committer)
  • Thu Jan 28 09:21:05 CET 2010
  • avatar
  • Max Motovilov <maxmotovilov @us…s.sourceforge.net> (Author)
  • Thu Jan 28 09:21:05 CET 2010
Workaround for Windows CE seek issue on a memory-mapped file

Platform: Windows CE 5 (Windows Mobile 5.x & 6.x)
Compiler: Visual Studio 2008; the issue is not compiler-related

Problem: on files larger than 4K opened in binary mode, ifstream::tellg()
does not return correct values. Short snippet demonstrates the issue:
=================================
std::ifstream in( filename, std::ios_base::in | std::ios_base::binary );
in.get();
std::streampos pos = in.tellg();
assert( pos == 1 );
=================================

Underlying problem: the sequence

  - create mapping
  - SetFilePosition( file, pos /* == file size */, FILE_BEGIN )
  - first access to mapped page
  - SetFilePosition( file, 0, FILE_CURRENT )

does not work as expected: last SetFilePosition() returns 4096 instead of
file size. If the first access to mapped page happens before the call to
SetFilePosition() that sets file pointer to EOF, everything works fine.

Workaround: in fstream_win32io.cpp, method
_Filebuf_base::_M_mmap() explicitly accesses the first page of the
mapping before calling _M_seek(). Note that with full & global
optimizations enabled, the optimizer is very aggressive and tends to cut
away expressions producing unused values (hence the assignment to a static
variable).

Issue discovered on Windows Mobile 6 (emulator) and later had it
reproduced on Windows Mobile 5.x on PPC-type hardware.

From the look of things it ought to be a problem in Windows CE 5 core
implementation. It's no idea if this is new for CE 5 or was
there before or whether M$ came around to fixing it in CE 6.

Patch tracker ID: 2941143
  
575575 return result;
576576}
577577
578#ifdef _STLP_WCE
579inline void access_page_aux( void* p )
580{ static char c = *static_cast<const char*>( p ); }
581#endif
578582
579583// Attempts to memory-map len bytes of the current file, starting
580584// at position offset. Precondition: offset is a multiple of the
609609 __STATIC_CAST(DWORD, len));
610610#endif
611611 // check if mapping succeded and is usable
612 if (base == 0 || _M_seek(offset + len, ios_base::beg) < 0) {
612#ifdef _STLP_WCE
613 /* Workaround for Windows CE 5 (Windows Mobile 5.x & 6.x):
614 SetFilePosition() returns wrong number before first read;
615 access_page_aux try to read. See patch tracker ID 2941143.
616 */
617 if ( base == 0 || (access_page_aux(base), _M_seek(offset + len, ios_base::beg)) < 0 )
618#else
619 if ( base == 0 || _M_seek(offset + len, ios_base::beg) < 0 )
620#endif
621 {
613622 this->_M_unmap(base, len);
614623 base = 0;
615624 }