diff --git a/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt b/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt index 7e99acda..64c76ba0 100644 --- a/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt +++ b/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt @@ -18,7 +18,7 @@ set(plClientPatcher_SOURCES ) add_library(plClientPatcher STATIC ${plClientPatcher_HEADERS} ${plClientPatcher_SOURCES}) -target_link_libraries(plClientPatcher CoreLib plAudioCore) +target_link_libraries(plClientPatcher CoreLib plAudioCore plStatusLog) source_group("Header Files" FILES ${plClientPatcher_HEADERS}) source_group("Source Files" FILES ${plClientPatcher_SOURCES}) diff --git a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp b/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp index add04291..c805a0cc 100644 --- a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp +++ b/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp @@ -46,6 +46,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com ***/ #include "Pch.h" +#include "plStatusLog/plStatusLog.h" #pragma hdrstop @@ -215,11 +216,6 @@ static wchar_t s_clientExeName[] = L"plClient.exe"; * ***/ -//============================================================================ -static void LogHandler (ELogSeverity severity, const wchar_t msg[]) { - AsyncLogWriteMsg(L"UruPlayer", severity, msg); -} - //============================================================================ static void NetErrorHandler (ENetProtocol protocol, ENetError error) { @@ -247,7 +243,8 @@ static void NetErrorHandler (ENetProtocol protocol, ENetError error) { break; } - LogMsg(kLogError, L"NetErr: %s: %s", srv, NetErrorToString(error)); + plString msg = plString::Format("NetErr: %S: %S", srv, NetErrorToString(error)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); // Notify GameTap something bad happened. if (!s_patchError) { @@ -831,7 +828,9 @@ static void FileSrvIpAddressCallback ( NetCliGateKeeperDisconnect(); if (IS_NET_ERROR(result)) { - LogMsg(kLogDebug, L"FileSrvIpAddressRequest failed: %s", NetErrorToString(result)); + plString msg = plString::Format("FileSrvIpAddressRequest failed: %S", NetErrorToString(result)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); + s_patchError = true; return; } @@ -862,13 +861,14 @@ static void FileSrvIpAddressCallback ( void InitAsyncCore () { if(AtomicAdd(&s_asyncCoreInitCount, 1) > 0) return; - LogRegisterHandler(LogHandler); AsyncCoreInitialize(); - AsyncLogInitialize(L"Log", false); - + wchar_t productString[256]; ProductString(productString, arrsize(productString)); - LogMsg(kLogPerf, L"Patcher: %s", productString); + + char* log = hsWStringToString(productString); + plStatusLog::AddLineS("patcher.log", log); + delete[] log; } //============================================================================ @@ -880,9 +880,7 @@ void ShutdownAsyncCore () { while (s_perf[kPerfThreadTaskCount]) AsyncSleep(10); - AsyncLogDestroy(); AsyncCoreDestroy(30 * 1000); - LogUnregisterHandler(LogHandler); } //============================================================================ diff --git a/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt b/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt index 404b0a31..758f828b 100644 --- a/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt +++ b/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt @@ -43,6 +43,7 @@ target_link_libraries(plUruLauncher plNetClientComm) target_link_libraries(plUruLauncher plNetGameLib) target_link_libraries(plUruLauncher plNetMessage) target_link_libraries(plUruLauncher plNetTransport) +target_link_libraries(plUruLauncher plStatusLog) target_link_libraries(plUruLauncher plUnifiedTime) target_link_libraries(plUruLauncher pnAsyncCore) target_link_libraries(plUruLauncher pnAsyncCoreExe) diff --git a/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp b/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp index 2f39689e..0bbda6d2 100644 --- a/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp +++ b/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp @@ -46,6 +46,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com ***/ #include "Pch.h" +#include "plStatusLog/plStatusLog.h" #pragma hdrstop @@ -87,7 +88,9 @@ static wchar_t s_newPatcherFile[MAX_PATH]; //============================================================================ static void NetErrorHandler (ENetProtocol protocol, ENetError error) { - LogMsg(kLogError, L"NetErr: %s", NetErrorToString(error)); + plString msg = plString::Format("NetErr: %S", NetErrorToString(error)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); + if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = error; s_downloadComplete = true; @@ -116,7 +119,9 @@ static void DownloadCallback ( break; default: - LogMsg(kLogError, L"Error getting patcher file: %s", NetErrorToString(result)); + plString msg = plString::Format("Error getting patcher file: %S", NetErrorToString(result)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); + if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = result; break; @@ -161,7 +166,9 @@ static void ManifestCallback ( break; default: - LogMsg(kLogError, L"Error getting patcher manifest: %s", NetErrorToString(result)); + plString msg = plString::Format("Error getting patcher manifest: %S", NetErrorToString(result)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); + if (IS_NET_SUCCESS(s_patchResult)) s_patchResult = result; break; @@ -211,7 +218,9 @@ static void FileSrvIpAddressCallback ( NetCliGateKeeperDisconnect(); if (IS_NET_ERROR(result)) { - LogMsg(kLogDebug, L"FileSrvIpAddressRequest failed: %s", NetErrorToString(result)); + plString msg = plString::Format("FileSrvIpAddressRequest failed: %S", NetErrorToString(result)); + plStatusLog::AddLineS("patcher.log", msg.c_str()); + s_patchResult = result; s_downloadComplete = true; } diff --git a/Sources/Plasma/CoreLib/hsThread.h b/Sources/Plasma/CoreLib/hsThread.h index 02f36a6a..dc8418b7 100644 --- a/Sources/Plasma/CoreLib/hsThread.h +++ b/Sources/Plasma/CoreLib/hsThread.h @@ -102,10 +102,6 @@ public: static void* Alloc(size_t size); // does not call operator::new(), may return nil static void Free(void* p); // does not call operator::delete() static void ThreadYield(); - -#if HS_BUILD_FOR_WIN32 - DWORD WinRun(); -#endif }; ////////////////////////////////////////////////////////////////////////////// @@ -149,7 +145,8 @@ class hsSemaphore { HANDLE fSemaH; #elif HS_BUILD_FOR_UNIX #ifdef USE_SEMA - sem_t fPSema; + sem_t* fPSema; + bool fNamed; #else pthread_mutex_t fPMutex; pthread_cond_t fPCond; @@ -157,13 +154,9 @@ class hsSemaphore { #endif #endif public: -#ifdef HS_BUILD_FOR_WIN32 - hsSemaphore(int initialValue=0, const char *name=nil); -#else - hsSemaphore(int initialValue=0); -#endif + hsSemaphore(int initialValue=0, const char* name=nil); ~hsSemaphore(); - + hsBool Wait(hsMilliseconds timeToWait = kPosInfinity32); void Signal(); }; diff --git a/Sources/Plasma/CoreLib/hsThread_Unix.cpp b/Sources/Plasma/CoreLib/hsThread_Unix.cpp index 8a25586b..109492a3 100644 --- a/Sources/Plasma/CoreLib/hsThread_Unix.cpp +++ b/Sources/Plasma/CoreLib/hsThread_Unix.cpp @@ -42,6 +42,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsThread.h" #include "hsExceptions.h" #include +#include +#include #include #define NO_POSIX_CLOCK 1 @@ -72,7 +74,7 @@ extern "C" { static void* gEntryPoint(void* param) { pthread_mutex_lock(((hsThread*)param)->GetStartupMutex()); - void* ret = (void*)((hsThread*)param)->Run(); + void* ret = (void*)(uintptr_t)((hsThread*)param)->Run(); pthread_mutex_unlock(((hsThread*)param)->GetStartupMutex()); pthread_exit(ret); return ret; @@ -266,12 +268,24 @@ void hsMutex::Unlock() ///////////////////////////////////////////////////////////////////////////// -hsSemaphore::hsSemaphore(int initialValue) +hsSemaphore::hsSemaphore(int initialValue, const char* name) { #ifdef USE_SEMA - int shared = 0; // 1 if sharing between processes - int status = ::sem_init(&fPSema, shared, initialValue); - hsThrowIfOSErr(status); + fPSema = nil; + if ((fNamed = (name != nil))) { + /* Named semaphore shared between processes */ + fPSema = sem_open(name, O_CREAT, 0666, initialValue); + if (fPSema == SEM_FAILED) + { + hsAssert(0, "hsOSException"); + throw hsOSException(errno); + } + } else { + /* Anonymous semaphore shared between threads */ + int shared = 0; // 1 if sharing between processes + int status = sem_init(fPSema, shared, initialValue); + hsThrowIfOSErr(status); + } #else int status = ::pthread_mutex_init(&fPMutex, nil); hsThrowIfOSErr(status); @@ -286,7 +300,12 @@ hsSemaphore::hsSemaphore(int initialValue) hsSemaphore::~hsSemaphore() { #ifdef USE_SEMA - int status = ::sem_destroy(&fPSema); + int status = 0; + if (fNamed) { + status = sem_close(fPSema); + } else { + status = sem_destroy(fPSema); + } hsThrowIfOSErr(status); #else int status = ::pthread_cond_destroy(&fPCond); @@ -300,8 +319,9 @@ hsSemaphore::~hsSemaphore() hsBool hsSemaphore::Wait(hsMilliseconds timeToWait) { #ifdef USE_SEMA // SHOULDN'T THIS USE timeToWait??!?!? -rje + // shouldn't this use sem_timedwait? -dpogue (2012-03-04) hsAssert( timeToWait==kPosInfinity32, "sem_t does not support wait with timeout. #undef USE_SEMA and recompile." ); - int status = ::sem_wait(&fPSema); + int status = sem_wait(fPSema); hsThrowIfOSErr(status); return true; #else @@ -351,7 +371,7 @@ EXIT: void hsSemaphore::Signal() { #ifdef USE_SEMA - int status = ::sem_post(&fPSema); + int status = sem_post(fPSema); hsThrowIfOSErr(status); #else int status = ::pthread_mutex_lock(&fPMutex); diff --git a/Sources/Plasma/CoreLib/hsThread_Win.cpp b/Sources/Plasma/CoreLib/hsThread_Win.cpp index 53592484..2cde7e9e 100644 --- a/Sources/Plasma/CoreLib/hsThread_Win.cpp +++ b/Sources/Plasma/CoreLib/hsThread_Win.cpp @@ -46,16 +46,23 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsExceptions.h" #include "hsMemory.h" -// typedef unsigned int __stdcall (*EntryPtCB)(void*); - -static DWORD __stdcall gEntryPoint(void* param) +struct WinThreadParam { - return ((hsThread*)param)->WinRun(); -} + hsThread* fThread; + HANDLE fQuitSemaH; // private member of hsThread + + WinThreadParam(hsThread* t, HANDLE quit) + : fThread(t), fQuitSemaH(quit) + { } +}; static unsigned int __stdcall gEntryPointBT(void* param) { - return ((hsThread*)param)->WinRun(); + WinThreadParam* wtp = (WinThreadParam*)param; + unsigned int result = wtp->fThread->Run(); + ::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit + delete param; + return result; } hsThread::hsThread(uint32_t stackSize) : fStackSize(stackSize), fQuit(false), fThreadH(nil), fQuitSemaH(nil) @@ -74,12 +81,8 @@ void hsThread::Start() fQuitSemaH = ::CreateSemaphore(nil, 0, kPosInfinity32, nil); if (fQuitSemaH == nil) throw hsOSException(-1); - -#if 0 - fThreadH = ::CreateThread(nil, fStackSize, gEntryPoint, this, 0, &fThreadId); -#else - fThreadH = (HANDLE)_beginthreadex(nil, fStackSize, gEntryPointBT, this, 0, (unsigned int*)&fThreadId); -#endif + WinThreadParam* wtp = new WinThreadParam(this, fQuitSemaH); + fThreadH = (HANDLE)_beginthreadex(nil, fStackSize, gEntryPointBT, wtp, 0, (unsigned int*)&fThreadId); if (fThreadH == nil) throw hsOSException(-1); } @@ -100,15 +103,6 @@ void hsThread::Stop() } } -DWORD hsThread::WinRun() -{ - DWORD result = this->Run(); - - ::ReleaseSemaphore(fQuitSemaH, 1, nil); // signal that we've quit - - return result; -} - ///////////////////////////////////////////////////////////////////////////////////////// void* hsThread::Alloc(size_t size) diff --git a/Sources/Plasma/CoreLib/hsUtils.h b/Sources/Plasma/CoreLib/hsUtils.h index b213687b..54e952f5 100644 --- a/Sources/Plasma/CoreLib/hsUtils.h +++ b/Sources/Plasma/CoreLib/hsUtils.h @@ -165,7 +165,8 @@ inline hsBool hsCompare(float a, float b, float delta=0.0001); # define hsWFopen(name, mode) fopen(hsWStringToString(name), hsWStringToString(mode)) -# define MAX_PATH 1024 +# include +# define MAX_PATH PATH_MAX #endif // Useful floating point utilities diff --git a/Sources/Plasma/NucleusLib/pnAsyncCore/CMakeLists.txt b/Sources/Plasma/NucleusLib/pnAsyncCore/CMakeLists.txt index 829c4b5d..0bebee89 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCore/CMakeLists.txt +++ b/Sources/Plasma/NucleusLib/pnAsyncCore/CMakeLists.txt @@ -1,5 +1,6 @@ include_directories(../../CoreLib) include_directories(../../NucleusLib) +include_directories(../../PubUtilLib) set(pnAsyncCore_HEADERS Pch.h diff --git a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcIo.h b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcIo.h index 287e3a4b..e789cb41 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcIo.h +++ b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcIo.h @@ -64,174 +64,6 @@ typedef struct AsyncCancelIdStruct * AsyncCancelId; const unsigned kAsyncSocketBufferSize = 1460; -enum EFileError { - kFileSuccess, - kFileErrorInvalidParameter, - kFileErrorFileNotFound, - kFileErrorPathNotFound, - kFileErrorAccessDenied, - kFileErrorSharingViolation, - kNumFileErrors -}; - -EFileError AsyncGetLastFileError (); - -const wchar_t * FileErrorToString (EFileError error); - - -/**************************************************************************** -* -* File notifications -* -***/ - -enum EAsyncNotifyFile { - kNotifyFileFlush, - kNotifyFileRead, - kNotifyFileWrite, - kNotifyFileSequence, - kNumFileNotifications -}; - -struct AsyncNotifyFile { - void * param; - AsyncId asyncId; -}; - -struct AsyncNotifyFileConnect : AsyncNotifyFile { - uint64_t fileSize; - uint64_t fileLastWriteTime; -}; - -struct AsyncNotifyFileFlush : AsyncNotifyFile { - EFileError error; - uint64_t truncateSize; -}; - -struct AsyncNotifyFileRead : AsyncNotifyFile { - uint64_t offset; - uint8_t * buffer; - unsigned bytes; -}; - -typedef AsyncNotifyFileRead AsyncNotifyFileWrite; - -struct AsyncNotifyFileSequence : AsyncNotifyFile { - // no additional fields -}; - -typedef void (* FAsyncNotifyFileProc)( - AsyncFile file, - EAsyncNotifyFile code, - AsyncNotifyFile * notify, - void ** userState -); - - -/**************************************************************************** -* -* File I/O functions -* -***/ - -// Desired access -const unsigned kAsyncFileReadAccess = 0x80000000; -const unsigned kAsyncFileWriteAccess = 0x40000000; -// Open mode (creation disposition) -const unsigned kAsyncFileModeCreateNew = 1; -const unsigned kAsyncFileModeCreateAlways = 2; -const unsigned kAsyncFileModeOpenExisting = 3; -const unsigned kAsyncFileModeOpenAlways = 4; -// Share mode flags -const unsigned kAsyncFileShareRead = 0x00000001; -const unsigned kAsyncFileShareWrite = 0x00000002; - -AsyncFile AsyncFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, // optional - void * userState, // optional - uint64_t * fileSize, // optional - uint64_t * fileLastWriteTime // optional -); - -// Use with AsyncFileDelete/AsyncFileFlushBuffers -const uint64_t kAsyncFileDontTruncate = (uint64_t) -1; - -// This function may ONLY be called when there is no outstanding I/O against a file -// and no more I/O will be initiated against it. This function guarantees that it -// will close the system file handle before it returns to that another open against -// the same filename can succeed. -void AsyncFileClose ( - AsyncFile file, - uint64_t truncateSize -); - -void AsyncFileSetLastWriteTime ( - AsyncFile file, - uint64_t lastWriteTime -); - -uint64_t AsyncFileGetLastWriteTime ( - const wchar_t fileName[] -); - -// Truncation occurs atomically, any writes which occur after -// AsyncFileFlushBuffers will be queued until the truncation completes -AsyncId AsyncFileFlushBuffers ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -); - -const unsigned kAsyncFileRwNotify = 1<<0; -const unsigned kAsyncFileRwSync = 1<<1; - -AsyncId AsyncFileRead ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -); - -// Buffer must stay valid until I/O is completed -AsyncId AsyncFileWrite ( - AsyncFile file, - uint64_t offset, - const void * buffer, - unsigned bytes, - unsigned flags, - void * param -); - -// Inserts a "null operation" into the list of reads and writes. The callback -// will be called when all preceding operations have successfully completed. -AsyncId AsyncFileCreateSequence ( - AsyncFile file, - bool notify, - void * param -); - -enum EFileSeekFrom { - kFileSeekFromBegin, - kFileSeekFromCurrent, - kFileSeekFromEnd, - kNumFileSeekFroms -}; - -bool AsyncFileSeek ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom seekFrom -); - - /**************************************************************************** * * Socket connect packet diff --git a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.cpp b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.cpp index edcca438..de48ee9e 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.cpp +++ b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.cpp @@ -46,81 +46,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com ***/ #include "../Pch.h" +#include "plStatusLog/plStatusLog.h" #pragma hdrstop - -/***************************************************************************** -* -* Private -* -***/ - -static const unsigned kMaxHandlers = 8; -static CCritSect s_critsect; -static FLogHandler s_asyncHandlers[kMaxHandlers]; - - -/***************************************************************************** -* -* Internal functions -* -***/ - -//=========================================================================== -static void Dispatch (ELogSeverity severity, const wchar_t msg[]) { - - // Dispatch to default debug handler - char dbg[1024]; - StrToAnsi(dbg, msg, arrsize(dbg)); - DEBUG_MSG(dbg); - - // We don't need to enter a critical section to read the handlers because they - // are atomically set and cleared - for (unsigned i = 0; i < arrsize(s_asyncHandlers); ++i) { - if (FLogHandler asyncHandler = s_asyncHandlers[i]) - asyncHandler(severity, msg); - } -} - - /***************************************************************************** * * Exports * ***/ -//=========================================================================== -void LogRegisterHandler (FLogHandler callback) { - ASSERT(callback); - - unsigned i; - s_critsect.Enter(); - for (i = 0; i < arrsize(s_asyncHandlers); ++i) { - if (!s_asyncHandlers[i]) { - s_asyncHandlers[i] = callback; - break; - } - } - s_critsect.Leave(); - - #ifdef HS_DEBUGGING - if (i >= arrsize(s_asyncHandlers)) - FATAL("Maximum number of log handlers exceeded."); - #endif -} - -//=========================================================================== -void LogUnregisterHandler (FLogHandler callback) { - s_critsect.Enter(); - for (unsigned i = 0; i < arrsize(s_asyncHandlers); ++i) { - if (s_asyncHandlers[i] == callback) { - s_asyncHandlers[i] = nil; - break; - } - } - s_critsect.Leave(); -} - //=========================================================================== void CDECL LogMsg (ELogSeverity severity, const char format[], ...) { ASSERT(format); @@ -148,10 +82,7 @@ void LogMsgV (ELogSeverity severity, const char format[], va_list args) { char msg[1024]; StrPrintfV(msg, arrsize(msg), format, args); - wchar_t uniMsg[1024]; - StrToUnicode(uniMsg, msg, arrsize(uniMsg)); - - Dispatch(severity, uniMsg); + plStatusLog::AddLineS("OLD_ASYNC_LOG.log", msg); } //=========================================================================== @@ -162,7 +93,9 @@ void LogMsgV (ELogSeverity severity, const wchar_t format[], va_list args) { wchar_t msg[1024]; StrPrintfV(msg, arrsize(msg), format, args); - Dispatch(severity, msg); + char* to_log = hsWStringToString(msg); + plStatusLog::AddLineS("OLD_ASYNC_LOG.log", to_log); + delete[] to_log; } //============================================================================ diff --git a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.h b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.h index 3489cb90..e2445c32 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.h +++ b/Sources/Plasma/NucleusLib/pnAsyncCore/Private/pnAcLog.h @@ -81,33 +81,6 @@ void LogMsg (ELogSeverity severity, const wchar_t format[], ...); void LogMsgV (ELogSeverity severity, const char format[], va_list args); void LogMsgV (ELogSeverity severity, const wchar_t format[], va_list args); -void LogBreakOnErrors (bool breakOnErrors); - -void AsyncLogInitialize ( - const wchar_t logDirName[], - bool breakOnErrors -); -void AsyncLogDestroy (); -void AsyncLogFlush (); - -void AsyncLogGetDirectory (wchar_t * dest, unsigned destChars); - - -// Low(er) level log API; call this from your LogHander function -// if you want to use the asynchronous log facility. -void AsyncLogWriteMsg ( - const wchar_t facility[], - ELogSeverity severity, - const wchar_t msg[] -); - -// FLogHandler must be capable of handling multiple threads and re-entrancy -typedef void (* FLogHandler) (ELogSeverity severity, const wchar_t msg[]); - -void LogRegisterHandler (FLogHandler callback); -void LogUnregisterHandler (FLogHandler callback); - - /**************************************************************************** * * Debugging API diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/CMakeLists.txt b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/CMakeLists.txt index 0fe44fb0..4ae85f4b 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/CMakeLists.txt +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/CMakeLists.txt @@ -4,7 +4,6 @@ include_directories(../../NucleusLib) set(pnAsyncCoreExe_SOURCES pnAceCore.cpp pnAceIo.cpp - pnAceLog.cpp pnAceThread.cpp pnAceTimer.cpp ) @@ -23,7 +22,6 @@ set(pnAysncCoreExe_PRIVATE set(pnAysncCoreExe_PRIVATE_NT Private/Nt/pnAceNt.cpp Private/Nt/pnAceNt.h - Private/Nt/pnAceNtFile.cpp Private/Nt/pnAceNtInt.h Private/Nt/pnAceNtSocket.cpp Private/Nt/pnAceNtThread.cpp @@ -36,7 +34,6 @@ set(pnAsyncCoreExe_PRIVATE_UNIX set(pnAsyncCoreExe_PRIVATE_W9X Private/W9x/pnAceW9x.cpp Private/W9x/pnAceW9x.h - Private/W9x/pnAceW9xFile.cpp Private/W9x/pnAceW9xInt.h Private/W9x/pnAceW9xSocket.cpp Private/W9x/pnAceW9xThread.cpp @@ -61,4 +58,4 @@ source_group("Private" FILES ${pnAsyncCoreExe_PRIVATE}) source_group("Private\\Nt" FILES ${pnAysncCoreExe_PRIVATE_NT}) source_group("Private\\Unix" FILES ${pnAsyncCoreExe_PRIVATE_UNIX}) source_group("Private\\W9x" FILES ${pnAsyncCoreExe_PRIVATE_W9X}) -source_group("Private\\Win32" FILES ${pnAsyncCoreExe_PRIVATE_WIN32}) \ No newline at end of file +source_group("Private\\Win32" FILES ${pnAsyncCoreExe_PRIVATE_WIN32}) diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNt.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNt.cpp index d41d3a94..8e9dbd18 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNt.cpp +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNt.cpp @@ -152,28 +152,6 @@ static void INtOpDispatch ( INtSocketOpCompleteSocketWrite((NtSock *) ntObj, (NtOpSocketWrite *) op); break; - case kOpQueuedFileRead: - case kOpQueuedFileWrite: - INtFileOpCompleteQueuedReadWrite((NtFile *) ntObj, (NtOpFileReadWrite *) op); - // operation converted into kOpFileWrite so we cannot move - // to next operation until write operation completes - return; - - case kOpFileRead: - case kOpFileWrite: - ASSERT(bytes != (uint32_t) -1); - if (!INtFileOpCompleteReadWrite((NtFile *) ntObj, (NtOpFileReadWrite *) op, bytes)) - return; - break; - - case kOpFileFlush: - INtFileOpCompleteFileFlush((NtFile *) ntObj, (NtOpFileFlush *) op); - break; - - case kOpSequence: - INtFileOpCompleteSequence((NtFile *) ntObj, (NtOpFileSequence *) op); - break; - DEFAULT_FATAL(opType); } @@ -329,10 +307,6 @@ void INtConnCompleteOperation (NtObject * ntObj) { DWORD err = GetLastError(); switch (ntObj->ioType) { - case kNtFile: - INtFileDelete((NtFile *) ntObj); - break; - case kNtSocket: INtSockDelete((NtSock *) ntObj); break; @@ -393,7 +367,6 @@ void NtInitialize () { ); } - INtFileInitialize(); INtSocketInitialize(); } @@ -403,7 +376,6 @@ void NtInitialize () { // shut down the program is to simply let the atexit() handler take care of it. void NtDestroy (unsigned exitThreadWaitMs) { // cleanup modules that post completion notifications as part of their shutdown - INtFileStartCleanup(); INtSocketStartCleanup(exitThreadWaitMs); // cleanup worker threads @@ -434,7 +406,6 @@ void NtDestroy (unsigned exitThreadWaitMs) { s_waitEvent = 0; } - INtFileDestroy(); INtSocketDestroy(); } @@ -466,16 +437,6 @@ void NtGetApi (AsyncApi * api) { api->waitForShutdown = NtWaitForShutdown; api->sleep = NtSleep; - api->fileOpen = NtFileOpen; - api->fileClose = NtFileClose; - api->fileRead = NtFileRead; - api->fileWrite = NtFileWrite; - api->fileFlushBuffers = NtFileFlushBuffers; - api->fileSetLastWriteTime = NtFileSetLastWriteTime; - api->fileGetLastWriteTime = NtFileGetLastWriteTime; - api->fileCreateSequence = NtFileCreateSequence; - api->fileSeek = NtFileSeek; - api->socketConnect = NtSocketConnect; api->socketConnectCancel = NtSocketConnectCancel; api->socketDisconnect = NtSocketDisconnect; diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtFile.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtFile.cpp deleted file mode 100644 index d717b69a..00000000 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtFile.cpp +++ /dev/null @@ -1,1010 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtFile.cpp -* -***/ - -#include "../../Pch.h" -#pragma hdrstop - -#include "pnAceNtInt.h" - - -namespace Nt { - -/**************************************************************************** -* -* Private -* -***/ - -// Must be a multiple of largest possible disk sector size -const unsigned kSplitRwBytes = 4 * 1024 * 1024; - - -struct NtOpFileReadWrite : Operation { - NtOpFileReadWrite * masterOp; - unsigned win32Bytes; - AsyncNotifyFileRead rw; -}; - -struct NtOpFileFlush : Operation { - AsyncNotifyFileFlush flush; -}; - -struct NtOpFileSequence : Operation { - AsyncNotifyFileSequence sequence; -}; - -struct NtFile : NtObject { - FAsyncNotifyFileProc notifyProc; - LINK(NtFile) openLink; // protected by s_fileCrit - LINK(NtFile) pendLink; // protected by s_fileCrit - unsigned queueWrites; - unsigned sectorSizeMask; - wchar_t fullPath[MAX_PATH]; - - NtFile (); - ~NtFile (); -}; - -static long s_fileOps; -static CNtCritSect s_fileCrit; -static LISTDECL(NtFile, openLink) s_openFiles; -static LISTDECL(NtFile, pendLink) s_pendFiles; -static AsyncTimer * s_timer; - - -//=========================================================================== -inline NtFile::NtFile () { - PerfAddCounter(kAsyncPerfFilesCurr, 1); - PerfAddCounter(kAsyncPerfFilesTotal, 1); -} - -//=========================================================================== -NtFile::~NtFile () { - PerfSubCounter(kAsyncPerfFilesCurr, 1); -} - -//=========================================================================== -static void FatalOnNonRecoverableError ( - const NtOpFileReadWrite & op, - unsigned error -) { - switch (error) { - case ERROR_NO_SYSTEM_RESOURCES: - case ERROR_NONPAGED_SYSTEM_RESOURCES: - case ERROR_PAGED_SYSTEM_RESOURCES: - case ERROR_WORKING_SET_QUOTA: - case ERROR_PAGEFILE_QUOTA: - case ERROR_COMMITMENT_LIMIT: - return; - } - - ASSERT((op.opType == kOpFileRead) || (op.opType == kOpFileWrite)); - ErrorAssert( - __LINE__, __FILE__, - "Disk %s failed, error: %u", - op.opType == kOpFileRead ? "read" : "write", - error - ); -} - -//=========================================================================== -static unsigned INtFileTimerProc (void *) { - if (!s_pendFiles.Head()) - return INFINITE; - - if (!s_fileCrit.TryEnter()) - return 10; - - // dequeue head of list - NtFile * file = s_pendFiles.Head(); - if (file) - s_pendFiles.Unlink(file); - s_fileCrit.Leave(); - if (!file) - return INFINITE; - - // retry operation - ASSERT(file->opList.Head()); - ASSERT((file->opList.Head()->opType == kOpQueuedFileRead) - || (file->opList.Head()->opType == kOpQueuedFileWrite) - ); - INtFileOpCompleteQueuedReadWrite(file, (NtOpFileReadWrite *) file->opList.Head()); - return 0; -} - -//=========================================================================== -static void HandleFailedOp ( - NtFile * file, - NtOpFileReadWrite * op, - unsigned error -) { - ASSERT((op->opType == kOpFileRead) || (op->opType == kOpFileWrite)); - - // break the operation into a bunch of sub-operations if it hasn't already been done - unsigned subOperations = 0; - LISTDECL(NtOpFileReadWrite, link) opList; - if (!op->masterOp) { - // setup master operation to read the start of the buffer; this - // ensures that op->rw.* is unchanged for the master operation, - // which is important for the user notification callback - op->masterOp = op; - op->win32Bytes = min(kSplitRwBytes, op->rw.bytes); - unsigned position = op->win32Bytes; - - // create sub-operations to read the rest of the buffer - for (; position < op->rw.bytes; ++subOperations) { - NtOpFileReadWrite * childOp = new NtOpFileReadWrite; - childOp->overlapped.hEvent = op->overlapped.hEvent ? CreateEvent(nil, true, false, nil) : nil; - childOp->overlapped.Offset = (uint32_t) ((op->rw.offset + position) & 0xffffffff); - childOp->overlapped.OffsetHigh = (uint32_t) ((op->rw.offset + position) >> 32); - childOp->opType = op->opType; - childOp->asyncId = 0; - childOp->notify = false; - childOp->pending = 1; - childOp->signalComplete = nil; - childOp->masterOp = op; - childOp->win32Bytes = min(kSplitRwBytes, op->rw.bytes - position); - childOp->rw.param = nil; - childOp->rw.asyncId = 0; - childOp->rw.offset = op->rw.offset + position; - childOp->rw.buffer = op->rw.buffer + position; - childOp->rw.bytes = childOp->win32Bytes; - opList.Link(childOp, kListTail); - position += childOp->win32Bytes; - } - - InterlockedExchangeAdd(&file->ioCount, (long) subOperations); - } - - bool autoComplete = true; - unsigned eventCount = 0; - HANDLE events[MAXIMUM_WAIT_OBJECTS]; - - file->critsect.Enter(); - - // start with the master operation since it points to the start of the buffer - NtOpFileReadWrite * childOp = op; - op->pending += subOperations; - for (;;) { - // if we're not repeating the previous operation then dequeue a new one - if (!childOp) { - if (nil == (childOp = opList.Head())) - break; - opList.Unlink(childOp); - file->opList.Link(childOp, kListLinkBefore, op); - } - - // issue the operation - bool result; - const HANDLE hEvent = childOp->overlapped.hEvent; - if (childOp->opType == kOpFileRead) { - result = ReadFile( - file->handle, - childOp->rw.buffer, - childOp->win32Bytes, - 0, - &childOp->overlapped - ); - } - else { - ASSERT(childOp->opType == kOpFileWrite); - result = WriteFile( - file->handle, - childOp->rw.buffer, - childOp->win32Bytes, - 0, - &childOp->overlapped - ); - } - - if (!result && ((error = GetLastError()) != ERROR_IO_PENDING)) { - FatalOnNonRecoverableError(*childOp, error); - - if (eventCount) { - LogMsg(kLogError, "HandleFailedOp1 failed"); - // wait for other operations to complete on this file before retrying - } - else if (childOp->overlapped.hEvent) { - LogMsg(kLogError, "HandleFailedOp2 failed"); - // wait a while and retry operation again - Sleep(10); - continue; - } - else { - // convert operation into pending operation - const EOpType opType = (childOp->opType == kOpFileRead) - ? kOpQueuedFileRead - : kOpQueuedFileWrite; - childOp->opType = opType; - - // convert all other operations into pending operations - while (nil != (childOp = opList.Head())) { - childOp->opType = opType; - opList.Unlink(childOp); - file->opList.Link(childOp, kListLinkBefore, op); - } - - // if there is an operation at the head of the list that will complete - // without help then it will autostart the operations we queued - autoComplete = file->opList.Head()->opType != opType; - break; - } - } - else { - // operation was successful - childOp = nil; - - // if we didn't fill the synchronous event array then continue issuing operations - if (nil == (events[eventCount] = hEvent)) - continue; - if (++eventCount < arrsize(events)) - continue; - } - - // wait for all synchronous operations to complete - if (eventCount) { - file->critsect.Leave(); - WaitForMultipleObjects(eventCount, events, true, INFINITE); - for (unsigned i = 0; i < eventCount; ++i) - CloseHandle(events[i]); - eventCount = 0; - file->critsect.Enter(); - } - } - file->critsect.Leave(); - - if (eventCount) { - WaitForMultipleObjects(eventCount, events, true, INFINITE); - for (unsigned i = 0; i < eventCount; ++i) - CloseHandle(events[i]); - } - else if (!autoComplete) { - s_fileCrit.Enter(); - s_pendFiles.Link(file, kListTail); - s_fileCrit.Leave(); - - AsyncTimerUpdate(s_timer, 0, kAsyncTimerUpdateSetPriorityHigher); - } -} - -//=========================================================================== -static void InternalFileSetSize (NtObject * file, uint64_t size) { - LONG sizeHigh = (long) (size >> 32); - DWORD seek = SetFilePointer(file->handle, (uint32_t) size, &sizeHigh, FILE_BEGIN); - if ((seek != (DWORD) -1) || (GetLastError() == NO_ERROR)) - SetEndOfFile(file->handle); -} - - -/**************************************************************************** -* -* Module functions -* -***/ - -//=========================================================================== -void INtFileInitialize () { - AsyncTimerCreate(&s_timer, INtFileTimerProc, INFINITE); -} - -//=========================================================================== -void INtFileStartCleanup () { - // wait until outstanding file I/O is complete - for (;; Sleep(10)) { - if (s_fileOps) - continue; - if (AsyncPerfGetCounter(kAsyncPerfFileBytesReadQueued)) - continue; - if (AsyncPerfGetCounter(kAsyncPerfFileBytesWriteQueued)) - continue; - if (volatile bool pending = (s_pendFiles.Head() != nil)) - continue; - break; - } - - // slam closed any files which are still open - for (;;) { - s_fileCrit.Enter(); - NtFile * file = s_openFiles.Head(); - if (file) - s_openFiles.Unlink(file); - s_fileCrit.Leave(); - if (!file) - break; - - char msg[256 + MAX_PATH]; - StrPrintf(msg, arrsize(msg), "Error: file '%S' still open", file->fullPath); - ErrorAssert(__LINE__, __FILE__, msg); - - file->notifyProc = nil; - INtConnCompleteOperation(file); - } -} - -//=========================================================================== -void INtFileDestroy () { - if (s_timer) { - AsyncTimerDelete(s_timer, kAsyncTimerDestroyWaitComplete); - s_timer = nil; - } -} - -//=========================================================================== -void INtFileDelete ( - NtFile * file -) { - file->critsect.Enter(); - if (file->handle != INVALID_HANDLE_VALUE) { - CloseHandle(file->handle); - file->handle = INVALID_HANDLE_VALUE; - } - file->critsect.Leave(); - - delete file; -} - -//=========================================================================== -void INtFileOpCompleteQueuedReadWrite ( - NtFile * file, - NtOpFileReadWrite * op -) { - bool result; - const HANDLE hEvent = op->overlapped.hEvent; - switch (op->opType) { - case kOpQueuedFileRead: - op->opType = kOpFileRead; - // fall through - - case kOpFileRead: - result = ReadFile( - file->handle, - op->rw.buffer, - op->win32Bytes, - 0, - &op->overlapped - ); - break; - - case kOpQueuedFileWrite: - op->opType = kOpFileWrite; - // fall through - - case kOpFileWrite: - result = WriteFile( - file->handle, - op->rw.buffer, - op->win32Bytes, - 0, - &op->overlapped - ); - break; - - DEFAULT_FATAL(opType); - } - - unsigned error; - if (!result && ((error = GetLastError()) != ERROR_IO_PENDING)) { - FatalOnNonRecoverableError(*op, error); - HandleFailedOp(file, op, error); - } - else if (hEvent) { - WaitForSingleObject(hEvent, INFINITE); - CloseHandle(hEvent); - } -} - -//=========================================================================== -bool INtFileOpCompleteReadWrite ( - NtFile * file, - NtOpFileReadWrite * op, - unsigned bytes -) { - // adjust outstanding bytes - if (bytes != op->win32Bytes) { - if (!file->sectorSizeMask) - ErrorAssert(__LINE__, __FILE__, "Disk %s failed", op->opType == kOpFileRead ? "read" : "write"); - if (op->opType == kOpFileRead) - memset(op->rw.buffer + bytes, 0, op->win32Bytes - bytes); - } - - if (op->masterOp) { - bool bail = false; - file->critsect.Enter(); - - // if this is a child operation (!op->asyncId) then - // decrement the master operation's pending count - if (!op->asyncId && (--op->masterOp->pending == 1)) { - if (!op->masterOp->masterOp) - INtConnPostOperation(file, op->masterOp, op->masterOp->win32Bytes); - } - // this is the master operation; wait until all the child operations complete - else if (op->pending != 1) { - op->masterOp->masterOp = nil; - bail = true; - } - file->critsect.Leave(); - if (bail) - return false; - } - - // callback notification procedure if requested - if (op->notify) { - // before we dispatch the operation to the handler, change its - // type to indicate that the operation is being dispatched - op->notify = false; - file->notifyProc( - (AsyncFile) file, - op->opType == kOpFileRead ? kNotifyFileRead : kNotifyFileWrite, - &op->rw, - &file->userState - ); - } - - PerfSubCounter( - op->opType == kOpFileRead ? kAsyncPerfFileBytesReadQueued : kAsyncPerfFileBytesWriteQueued, - op->win32Bytes - ); - return true; -} - -//=========================================================================== -void INtFileOpCompleteFileFlush ( - NtFile * file, - NtOpFileFlush * op -) { - ASSERT(file->ioType == kNtFile); - - // complete flush operation - if (!FlushFileBuffers(file->handle)) - op->flush.error = AsyncGetLastFileError(); - else - op->flush.error = kFileSuccess; - - if (op->flush.truncateSize != kAsyncFileDontTruncate) - InternalFileSetSize(file, op->flush.truncateSize); - - // start any queued writes which were waiting for this flush operation to - // complete, but only complete any writes up to the next flush operation - file->critsect.Enter(); - --file->queueWrites; - for (Operation * scan = file->opList.Head(); scan; scan = file->opList.Next(scan)) { - if (scan->opType == kOpQueuedFileWrite) - INtFileOpCompleteQueuedReadWrite(file, (NtOpFileReadWrite *) scan); - else if ((scan->opType == kOpFileFlush) && (scan != op)) - break; - } - file->critsect.Leave(); - - if (op->notify) { - op->notify = false; - file->notifyProc((AsyncFile) file, kNotifyFileFlush, &op->flush, &file->userState); - } - InterlockedDecrement(&s_fileOps); -} - -//=========================================================================== -void INtFileOpCompleteSequence ( - NtFile * file, - NtOpFileSequence * op -) { - if (op->notify) { - op->notify = false; - file->notifyProc((AsyncFile) file, kNotifyFileSequence, &op->sequence, &file->userState); - } - InterlockedDecrement(&s_fileOps); -} - - -/**************************************************************************** -* -* Exported functions -* -***/ - -//=========================================================================== -AsyncFile NtFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -) { - unsigned attributeFlags = 0; - attributeFlags |= FILE_FLAG_OVERLAPPED; - - HANDLE handle = CreateFileW( - fullPath, - desiredAccess, - shareModeFlags, - nil, // plSecurityAttributes - openMode, - attributeFlags, - nil // hTemplateFile - ); - *error = AsyncGetLastFileError(); - - if (INVALID_HANDLE_VALUE == handle) - return nil; - - // don't allow users to open devices like "LPT1", etc. - if (GetFileType(handle) != FILE_TYPE_DISK) { - LogMsg(kLogFatal, "!FILE_TYPE_DISK"); - *error = kFileErrorFileNotFound; - CloseHandle(handle); - return nil; - } - - // get file size - DWORD sizeHi, sizeLo = GetFileSize(handle, &sizeHi); - if ((sizeLo == (DWORD) -1) && (NO_ERROR != GetLastError())) { - *error = AsyncGetLastFileError(); - LogMsg(kLogFatal, "GetFileSize"); - CloseHandle(handle); - return nil; - } - const uint64_t size = ((uint64_t) sizeHi << (uint64_t) 32) | (uint64_t) sizeLo; - - uint64_t lastWriteTime; - ASSERT(sizeof(lastWriteTime) >= sizeof(FILETIME)); - GetFileTime(handle, nil, nil, (FILETIME *) &lastWriteTime); - - // allocate and initialize a new file - NtFile * conn = NEWZERO(NtFile); - conn->ioType = kNtFile; - conn->handle = handle; - conn->notifyProc = notifyProc; - conn->ioCount = 1; - conn->queueWrites = 0; - conn->userState = userState; - conn->sectorSizeMask = 0; - - conn->closed = false; - StrCopy(conn->fullPath, fullPath, arrsize(conn->fullPath)); - - if (!INtConnInitialize(conn)) { - *error = kFileErrorFileNotFound; - conn->notifyProc = nil; - INtConnCompleteOperation(conn); - return nil; - } - - // add to list of open files - s_fileCrit.Enter(); - s_openFiles.Link(conn); - s_fileCrit.Leave(); - - // return out parameters - if (fileSize) - *fileSize = size; - if (fileLastWriteTime) - *fileLastWriteTime = lastWriteTime; - return (AsyncFile) conn; -} - -//=========================================================================== -AsyncId NtFileRead ( - AsyncFile conn, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - NtFile * file = (NtFile *) conn; - ASSERT(file->ioType == kNtFile); - ASSERT(file->handle != INVALID_HANDLE_VALUE); - ASSERT((flags & (kAsyncFileRwNotify|kAsyncFileRwSync)) != (kAsyncFileRwNotify|kAsyncFileRwSync)); - ASSERT(! (offset & file->sectorSizeMask)); - ASSERT(! (bytes & file->sectorSizeMask)); - ASSERT(! ((uintptr_t) buffer & file->sectorSizeMask)); - - // Normally, I/O events do not complete until both the WIN32 operation has completed - // and the callback notification has occurred. A deadlock can occur if a thread attempts - // to perform a series of operations and then waits for those operations to complete if - // that thread holds a critical section, because all the I/O worker threads cannot - // enter that critical section to complete their required notification callbacks. To - // enable the sequential thread to perform a wait operation, we set the event field - // into the Overlapped structure, because the event will be signaled prior to the - // potentially deadlocking callback notification. - NtOpFileReadWrite * op = new NtOpFileReadWrite; - op->overlapped.Offset = (uint32_t) (offset & 0xffffffff); - op->overlapped.OffsetHigh = (uint32_t) (offset >> 32); - op->overlapped.hEvent = (flags & kAsyncFileRwSync) ? CreateEvent(nil, true, false, nil) : nil; - op->opType = kOpFileRead; - op->notify = (flags & kAsyncFileRwNotify) != 0; - op->pending = 1; - op->signalComplete = nil; - op->masterOp = nil; - op->win32Bytes = bytes; - op->rw.param = param; - op->rw.offset = offset; - op->rw.buffer = (uint8_t *) buffer; - op->rw.bytes = bytes; - - InterlockedIncrement(&file->ioCount); - PerfAddCounter(kAsyncPerfFileBytesReadQueued, bytes); - - file->critsect.Enter(); - const AsyncId asyncId = op->rw.asyncId = op->asyncId = INtConnSequenceStart(file); - file->opList.Link(op, kListTail); - file->critsect.Leave(); - - INtFileOpCompleteQueuedReadWrite(file, op); - - return asyncId; -} - -//=========================================================================== -// buffer must stay valid until I/O is completed -AsyncId NtFileWrite ( - AsyncFile conn, - uint64_t offset, - const void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - NtFile * file = (NtFile *) conn; - ASSERT(file->ioType == kNtFile); - ASSERT(file->handle != INVALID_HANDLE_VALUE); - ASSERT((flags & (kAsyncFileRwNotify|kAsyncFileRwSync)) != (kAsyncFileRwNotify|kAsyncFileRwSync)); - ASSERT(! (offset & file->sectorSizeMask)); - ASSERT(! (bytes & file->sectorSizeMask)); - ASSERT(! ((uintptr_t) buffer & file->sectorSizeMask)); - - // Normally, I/O events do not complete until both the WIN32 operation has completed - // and the callback notification has occurred. A deadlock can occur if a thread attempts - // to perform a series of operations and then waits for those operations to complete if - // that thread holds a critical section, because all the I/O worker threads cannot - // enter that critical section to complete their required notification callbacks. To - // enable the sequential thread to perform a wait operation, we set the event field - // into the Overlapped structure, because the event will be signaled prior to the - // potentially deadlocking callback notification. - NtOpFileReadWrite * op = new NtOpFileReadWrite; - op->overlapped.Offset = (uint32_t) (offset & 0xffffffff); - op->overlapped.OffsetHigh = (uint32_t) (offset >> 32); - op->overlapped.hEvent = (flags & kAsyncFileRwSync) ? CreateEvent(nil, true, false, nil) : nil; - op->opType = kOpFileWrite; - op->notify = (flags & kAsyncFileRwNotify) != 0; - op->pending = 1; - op->signalComplete = nil; - op->masterOp = nil; - op->win32Bytes = bytes; - op->rw.param = param; - op->rw.offset = offset; - op->rw.buffer = (uint8_t *) buffer; - op->rw.bytes = bytes; - - InterlockedIncrement(&file->ioCount); - PerfAddCounter(kAsyncPerfFileBytesWriteQueued, bytes); - - // to avoid a potential deadlock, we MUST issue the write if the SYNC flag is set - file->critsect.Enter(); - ASSERT(!file->queueWrites || !op->overlapped.hEvent); - const bool startOperation = !file->queueWrites || op->overlapped.hEvent; - if (!startOperation) - op->opType = kOpQueuedFileWrite; - const AsyncId asyncId = op->asyncId = op->rw.asyncId = INtConnSequenceStart(file); - file->opList.Link(op, kListTail); - file->critsect.Leave(); - - if (startOperation) - INtFileOpCompleteQueuedReadWrite(file, op); - - return asyncId; -} - -//=========================================================================== -AsyncId NtFileFlushBuffers ( - AsyncFile conn, - uint64_t truncateSize, - bool notify, - void * param -) { - NtFile * file = (NtFile *) conn; - ASSERT(file); - ASSERT(file->ioType == kNtFile); - ASSERT(file->handle != INVALID_HANDLE_VALUE); - ASSERT((truncateSize == kAsyncFileDontTruncate) || !(truncateSize & file->sectorSizeMask)); - - // create new operation - NtOpFileFlush * op = new NtOpFileFlush; - file->critsect.Enter(); - - // write operations cannot complete while a flush is in progress - ++file->queueWrites; - - // init Operation - const AsyncId asyncId = INtConnSequenceStart(file); - op->overlapped.Offset = 0; - op->overlapped.OffsetHigh = 0; - op->overlapped.hEvent = nil; - op->opType = kOpFileFlush; - op->asyncId = asyncId; - op->notify = notify; - op->pending = 1; - op->signalComplete = nil; - file->opList.Link(op, kListTail); - - // init OpFileFlush - op->flush.param = param; - op->flush.asyncId = asyncId; - op->flush.error = kFileSuccess; - op->flush.truncateSize = truncateSize; - - InterlockedIncrement(&s_fileOps); - InterlockedIncrement(&file->ioCount); - - // if there are other operations already on the list we can't complete this one - if (op != file->opList.Head()) - op = nil; - - file->critsect.Leave(); - - // If the operation is at the head of the - // list then issue it for immediate complete - if (op) - INtConnPostOperation(file, op, 0); - return asyncId; -} - -//=========================================================================== -void NtFileClose ( - AsyncFile conn, - uint64_t truncateSize -) { - NtFile * file = (NtFile *) conn; - ASSERT(file); - ASSERT(file->ioType == kNtFile); - - file->critsect.Enter(); - { - { - // AsyncFileClose guarantees that when it returns the file handle will be - // closed so that an immediate call to AsyncFileOpen will succeed. In order - // to successfully close the file handle immediately, we must ensure that - // there is be no active I/O on the file; either no operations on list, or - // only operations on list which are being dispatched or have been dispatched. - ASSERT(!file->pendLink.IsLinked()); - for (Operation * op = file->opList.Head(); op; op = file->opList.Next(op)) { - // skip completed operations - if (!op->pending) - continue; - - // skip operations which are "technically complete" - if (!op->notify) - continue; - - ErrorAssert(__LINE__, __FILE__, "AsyncFileClose: File has pending I/O!"); - break; - } - - // make sure the user doesn't attempt to close the file twice - ASSERT(!file->closed); - file->closed = true; - } - - if (truncateSize != kAsyncFileDontTruncate) - InternalFileSetSize(file, truncateSize); - - ASSERT(file->handle != INVALID_HANDLE_VALUE); - CloseHandle(file->handle); - file->handle = INVALID_HANDLE_VALUE; - } - file->critsect.Leave(); - - // remove file from list of open files - s_fileCrit.Enter(); - ASSERT(!file->pendLink.IsLinked()); - s_openFiles.Unlink(file); - s_fileCrit.Leave(); - - INtConnCompleteOperation(file); -} - -//=========================================================================== -void NtFileSetLastWriteTime ( - AsyncFile conn, - uint64_t lastWriteTime -) { - NtFile * file = (NtFile *) conn; - ASSERT(file); - ASSERT(file->ioType == kNtFile); - - file->critsect.Enter(); - ASSERT(file->handle != INVALID_HANDLE_VALUE); - SetFileTime(file->handle, nil, nil, (FILETIME *) &lastWriteTime); - file->critsect.Leave(); -} - -//=========================================================================== -uint64_t NtFileGetLastWriteTime ( - const wchar_t fileName[] -) { - WIN32_FILE_ATTRIBUTE_DATA info; - bool f = GetFileAttributesExW(fileName, GetFileExInfoStandard, &info); - return f ? *((uint64_t *) &info.ftLastWriteTime) : 0; -} - -//=========================================================================== -// Inserts a "null operation" into the list of reads and writes. The callback -// will be called when all preceding operations have successfully completed. -AsyncId NtFileCreateSequence ( - AsyncFile conn, - bool notify, - void * param -) { - NtFile * file = (NtFile *) conn; - ASSERT(file); - ASSERT(file->ioType == kNtFile); - - // create new operation - NtOpFileSequence * op = new NtOpFileSequence; - file->critsect.Enter(); - - // init Operation - const AsyncId asyncId = INtConnSequenceStart(file); - op->overlapped.Offset = 0; - op->overlapped.OffsetHigh = 0; - op->overlapped.hEvent = nil; - op->opType = kOpSequence; - op->asyncId = asyncId; - op->notify = notify; - op->pending = 1; - op->signalComplete = nil; - file->opList.Link(op, kListTail); - - // init OpFileSequence - op->sequence.param = param; - op->sequence.asyncId = asyncId; - - InterlockedIncrement(&s_fileOps); - InterlockedIncrement(&file->ioCount); - - // if there are other operations already on the list we can't complete this one - if (op != file->opList.Head()) - op = nil; - - file->critsect.Leave(); - - // If the operation is at the head of the - // list then issue it for immediate complete - if (op) - INtConnPostOperation(file, op, 0); - return asyncId; -} - -//=========================================================================== -// This function allows the caller to wait until an I/O operation completes for -// a file. However, it is an EXTREMELY DANGEROUS function, so you should follow -// these rules to avoid a deadlock: -// 1. AsyncWaitId CAN NEVER be called in response to an I/O completion notification -// callback (a call to an FAsyncNotifyFileProc), because if all I/O threads were -// blocking for I/O there would be no threads left to complete the I/O. -// 2. AsyncWaitId CAN NEVER be called from a timer callback for the same reason as #1. -// 3. AsyncWaitId can be called from inside an idle callback (FAsyncIdleProc), because -// only half of the I/O threads can be inside an idle callback at the same time, -// which leaves the other half available to complete I/O. -// 4. When calling AsyncWaitId, the thread which makes the call MUST NOT hold any -// locks (critical section or reader/writer locks) which would cause an I/O -// thread to block while completing I/O that might be needed to complete the -// I/O operation that is being waited. That means not only the specific I/O -// operation that is being waited, but also any I/O that will call the same -// FAsyncNotifyFileProc. -// 5. Spin-blocking (calling AsyncWaitId in a loop with a small timeout value) IS NOT -// a solution to the deadlock problem, it will still create a deadlock because -// the I/O thread is still fully occupied and cannot complete any I/O -bool NtFileWaitId (AsyncFile conn, AsyncId asyncId, unsigned timeoutMs) { - NtFile * file = (NtFile *) conn; - ASSERT(asyncId); - ASSERT(file); - ASSERT(file->ioType == kNtFile); - ASSERT(file->handle != INVALID_HANDLE_VALUE); - - ThreadAssertCanBlock(__FILE__, __LINE__); - - // has the AsyncId already completed? - if (file->nextCompleteSequence - (long) asyncId >= 0) - return true; - - // is this a non-blocking wait? - if (!timeoutMs) - return false; - - // find the I/O operation the user is waiting for - CNtWaitHandle * signalComplete = nil; - file->critsect.Enter(); - for (Operation * op = file->opList.Head(); op; op = file->opList.Next(op)) { - if (asyncId != op->asyncId) - continue; - - // create an object to wait on - if (!op->signalComplete) - op->signalComplete = new CNtWaitHandle; - signalComplete = op->signalComplete; - signalComplete->IncRef(); - break; - } - file->critsect.Leave(); - - // if we didn't find or create a signal then the operation must have - // completed just before we managed to enter the critical section - if (!signalComplete) - return true; - - const bool result = signalComplete->WaitForObject(timeoutMs); - signalComplete->DecRef(); - return result; -} - -//============================================================================ -bool NtFileSeek ( - AsyncFile conn, - uint64_t distance, - EFileSeekFrom from -) { - COMPILER_ASSERT(kFileSeekFromBegin == FILE_BEGIN); - COMPILER_ASSERT(kFileSeekFromCurrent == FILE_CURRENT); - COMPILER_ASSERT(kFileSeekFromEnd == FILE_END); - - NtFile * file = (NtFile *) conn; - LONG low = (LONG)(distance % 0x100000000ul); - LONG high = (LONG)(distance / 0x100000000ul); - uint32_t result = SetFilePointer(file->handle, low, &high, from); - if ((result == (uint32_t)-1) && (GetLastError() != NO_ERROR)) { - LogMsg(kLogFatal, "failed: SetFilePointer"); - return false; - } - else - return true; -} - -} // namespace Nt diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtInt.h b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtInt.h index 0d2bc7d4..8f702287 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtInt.h +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtInt.h @@ -142,45 +142,6 @@ bool INtConnInitialize (NtObject * ntObj); void INtConnCompleteOperation (NtObject * ntObj); -/***************************************************************************** -* -* NtFile.cpp internal functions -* -***/ - -struct NtFile; -struct NtOpFileFlush; -struct NtOpFileReadWrite; -struct NtOpFileSequence; - -void INtFileInitialize (); -void INtFileStartCleanup (); -void INtFileDestroy (); - -void INtFileDelete ( - NtFile * file -); - -bool INtFileOpCompleteReadWrite ( - NtFile * ioConn, - NtOpFileReadWrite * op, - unsigned bytes -); -void INtFileOpCompleteQueuedReadWrite ( - NtFile * ioConn, - NtOpFileReadWrite * op -); -void INtFileOpCompleteFileFlush ( - NtFile * ioConn, - NtOpFileFlush * op -); -void INtFileOpCompleteSequence ( - NtFile * ioConn, - NtOpFileSequence * op -); - -void INtFileStartCleanup (); - /***************************************************************************** * @@ -228,60 +189,6 @@ void NtDestroy (unsigned exitThreadWaitMs); void NtSignalShutdown (); void NtWaitForShutdown (); void NtSleep (unsigned sleepMs); -AsyncFile NtFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -); -void NtFileClose ( - AsyncFile file, - uint64_t truncateSize -); -void NtFileSetLastWriteTime ( - AsyncFile file, - uint64_t lastWriteTime -); -uint64_t NtFileGetLastWriteTime ( - const wchar_t fileName[] -); -AsyncId NtFileFlushBuffers ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -); -AsyncId NtFileRead ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -); -AsyncId NtFileWrite ( - AsyncFile file, - uint64_t offset, - const void *buffer, - unsigned bytes, - unsigned flags, - void * param -); -AsyncId NtFileCreateSequence ( - AsyncFile file, - bool notify, - void * param -); -bool NtFileSeek ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom from -); void NtSocketConnect ( AsyncCancelId * cancelId, const NetAddress & netAddr, diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9x.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9x.cpp index 05a439d1..6d8a5db4 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9x.cpp +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9x.cpp @@ -67,16 +67,6 @@ void W9xGetApi (AsyncApi * api) { api->waitForShutdown = W9xThreadWaitForShutdown; api->sleep = W9xThreadSleep; - api->fileOpen = W9xFileOpen; - api->fileClose = W9xFileClose; - api->fileRead = W9xFileRead; - api->fileWrite = W9xFileWrite; - api->fileFlushBuffers = W9xFileFlushBuffers; - api->fileSetLastWriteTime = W9xFileSetLastWriteTime; - api->fileGetLastWriteTime = W9xFileGetLastWriteTime; - api->fileCreateSequence = W9xFileCreateSequence; - api->fileSeek = W9xFileSeek; - api->socketConnect = W9xSocketConnect; api->socketConnectCancel = W9xSocketConnectCancel; api->socketDisconnect = W9xSocketDisconnect; diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xFile.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xFile.cpp deleted file mode 100644 index d35f9f8b..00000000 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xFile.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xFile.cpp -* -***/ - -#include "../../Pch.h" -#pragma hdrstop - -#include "pnAceW9xInt.h" - - -namespace W9x { - - -/**************************************************************************** -* -* FileOp -* -***/ - -struct FileOp { - EAsyncNotifyFile code; - bool notify; - union { - AsyncNotifyFileFlush flush; - AsyncNotifyFileRead read; - AsyncNotifyFileSequence sequence; - AsyncNotifyFileWrite write; - } data; -}; - - -/**************************************************************************** -* -* CFile -* -***/ - -class CFile : public CThreadDispObject { -private: - CCritSect m_critSect; - HANDLE m_handle; - FAsyncNotifyFileProc m_notifyProc; - void * m_userState; - -protected: - void Complete (void * op, CCritSect * critSect, AsyncId asyncId); - void Delete (void * op); - -public: - CFile ( - HANDLE handle, - FAsyncNotifyFileProc notifyProc, - void * userState - ); - ~CFile (); - - void Read ( - uint64_t offset, - void * buffer, - unsigned bytes - ); - - void SetLastWriteTime (uint64_t lastWriteTime); - - void Truncate (uint64_t size); - - void Write ( - uint64_t offset, - const void * buffer, - unsigned bytes - ); - - bool Seek (uint64_t offset, EFileSeekFrom from); -}; - -//=========================================================================== -CFile::CFile ( - HANDLE handle, - FAsyncNotifyFileProc notifyProc, - void * userState -) : - m_handle(handle), - m_notifyProc(notifyProc), - m_userState(userState) -{ -} - -//=========================================================================== -CFile::~CFile () { - CloseHandle(m_handle); - m_handle = INVALID_HANDLE_VALUE; -} - -//=========================================================================== -void CFile::Complete (void * op, CCritSect * critSect, AsyncId asyncId) { - FileOp * fileOp = (FileOp *)op; - - // Enter our local critical section and leave the global one - m_critSect.Enter(); - critSect->Leave(); - - // Complete the operation - switch (fileOp->code) { - - case kNotifyFileFlush: { - if (fileOp->data.flush.truncateSize != kAsyncFileDontTruncate) - Truncate(fileOp->data.flush.truncateSize); - BOOL result = FlushFileBuffers(m_handle); - fileOp->data.flush.error = result ? kFileSuccess : AsyncGetLastFileError(); - } - break; - - case kNotifyFileRead: - Read( - fileOp->data.read.offset, - fileOp->data.read.buffer, - fileOp->data.read.bytes - ); - break; - - case kNotifyFileWrite: - Write( - fileOp->data.write.offset, - fileOp->data.write.buffer, - fileOp->data.write.bytes - ); - break; - - } - - // Leave our local critical section - m_critSect.Leave(); - - // Dispatch a completion notification - if (fileOp->notify) { - fileOp->data.flush.asyncId = asyncId; - m_notifyProc( - (AsyncFile)this, - fileOp->code, - &fileOp->data.flush, - &m_userState - ); - } - -} - -//=========================================================================== -void CFile::Delete (void * op) { - FileOp * fileOp = (FileOp *)op; - delete fileOp; -} - -//=========================================================================== -void CFile::Read ( - uint64_t offset, - void * buffer, - unsigned bytes -) { - - // Seek to the start of the read - Seek(offset, kFileSeekFromBegin); - - // Perform the read - DWORD bytesRead; - BOOL result = ReadFile( - m_handle, - buffer, - bytes, - &bytesRead, - nil // overlapped - ); - - // Handle errors - if (bytesRead != bytes) - memset((uint8_t *)buffer + bytesRead, 0, bytes - bytesRead); - if ( (!result && (GetLastError() != ERROR_IO_PENDING)) || - (bytesRead != bytes) ) - LogMsg(kLogFatal, "failed: ReadFile"); - -} - -//=========================================================================== -bool CFile::Seek (uint64_t offset, EFileSeekFrom from) { - COMPILER_ASSERT(kFileSeekFromBegin == FILE_BEGIN); - COMPILER_ASSERT(kFileSeekFromCurrent == FILE_CURRENT); - COMPILER_ASSERT(kFileSeekFromEnd == FILE_END); - - LONG low = (LONG)(offset % 0x100000000ul); - LONG high = (LONG)(offset / 0x100000000ul); - uint32_t result = SetFilePointer(m_handle, low, &high, from); - if ((result == (uint32_t)-1) && (GetLastError() != NO_ERROR)) { - LogMsg(kLogFatal, "failed: SetFilePointer"); - return false; - } - else - return true; -} - -//=========================================================================== -void CFile::SetLastWriteTime (uint64_t lastWriteTime) { - COMPILER_ASSERT(sizeof(lastWriteTime) == sizeof(FILETIME)); - SetFileTime(m_handle, nil, nil, (const FILETIME *)&lastWriteTime); -} - -//=========================================================================== -void CFile::Truncate (uint64_t size) { - ASSERT(size != kAsyncFileDontTruncate); - - if (Seek(size, kFileSeekFromBegin) && !SetEndOfFile(m_handle)) - LogMsg(kLogFatal, "failed: SetEndOfFile"); -} - -//=========================================================================== -void CFile::Write ( - uint64_t offset, - const void * buffer, - unsigned bytes -) { - - // Seek to the start of the write - Seek(offset, kFileSeekFromBegin); - - // Perform the write - DWORD bytesWritten; - BOOL result = WriteFile( - m_handle, - buffer, - bytes, - &bytesWritten, - nil // overlapped - ); - - // Handle errors - if ( (!result && (GetLastError() != ERROR_IO_PENDING)) || - (bytesWritten != bytes) ) { - LogMsg(kLogFatal, "failed: WriteFile"); - if (!result && (GetLastError() == ERROR_DISK_FULL)) { - MessageBox(nil, "Disk full!", "Error", MB_ICONSTOP | MB_SYSTEMMODAL); -// DebugDisableLeakChecking(); - ExitProcess(1); - } - } - -} - - -/**************************************************************************** -* -* Exported functions -* -***/ - -//=========================================================================== -void W9xFileClose ( - AsyncFile file, - uint64_t truncateSize -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // If requested, truncate the file - if (truncateSize != kAsyncFileDontTruncate) - object->Truncate(truncateSize); - - // Close the file object - object->Close(); - -} - -//=========================================================================== -AsyncId W9xFileCreateSequence ( - AsyncFile file, - bool notify, - void * param -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // Queue an operation - FileOp * op = new FileOp; - op->code = kNotifyFileSequence; - op->notify = notify; - op->data.flush.param = param; - return object->Queue(op); - -} - -//=========================================================================== -AsyncId W9xFileFlushBuffers ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // Queue an operation - FileOp * op = new FileOp; - op->code = kNotifyFileFlush; - op->notify = notify; - op->data.flush.param = param; - op->data.flush.truncateSize = truncateSize; - // op->data.flush.error filled in upon completion - return object->Queue(op); - -} - -//=========================================================================== -AsyncFile W9xFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -) { - HANDLE fileHandle = CreateFileW( - fullPath, - desiredAccess, - shareModeFlags, - nil, // plSecurityAttributes - openMode, - 0, // attributeFlags - nil // hTemplateFile - ); - *error = AsyncGetLastFileError(); - - if (INVALID_HANDLE_VALUE == fileHandle) - return nil; - - // don't allow users to open devices like "LPT1", etc. - if (GetFileType(fileHandle) != FILE_TYPE_DISK) { - LogMsg(kLogFatal, "failed: !FILE_TYPE_DISK"); - *error = kFileErrorFileNotFound; - CloseHandle(fileHandle); - return nil; - } - - // Get the file size - DWORD sizeHi, sizeLo = GetFileSize(fileHandle, &sizeHi); - if ((sizeLo == (DWORD) -1) && (NO_ERROR != GetLastError())) { - *error = AsyncGetLastFileError(); - LogMsg(kLogFatal, "failed: GetFileSize"); - CloseHandle(fileHandle); - return nil; - } - const uint64_t size = ((uint64_t) sizeHi << (uint64_t) 32) | (uint64_t) sizeLo; - - uint64_t lastWriteTime; - ASSERT(sizeof(lastWriteTime) >= sizeof(FILETIME)); - GetFileTime(fileHandle, nil, nil, (FILETIME *) &lastWriteTime); - - // Create a file object - CFile * object = new CFile( - fileHandle, - notifyProc, - userState - ); - - // return out parameters - if (fileSize) - *fileSize = size; - if (fileLastWriteTime) - *fileLastWriteTime = lastWriteTime; - return (AsyncFile)object; -} - -//=========================================================================== -AsyncId W9xFileRead ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // Perform synchronous operations immediately - if (flags & kAsyncFileRwSync) { - object->Read(offset, buffer, bytes); - return 0; - } - - // Queue asynchronous operations - else { - FileOp * op = new FileOp; - op->code = kNotifyFileRead; - op->notify = (flags & kAsyncFileRwNotify) != 0; - op->data.read.param = param; - op->data.read.offset = offset; - op->data.read.buffer = (uint8_t *)buffer; - op->data.read.bytes = bytes; - return object->Queue(op); - } - -} - -//=========================================================================== -void W9xFileSetLastWriteTime ( - AsyncFile file, - uint64_t lastWriteTime -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // Set the file time - object->SetLastWriteTime(lastWriteTime); - -} - -//=========================================================================== -uint64_t W9xFileGetLastWriteTime ( - const wchar_t fileName[] -) { - WIN32_FILE_ATTRIBUTE_DATA info; - bool f = GetFileAttributesExW(fileName, GetFileExInfoStandard, &info); - return f ? *((uint64_t *) &info.ftLastWriteTime) : 0; -} - -//=========================================================================== -AsyncId W9xFileWrite ( - AsyncFile file, - uint64_t offset, - const void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - - // Dereference the object - CFile * object = (CFile *)file; - - // Perform synchronous operations immediately - if (flags & kAsyncFileRwSync) { - object->Write(offset, buffer, bytes); - return 0; - } - - // Queue asynchronous operations - else { - FileOp * op = new FileOp; - op->code = kNotifyFileWrite; - op->notify = (flags & kAsyncFileRwNotify) != 0; - op->data.write.param = param; - op->data.write.offset = offset; - op->data.write.buffer = (uint8_t *)buffer; - op->data.write.bytes = bytes; - return object->Queue(op); - } - -} - -//============================================================================ -bool W9xFileSeek ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom from -) { - CFile * object = (CFile *)file; - return object->Seek(distance, from); -} - - -} // namespace W9x diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xInt.h b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xInt.h index f8668c1b..d518dbe1 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xInt.h +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xInt.h @@ -86,61 +86,6 @@ bool W9xThreadWaitId ( AsyncId asyncId, unsigned timeoutMs ); - -AsyncFile W9xFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -); -void W9xFileClose ( - AsyncFile file, - uint64_t truncateSize -); -void W9xFileSetLastWriteTime ( - AsyncFile file, - uint64_t lastWriteTime -); -uint64_t W9xFileGetLastWriteTime ( - const wchar_t fileName[] -); -AsyncId W9xFileFlushBuffers ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -); -AsyncId W9xFileRead ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -); -AsyncId W9xFileWrite ( - AsyncFile file, - uint64_t offset, - const void *buffer, - unsigned bytes, - unsigned flags, - void * param -); -AsyncId W9xFileCreateSequence ( - AsyncFile file, - bool notify, - void * param -); -bool W9xFileSeek ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom from -); void W9xSocketConnect ( AsyncCancelId * cancelId, const NetAddress & netAddr, diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/pnAceInt.h b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/pnAceInt.h index 3a2d274b..83270e82 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/pnAceInt.h +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/pnAceInt.h @@ -103,76 +103,6 @@ typedef void (* FSignalShutdown) (); typedef void (* FWaitForShutdown) (); typedef void (* FSleep) (unsigned sleepMs); -// Files -typedef AsyncFile (* FAsyncFileOpen) ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -); - -typedef void (* FAsyncFileClose) ( - AsyncFile file, - uint64_t truncateSize -); - -typedef void (* FAsyncFileSetLastWriteTime) ( - AsyncFile file, - uint64_t lastWriteTime -); - -typedef uint64_t (* FAsyncFileGetLastWriteTime) ( - const wchar_t fileName[] -); - -typedef AsyncId (* FAsyncFileFlushBuffers) ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -); - -typedef AsyncId (* FAsyncFileRead) ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -); - -typedef AsyncId (* FAsyncFileWrite) ( - AsyncFile file, - uint64_t offset, - const void * buffer, - unsigned bytes, - unsigned flags, - void * param -); - -typedef AsyncId (* FAsyncFileCreateSequence) ( - AsyncFile file, - bool notify, - void * param -); - -typedef bool (* FAsyncFileSeek) ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom from -); - -typedef bool (* FAsyncFileWaitId) ( - AsyncFile file, - AsyncId asyncId, - unsigned timeoutMs -); - // Sockets typedef void (* FAsyncSocketConnect) ( AsyncCancelId * cancelId, @@ -252,17 +182,6 @@ struct AsyncApi { FWaitForShutdown waitForShutdown; FSleep sleep; - // Files - FAsyncFileOpen fileOpen; - FAsyncFileClose fileClose; - FAsyncFileRead fileRead; - FAsyncFileWrite fileWrite; - FAsyncFileFlushBuffers fileFlushBuffers; - FAsyncFileSetLastWriteTime fileSetLastWriteTime; - FAsyncFileGetLastWriteTime fileGetLastWriteTime; - FAsyncFileCreateSequence fileCreateSequence; - FAsyncFileSeek fileSeek; - // Sockets FAsyncSocketConnect socketConnect; FAsyncSocketConnectCancel socketConnectCancel; diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceIo.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceIo.cpp index cf4d78c2..bd4ef8d1 100644 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceIo.cpp +++ b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceIo.cpp @@ -203,179 +203,6 @@ static unsigned GetConnHash ( * ***/ -//=========================================================================== -EFileError AsyncGetLastFileError () { - const unsigned error = GetLastError(); - switch (error) { - - case NO_ERROR: - return kFileSuccess; - - case ERROR_FILE_NOT_FOUND: - return kFileErrorFileNotFound; - - case ERROR_ACCESS_DENIED: - case ERROR_FILE_EXISTS: - case ERROR_ALREADY_EXISTS: - return kFileErrorAccessDenied; - - case ERROR_SHARING_VIOLATION: - return kFileErrorSharingViolation; - - case ERROR_BAD_NETPATH: - case ERROR_PATH_NOT_FOUND: - case ERROR_INVALID_NAME: - case ERROR_BAD_NET_NAME: - case ERROR_CANT_ACCESS_DOMAIN_INFO: - case ERROR_NETWORK_UNREACHABLE: - case ERROR_HOST_UNREACHABLE: - return kFileErrorPathNotFound; - } - - LogMsg(kLogPerf, "Unexpected Win32 error [%#x]", error); - - return kFileErrorPathNotFound; -} - -//============================================================================ -const wchar_t * FileErrorToString (EFileError error) { - - static wchar_t * s_fileErrorStrings[] = { - L"FileSuccess", - L"FileErrorInvalidParameter", - L"FileErrorFileNotFound", - L"FileErrorPathNotFound", - L"FileErrorAccessDenied", - L"FileErrorSharingViolation", - }; - COMPILER_ASSERT(kNumFileErrors == arrsize(s_fileErrorStrings)); - - return s_fileErrorStrings[error]; -} - -//============================================================================ -AsyncFile AsyncFileOpen ( - const wchar_t fullPath[], - FAsyncNotifyFileProc notifyProc, - EFileError * error, - unsigned desiredAccess, - unsigned openMode, - unsigned shareModeFlags, - void * userState, - uint64_t * fileSize, - uint64_t * fileLastWriteTime -) { - ASSERT(g_api.fileOpen); - return g_api.fileOpen( - fullPath, - notifyProc, - error, - desiredAccess, - openMode, - shareModeFlags, - userState, - fileSize, - fileLastWriteTime - ); -} - -//============================================================================ -void AsyncFileClose ( - AsyncFile file, - uint64_t truncateSize -) { - ASSERT(g_api.fileClose); - g_api.fileClose(file, truncateSize); -} - -//============================================================================ -void AsyncFileSetLastWriteTime ( - AsyncFile file, - uint64_t lastWriteTime -) { - ASSERT(g_api.fileSetLastWriteTime); - g_api.fileSetLastWriteTime(file, lastWriteTime); -} - -//============================================================================ -uint64_t AsyncFileGetLastWriteTime ( - const wchar_t fileName[] -) { - ASSERT(g_api.fileGetLastWriteTime); - return g_api.fileGetLastWriteTime(fileName); -} - -//============================================================================ -AsyncId AsyncFileFlushBuffers ( - AsyncFile file, - uint64_t truncateSize, - bool notify, - void * param -) { - ASSERT(g_api.fileFlushBuffers); - return g_api.fileFlushBuffers(file, truncateSize, notify, param); -} - -//============================================================================ -AsyncId AsyncFileRead ( - AsyncFile file, - uint64_t offset, - void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - ASSERT(g_api.fileRead); - return g_api.fileRead( - file, - offset, - buffer, - bytes, - flags, - param - ); -} - -//============================================================================ -AsyncId AsyncFileWrite ( - AsyncFile file, - uint64_t offset, - const void * buffer, - unsigned bytes, - unsigned flags, - void * param -) { - ASSERT(g_api.fileWrite); - return g_api.fileWrite( - file, - offset, - buffer, - bytes, - flags, - param - ); -} - -//============================================================================ -AsyncId AsyncFileCreateSequence ( - AsyncFile file, - bool notify, - void * param -) { - ASSERT(g_api.fileCreateSequence); - return g_api.fileCreateSequence(file, notify, param); -} - -//============================================================================ -bool AsyncFileSeek ( - AsyncFile file, - uint64_t distance, - EFileSeekFrom seekFrom -) { - ASSERT(g_api.fileSeek); - return g_api.fileSeek(file, distance, seekFrom); -} - //=========================================================================== void AsyncSocketConnect ( AsyncCancelId * cancelId, diff --git a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceLog.cpp b/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceLog.cpp deleted file mode 100644 index dfb4584d..00000000 --- a/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceLog.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/pnAceLog.cpp -* -***/ - -#include "Pch.h" -#pragma hdrstop - -#if defined(PLASMA_EXTERNAL_RELEASE) - // If this is an external build then don't write log files - #define ACELOG_NO_LOG_FILES -#endif - - -namespace AsyncLog { - -/**************************************************************************** -* -* Private -* -***/ - -static const unsigned kLogFlushMs = 10 * 1000; - -enum ELogType { -#ifdef SERVER - kLogTypeDebug, - kLogTypePerf, - kLogTypeError, -#else - kLogTypeDebug, -#endif - kNumLogTypes -}; - -static bool s_breakOnErrors; -static wchar_t s_directory[MAX_PATH]; -static CCritSect s_logCrit[kNumLogTypes]; -static char * s_logBuf[kNumLogTypes]; -static unsigned s_logPos[kNumLogTypes]; -static uint64_t s_logWritePos[kNumLogTypes]; -static TimeDesc s_logTime[kNumLogTypes]; -static unsigned s_logWriteMs[kNumLogTypes]; -static AsyncFile s_logFile[kNumLogTypes]; -static long s_opsPending; -static bool s_running; -static AsyncTimer * s_timer; - -static unsigned s_logSize[kNumLogTypes] = { -#ifdef SERVER - 64 * 1024, - 64 * 1024, - 8 * 1024, -#else - 64 * 1024, -#endif -}; - -static const wchar_t * s_logNameFmt[kNumLogTypes] = { -#ifdef SERVER - L"Dbg%02u%02u%02u.log", - L"Inf%02u%02u%02u.log", - L"Err%02u%02u%02u.log", -#else - L"%s%02u%02u%02u.log", -#endif -}; - -static ELogType s_logSeverityToType[kNumLogSeverity] = { -#ifdef SERVER - kLogTypeDebug, // kLogDebug - kLogTypePerf, // kLogPerf - kLogTypeError, // kLogError - kLogTypeError, // kLogFatal -#else - kLogTypeDebug, // kLogDebug - kLogTypeDebug, // kLogPerf - kLogTypeDebug, // kLogError - kLogTypeDebug, // kLogFatal -#endif -}; - -static char * s_logSeverityToText[kNumLogSeverity] = { - "Debug", - "Info", - "Error", - "Fatal", -}; - - -/**************************************************************************** -* -* Local functions -* -***/ - -//============================================================================ -static void LogFileNotifyProc ( - AsyncFile file, - EAsyncNotifyFile code, - AsyncNotifyFile * notify, - void ** userState -) { - switch (code) { - case kNotifyFileWrite: - free(notify->param); - AtomicAdd(&s_opsPending, -1); - break; - - case kNotifyFileFlush: - AsyncFileClose(file, kAsyncFileDontTruncate); - AtomicAdd(&s_opsPending, -1); - break; - - DEFAULT_FATAL(code); - } -} - -//============================================================================ -static void AllocLogBuffer_CS (unsigned index) { - ASSERT(!s_logBuf[index]); - s_logBuf[index] = (char *)malloc(s_logSize[index]); - s_logPos[index] = 0; - - if (!s_logBuf[index]) - ErrorAssert(__LINE__, __FILE__, "Out of memory"); -} - -//============================================================================ -static void FreeLogBuffer_CS (unsigned index) { - if (s_logBuf[index]) { - free(s_logBuf[index]); - s_logBuf[index] = nil; - } -} - -//============================================================================ -static void GetLogFilename ( - unsigned index, - TimeDesc timeDesc, - wchar_t * filename, - unsigned chars -) { - StrPrintf( - filename, - chars, - s_logNameFmt[index], -#ifndef SERVER - ProductShortName(), -#endif - timeDesc.year % 100, - timeDesc.month, - timeDesc.day - ); - PathAddFilename(filename, s_directory, filename, chars); -} - -//============================================================================ -static bool OpenLogFile_CS (unsigned index) { - if (s_logFile[index] != nil) - return true; - - // Build filename - wchar_t filename[MAX_PATH]; - GetLogFilename( - index, - s_logTime[index], - filename, - arrsize(filename) - ); - - // Open file - uint64_t fileTime; - EFileError fileError; - bool fileExist = PathDoesFileExist(filename); - s_logFile[index] = AsyncFileOpen( - filename, - LogFileNotifyProc, - &fileError, - kAsyncFileWriteAccess, - kAsyncFileModeOpenAlways, - kAsyncFileShareRead, - nil, // userState - &s_logWritePos[index], - &fileTime - ); - - if (s_logFile[index] == nil) - return false; - - TimeGetDesc(fileTime, &s_logTime[index]); - s_logWriteMs[index] = TimeGetMs(); - - // Seek to end of file - AsyncFileSeek(s_logFile[index], s_logWritePos[index], kFileSeekFromBegin); - - // If this is a new file, write uint8_t Order Mark - if (!fileExist) { - static const char s_bom[] = "\xEF\xBB\xBF"; - AsyncFileWrite( - s_logFile[index], - s_logWritePos[index], - s_bom, - arrsize(s_bom)- 1, - kAsyncFileRwSync, // perform blocking write - nil // param - ); - s_logWritePos[index] += arrsize(s_bom) - 1; - } - - // Write a sentinel in case there are multiple runs in one day - static const char s_logOpened[] = "Log Opened\r\n"; - AsyncFileWrite( - s_logFile[index], - s_logWritePos[index], - s_logOpened, - arrsize(s_logOpened)- 1, - kAsyncFileRwSync, // perform blocking write - nil - ); - s_logWritePos[index] += arrsize(s_logOpened) - 1; - - return true; -} - -//============================================================================ -static void WriteLogFile_CS (unsigned index, bool close) { - unsigned flags = kAsyncFileRwSync; // kAsyncFileRwNotify - if (s_logPos[index]) { - if (OpenLogFile_CS(index)) { - AsyncFileWrite( - s_logFile[index], - s_logWritePos[index], - s_logBuf[index], - s_logPos[index], - flags, - s_logBuf[index] - ); - if (flags == kAsyncFileRwSync) - delete s_logBuf[index]; - else - AtomicAdd(&s_opsPending, 1); - s_logWritePos[index] += s_logPos[index]; - s_logWriteMs[index] = TimeGetMs(); - s_logBuf[index] = nil; - s_logPos[index] = 0; - } - } - - if (close && s_logFile[index]) { - if (flags == kAsyncFileRwNotify) { - AtomicAdd(&s_opsPending, 1); - AsyncFileFlushBuffers( - s_logFile[index], - kAsyncFileDontTruncate, - true, - nil - ); - } - else { - AsyncFileClose( - s_logFile[index], - kAsyncFileDontTruncate - ); - } - s_logFile[index] = nil; - } -} - -//============================================================================ -static void FlushLogFile_CS ( - unsigned index, - TimeDesc timeDesc -) { - bool close = !s_running || (s_logTime[index].day != timeDesc.day); - WriteLogFile_CS(index, close); - if (close) - s_logTime[index] = timeDesc; -} - -//============================================================================ -static unsigned FlushLogsTimerCallback (void *) { - AsyncLogFlush(); - return kAsyncTimeInfinite; -} - - -} using namespace AsyncLog; - - -/**************************************************************************** -* -* Exported functions -* -***/ - -//============================================================================ -void AsyncLogInitialize ( - const wchar_t logDirName[], - bool breakOnErrors -) { - s_running = true; - - // Save options - s_breakOnErrors = breakOnErrors; - - // Build log directory name -#ifdef SERVER - PathGetProgramDirectory(s_directory, arrsize(s_directory)); -#else - PathGetUserDirectory(s_directory, arrsize(s_directory)); -#endif - PathAddFilename(s_directory, s_directory, logDirName, arrsize(s_directory)); - -#ifndef ACELOG_NO_LOG_FILES - // Create log directory - if (kPathCreateDirSuccess != PathCreateDirectory(s_directory, 0)) - PathRemoveFilename(s_directory, s_directory, arrsize(s_directory)); - - // Allocate log buffers - for (unsigned index = 0; index < kNumLogTypes; ++index) { - s_logCrit[index].Enter(); - AllocLogBuffer_CS(index); - s_logCrit[index].Leave(); - } - - AsyncTimerCreate(&s_timer, FlushLogsTimerCallback, kAsyncTimeInfinite, nil); -#endif // ndef ACELOG_NO_LOG_FILES -} - -//============================================================================ -void AsyncLogDestroy () { - s_running = false; - -#ifndef ACELOG_NO_LOG_FILES - AsyncTimerDelete(s_timer, kAsyncTimerDestroyWaitComplete); - - for (unsigned index = 0; index < kNumLogTypes; ++index) { - s_logCrit[index].Enter(); - { - WriteLogFile_CS(index, true); - FreeLogBuffer_CS(index); - } - s_logCrit[index].Leave(); - } - while (s_opsPending) - AsyncSleep(10); -#endif // ndef ACELOG_NO_LOG_FILES -} - -//============================================================================ -void AsyncLogFlush () { -#ifndef ACELOG_NO_LOG_FILES - TimeDesc timeDesc; - TimeGetDesc(TimeGetTime(), &timeDesc); - - for (unsigned index = 0; index < kNumLogTypes; ++index) { - s_logCrit[index].Enter(); - FlushLogFile_CS(index, timeDesc); - s_logCrit[index].Leave(); - } -#endif // ndef ACELOG_NO_LOG_FILES -} - -//============================================================================ -void LogBreakOnErrors (bool breakOnErrors) { - s_breakOnErrors = breakOnErrors; -} - -//============================================================================ -void AsyncLogWriteMsg ( - const wchar_t facility[], - ELogSeverity severity, - const wchar_t msg[] -) { - if (!s_running) - return; - -#ifndef ACELOG_NO_LOG_FILES - TimeDesc timeDesc; - TimeGetDesc(TimeGetTime(), &timeDesc); - - char buffer[2048]; - const unsigned chars = StrPrintf( - buffer, - arrsize(buffer), - "%02u/%02u/%02u % 2u:%02u:%02u [%S] %s %S\r\n", - timeDesc.month, - timeDesc.day, - timeDesc.year % 100, - timeDesc.hour, - timeDesc.minute, - timeDesc.second, - facility, - s_logSeverityToText[severity], - msg - ); - - unsigned index = s_logSeverityToType[severity]; - s_logCrit[index].Enter(); - { - // If day changed then write and flush file - if (s_logTime[index].day != timeDesc.day) - FlushLogFile_CS(index, timeDesc); - // Otherwise if the buffer is full then write to file - else if (s_logPos[index] + chars > s_logSize[index]) - WriteLogFile_CS(index, false); - - // Allocate log buffer if necessary - if (!s_logBuf[index]) - AllocLogBuffer_CS(index); - - // Add new data to the log buffer - memcpy(s_logBuf[index] + s_logPos[index], buffer, chars); - s_logPos[index] += chars; - - // Write, flush and close file immediately if this is a fatal error - if (severity == kLogFatal) - WriteLogFile_CS(index, true); - - // Drop to debugger if this is an error msg and that option was specified - if (s_breakOnErrors && severity >= kLogError) - DebugBreakIfDebuggerPresent(); - } - s_logCrit[index].Leave(); - - // Queue flush - AsyncTimerUpdate(s_timer, kLogFlushMs, kAsyncTimerUpdateSetPriorityHigher); -#endif // ndef ACELOG_NO_LOG_FILES -} - -//============================================================================ -void AsyncLogGetDirectory (wchar_t * dest, unsigned destChars) { - ASSERT(dest); - StrCopy(dest, s_directory, destChars); -} diff --git a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp index b817fbae..fb403161 100644 --- a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp @@ -151,15 +151,6 @@ static NetCommMsgHandler s_defaultHandler(0, nil, nil); static NetCommMsgHandler s_preHandler(0, nil, nil); -//============================================================================ -static void INetLogCallback ( - ELogSeverity severity, - const wchar_t msg[] -) { - // Use the async log facility - AsyncLogWriteMsg(ProductShortName(), severity, msg); -} - //============================================================================ static void INetErrorCallback ( ENetProtocol protocol, @@ -755,9 +746,7 @@ void NetCommChangeMyPassword ( void NetCommStartup () { s_shutdown = false; - LogRegisterHandler(INetLogCallback); AsyncCoreInitialize(); - AsyncLogInitialize(L"Log", false); wchar_t productString[256]; ProductString(productString, arrsize(productString)); LogMsg(kLogPerf, L"Client: %s", productString); @@ -797,9 +786,7 @@ void NetCommShutdown () { NetCliFileDisconnect(); NetClientDestroy(false); - AsyncLogDestroy(); AsyncCoreDestroy(30 * 1000); - LogUnregisterHandler(INetLogCallback); } //============================================================================ diff --git a/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.cpp b/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.cpp index b5551283..0a940a80 100644 --- a/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.cpp +++ b/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.cpp @@ -45,7 +45,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsTemplates.h" -plLoggable::~plLoggable() +plLoggable::~plLoggable() { IDeleteLog(); } @@ -53,7 +53,7 @@ plLoggable::~plLoggable() void plLoggable::IDeleteLog() { if ( fWeCreatedLog ) - delete fStatusLog; + delete fStatusLog; fWeCreatedLog = false; fStatusLog = nil; } @@ -86,13 +86,20 @@ void plLoggable::SetLog( plStatusLog * log, bool deleteOnDestruct/*=false */) bool plLoggable::Log( const char * str ) const { - if ( !str || strlen( str )==0 ) + return Log(plString::FromUtf8(str)); +} + +bool plLoggable::Log(const plString& str) const +{ + if (str.IsNull() || str.IsEmpty()) { return true; + } GetLog(); - if ( fStatusLog ) - return fStatusLog->AddLine( str ); + if (fStatusLog) { + return fStatusLog->AddLine(str.c_str()); + } return true; } @@ -101,60 +108,75 @@ bool plLoggable::LogF( const char * fmt, ... ) const { va_list args; va_start(args, fmt); - return Log( xtl::formatv( fmt, args ).c_str() ); + bool ret = Log(plString::IFormat(fmt, args)); + va_end(args); + + return ret; } bool plLoggable::LogV( const char * fmt, va_list args ) const { - return Log( xtl::formatv( fmt, args ).c_str() ); + return Log(plString::IFormat(fmt, args)); } -bool plLoggable::DebugMsgV(const char* fmt, va_list args) const +bool plLoggable::DebugMsgV(const char* fmt, va_list args) const { - return LogF("DBG: %s", xtl::formatv(fmt,args).c_str()); + return Log(_TEMP_CONVERT_FROM_LITERAL("DBG: ") + plString::IFormat(fmt, args)); } -bool plLoggable::ErrorMsgV(const char* fmt, va_list args) const +bool plLoggable::ErrorMsgV(const char* fmt, va_list args) const { - return LogF("ERR: %s", xtl::formatv(fmt,args).c_str()); + return Log(_TEMP_CONVERT_FROM_LITERAL("ERR: ") + plString::IFormat(fmt, args)); } -bool plLoggable::WarningMsgV(const char* fmt, va_list args) const +bool plLoggable::WarningMsgV(const char* fmt, va_list args) const { - return LogF("WRN: %s", xtl::formatv(fmt,args).c_str()); + return Log(_TEMP_CONVERT_FROM_LITERAL("WRN: ") + plString::IFormat(fmt, args)); } -bool plLoggable::AppMsgV(const char* fmt, va_list args) const +bool plLoggable::AppMsgV(const char* fmt, va_list args) const { - return LogF("APP: %s", xtl::formatv(fmt,args).c_str()); + return Log(_TEMP_CONVERT_FROM_LITERAL("APP: ") + plString::IFormat(fmt, args)); } /////////////////////////////////////////////////////////////// -bool plLoggable::DebugMsg(const char* fmt, ...) const +bool plLoggable::DebugMsg(const char* fmt, ...) const { va_list args; va_start(args, fmt); - return DebugMsgV(fmt, args); + bool ret = DebugMsgV(fmt, args); + va_end(args); + + return ret; } -bool plLoggable::ErrorMsg(const char* fmt, ...) const +bool plLoggable::ErrorMsg(const char* fmt, ...) const { va_list args; va_start(args, fmt); - return ErrorMsgV(fmt, args); + bool ret = ErrorMsgV(fmt, args); + va_end(args); + + return ret; } -bool plLoggable::WarningMsg(const char* fmt, ...) const +bool plLoggable::WarningMsg(const char* fmt, ...) const { va_list args; va_start(args, fmt); - return WarningMsgV(fmt, args); + bool ret = WarningMsgV(fmt, args); + va_end(args); + + return ret; } -bool plLoggable::AppMsg(const char* fmt, ...) const +bool plLoggable::AppMsg(const char* fmt, ...) const { va_list args; va_start(args, fmt); - return AppMsgV(fmt, args); + bool ret = AppMsgV(fmt, args); + va_end(args); + + return ret; } diff --git a/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.h b/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.h index 25e86efc..204b0c3a 100644 --- a/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.h +++ b/Sources/Plasma/PubUtilLib/plStatusLog/plLoggable.h @@ -44,6 +44,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include #include "HeadSpin.h" +#include "plString.h" // // An abstract base class which contains a status log and simple functions @@ -66,10 +67,11 @@ public: plStatusLog* GetLog() const; void SetLog( plStatusLog * log, bool deleteOnDestruct=false ); - + // logging virtual bool Log( const char * str ) const; + virtual bool Log(const plString& str) const; virtual bool LogF( const char * fmt, ... ) const; virtual bool LogV( const char * fmt, va_list args ) const; virtual bool ErrorMsgV(const char* fmt, va_list args) const ; diff --git a/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.cpp b/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.cpp index ed1f488d..dd908352 100644 --- a/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.cpp +++ b/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.cpp @@ -70,10 +70,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plEncryptLogLine.h" -#if HS_BUILD_FOR_UNIX - #include - #define MAX_PATH PATH_MAX -#elif HS_BUILD_FOR_WIN32 +#if HS_BUILD_FOR_WIN32 #include #endif @@ -411,6 +408,7 @@ uint32_t plStatusLog::fLoggingOff = false; plStatusLog::plStatusLog( uint8_t numDisplayLines, const wchar_t *filename, uint32_t flags ) { fFileHandle = nil; + fSema = nil; fSize = 0; fForceLog = false; @@ -421,12 +419,16 @@ plStatusLog::plStatusLog( uint8_t numDisplayLines, const wchar_t *filename, uint char* temp = hsWStringToString(filename); fCFilename = temp; delete [] temp; + + fSema = new hsSemaphore(1, fCFilename.c_str()); } else { fFilename = L""; fCFilename = ""; flags |= kDontWriteFile; + + fSema = new hsSemaphore(1); } fOrigFlags = fFlags = flags; @@ -532,6 +534,9 @@ void plStatusLog::IFini( void ) for( i = 0; i < fMaxNumLines; i++ ) delete [] fLines[ i ]; + if (fSema) + delete fSema; + delete [] fLines; delete [] fColors; } @@ -601,7 +606,7 @@ bool plStatusLog::IAddLine( const char *line, int32_t count, uint32_t color ) return true; /// Scroll pointers up - hsTempMutexLock lock( fMutex ); + fSema->Wait(); bool ret = true; @@ -649,6 +654,8 @@ bool plStatusLog::IAddLine( const char *line, int32_t count, uint32_t color ) ret = IPrintLineToFile( line, count ); } + fSema->Signal(); + return ret; } diff --git a/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.h b/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.h index 965fc74b..82b6ba6f 100644 --- a/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.h +++ b/Sources/Plasma/PubUtilLib/plStatusLog/plStatusLog.h @@ -82,16 +82,16 @@ class plStatusLog mutable uint32_t fFlags; // Mutable so we can change it in IPrintLineToFile() internally uint32_t fOrigFlags; - uint32_t fMaxNumLines; - std::string fCFilename; // used ONLY by GetFileName() + uint32_t fMaxNumLines; + std::string fCFilename; // used ONLY by GetFileName() std::wstring fFilename; - char **fLines; - uint32_t *fColors; - hsMutex fMutex; // To make multithreaded-safe - FILE* fFileHandle; - uint32_t fSize; - bool fEncryptMe; - bool fForceLog; + char** fLines; + uint32_t* fColors; + hsSemaphore* fSema; + FILE* fFileHandle; + uint32_t fSize; + bool fEncryptMe; + bool fForceLog; plStatusLog *fNext, **fBack;