#define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #include "filewriter_mt.h" const int cStartBufSize = 64 * 1024; static int sActiveThreadCount = 0; static int sAllocatedSize = 0; static bool sAbortNow = false; DWORD WINAPI WriteThread(void* inInfo) { ++sActiveThreadCount; FileWriterMT* file_writer = (FileWriterMT*) inInfo; bool succes = false; HANDLE handle = file_writer->CreateFile(file_writer->IsWriteable(), false, file_writer->GetModTime()); if (handle != INVALID_HANDLE_VALUE) { file_writer->SetHandle(handle); succes = true; bool did_close = false; while ((!file_writer->IsClosed() || !file_writer->GetBuffers().empty()) && !sAbortNow) { std::list<FileWriterMT::BufInfo*>& buffers = file_writer->GetBuffers(); if (buffers.size() > 0 && buffers.front()->mFilled) { FileWriterMT::BufInfo* buf_info = buffers.front(); DWORD written; if (::WriteFile(handle, buf_info->mData, buf_info->mLength, &written, NULL) == 0 || written != buf_info->mLength) succes = false; if (FileWriter::GetWriteCallback()) FileWriter::GetWriteCallback()(written); ::VirtualFree(buf_info->mData, 0, MEM_RELEASE); sAllocatedSize -= buf_info->mSize; delete buf_info; ::EnterCriticalSection(file_writer->GetCriticalSection()); { buffers.pop_front(); } ::LeaveCriticalSection(file_writer->GetCriticalSection()); } ::Sleep(0); } file_writer->CloseFile(handle); if (sAbortNow) { // Aborted before file actions could be finished, so delete file_writer->DeleteFile(); } } file_writer->WriteCompleted(); --sActiveThreadCount; return succes; } FileWriterMT::BufInfo::BufInfo(int inMaxSize) : mData(NULL), mLength(0), mSize(cStartBufSize), mFilled(false) { mData = (unsigned char*) ::VirtualAlloc(NULL, inMaxSize, MEM_RESERVE, PAGE_READWRITE); ::VirtualAlloc(mData, mSize, MEM_COMMIT, PAGE_READWRITE); sAllocatedSize += mSize; } FileWriterMT* FileWriterMT::GetFileWriter(const std::string& inName, long long inFileSize) { return new FileWriterMT(inName, inFileSize); } void FileWriterMT::Finalize() { // Wait until all pending WriteThreads are done while (sActiveThreadCount > 0) Sleep(0); } FileWriterMT::FileWriterMT(const std::string& inName, long long inFileSize) : FileWriter(inName, inFileSize), mClosed(true), mWriteCompleted(false), mWriteable(false), mModTime(0), mHandle(INVALID_HANDLE_VALUE) { ::InitializeCriticalSection(&mCriticalSection); } FileWriterMT::~FileWriterMT() { // Wait until the WriteThread is done while (!mWriteCompleted) ::Sleep(0); ::DeleteCriticalSection(&mCriticalSection); } bool FileWriterMT::Open(bool inWriteable, int inModTime) { mWriteable = inWriteable; mModTime = inModTime; BufInfo* buf_info = new BufInfo(mMaxMemSize / 2); ::EnterCriticalSection(&mCriticalSection); { mBuffers.push_back(buf_info); } ::LeaveCriticalSection(&mCriticalSection); mClosed = false; ::CreateThread(NULL, 0, WriteThread, (void*) this, 0, NULL); return true; } bool FileWriterMT::Close() { if (mBuffers.size() > 0) mBuffers.back()->mFilled = true; mClosed = true; // VirtualFree ... return true; } void FileWriterMT::GetWriteBuffer(unsigned char*& outBuf, int& outLength) { BufInfo* buf_info = mBuffers.back(); outBuf = buf_info->mData + buf_info->mLength; outLength = buf_info->mSize - buf_info->mLength; } bool FileWriterMT::ReleaseWriteBuffer(int inRemainingLength) { BufInfo* buf_info = mBuffers.back(); buf_info->mLength = buf_info->mSize - inRemainingLength; // We need to have at least two bytes free, as we may need to do a line-end conversion if (buf_info->mLength >= buf_info->mSize - 1) { if (buf_info->mSize >= mMaxMemSize / 2) { while (sAllocatedSize > mMaxMemSize / 2) Sleep(0); ::EnterCriticalSection(&mCriticalSection); { mBuffers.push_back(new BufInfo(mMaxMemSize / 2)); } ::LeaveCriticalSection(&mCriticalSection); buf_info->mFilled = true; } else { buf_info->mSize *= 2; ::VirtualAlloc(buf_info->mData, buf_info->mSize, MEM_COMMIT, PAGE_READWRITE); sAllocatedSize += buf_info->mSize / 2; } } return true; } void FileWriterMT::Finish() { // Wait until the WriteThread is done while (!mWriteCompleted) ::Sleep(0); } void FileWriterMT::HandleAbort() { // Signal abort so the WriteThread will now to clean up once it's done with it's current write request sAbortNow = true; } bool FileWriterMT::ChModTime(int inModTime) { if (mHandle != INVALID_HANDLE_VALUE) return FileWriter::ChModTime(mHandle, inModTime); return false; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 6420 | Frank Compagner |
A number of improvements: - p4fs now supports the global -s (scripted output) option. - p4fs and P4fsV now support the modtime client option. - P4CHARSET is now correctly handled (though no full Unicode support yet). - Increased the maximum command line length for p4fs to the Windows maximum 32768. - Improved error handling. - Fixed a crash when cancelling a sync using the async or multithreaded writers. - P4fsV progressbar now behaves well when passing more than one filespec - P4fsV will now offer the option to overwrite any locally changed (but not checked out) files when it finds these during a sync (cannot clobber ...). - Made the P4fsV error dialog resizeable. - P4fsV Windows layout fixed so it works properly with all Windows style setings. - Ooh, and prettier icons too. |
||
#2 | 6280 | Frank Compagner | Added support for +w filetype | ||
#1 | 6187 | Frank Compagner | Added p4fs project |