2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

CWE Directory Reorganization

Rearrange directory structure of CWE to be loosely equivalent to
the H'uru Plasma repository.

Part 1: Movement of directories and files.
This commit is contained in:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

View File

@ -0,0 +1,68 @@
/*==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 <http://www.gnu.org/licenses/>.
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/Pch.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PCH_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Pch.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PCH_H
#include "pnUtils/pnUtils.h"
#include "pnProduct/pnProduct.h"
#include "pnNetBase/pnNetBase.h"
#include "pnAsyncCore/pnAsyncCore.h"
#ifdef SERVER
#include "pnCrash/pnCrash.h" // deadlock API
#endif
#include "Private/pnAceInt.h"
#include "Private/W9x/pnAceW9x.h"
#include "Private/Nt/pnAceNt.h"
#include "Private/Unix/pnAceUx.h"
#include <process.h>
#include <malloc.h>

View File

@ -0,0 +1,503 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceNt.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
#include "pnAceNtInt.h"
namespace Nt {
/****************************************************************************
*
* Private data
*
***/
// Use non-allocated arrays for worker threads since they're used so frequently.
const unsigned kMaxWorkerThreads = 32; // handles 8-processor computer w/hyperthreading
static bool s_running;
static HANDLE s_waitEvent;
static long s_ioThreadCount;
static HANDLE s_ioThreadHandles[kMaxWorkerThreads];
static HANDLE s_ioPort;
static unsigned s_pageSizeMask;
/****************************************************************************
*
* Waitable event handles
*
***/
//===========================================================================
CNtWaitHandle::CNtWaitHandle () {
m_refCount = 1;
m_event = CreateEvent(
(LPSECURITY_ATTRIBUTES) nil,
true, // manual reset
false, // initial state
(LPCTSTR) nil
);
}
//===========================================================================
CNtWaitHandle::~CNtWaitHandle () {
CloseHandle(m_event);
}
//===========================================================================
void CNtWaitHandle::IncRef () {
InterlockedIncrement(&m_refCount);
}
//===========================================================================
void CNtWaitHandle::DecRef () {
if (!InterlockedDecrement(&m_refCount))
DEL(this);
}
//===========================================================================
bool CNtWaitHandle::WaitForObject (unsigned timeMs) const {
return WAIT_TIMEOUT != WaitForSingleObject(m_event, timeMs);
}
//===========================================================================
void CNtWaitHandle::SignalObject () const {
SetEvent(m_event);
}
/****************************************************************************
*
* OPERATIONS
*
***/
//===========================================================================
static void INtOpDispatch (
NtObject * ntObj,
Operation * op,
dword bytes
) {
for (;;) {
switch (op->opType) {
case kOpConnAttempt:
INtSocketOpCompleteSocketConnect((NtOpConnAttempt *) op);
// operation not associated with ntObj so there is no next operation.
// operation has already been deleted by OpCompleteSocketConnect.
return;
case kOpQueuedSocketWrite:
INtSocketOpCompleteQueuedSocketWrite((NtSock *) ntObj, (NtOpSocketWrite *) op);
// operation converted into kOpSocketWrite so we cannot move
// to next operation until write operation completes
return;
case kOpSocketRead:
ASSERT(bytes != (dword) -1);
INtSocketOpCompleteSocketRead((NtSock *) ntObj, bytes);
return;
case kOpSocketWrite:
ASSERT(bytes != (dword) -1);
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 != (dword) -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);
}
// if this operation is not at the head of the list then it can't be completed
// because nextCompleteSequence would be prematurely incremented. Instead
// convert the operation to OP_NULL, which will get completed when it reaches
// the head of the list.
ntObj->critsect.Enter();
if (ntObj->opList.Prev(op)) {
// setting the completion flag must be done inside the critical section
// because it will be checked by sibling operations when they have the
// critical section.
op->pending = 0;
ntObj->critsect.Leave();
return;
}
// complete processing this event, and, since we're still inside the critical
// section, finish all completed operations since we don't have to leave the
// critical section to do so. This is a big win because a single operation
// that takes a long time to complete can backlog a long list of completed ops.
bool continueDispatch;
for (;;) {
// wake up any other threads waiting on this event
CNtWaitHandle * signalComplete = op->signalComplete;
op->signalComplete = nil;
// since this operation is at the head of the list we can complete it
if (op->asyncId && !++ntObj->nextCompleteSequence)
++ntObj->nextCompleteSequence;
Operation * next = ntObj->opList.Next(op);
ntObj->opList.Delete(op);
op = next;
// set event *after* operation is complete
if (signalComplete) {
signalComplete->SignalObject();
signalComplete->DecRef();
}
// if we just deleted the last operation then stop dispatching
if (!op) {
continueDispatch = false;
break;
}
// opTypes >= kOpSequence complete when they reach the head of the list
continueDispatch = op->opType >= kOpSequence;
if (op->pending)
break;
InterlockedDecrement(&ntObj->ioCount);
}
ntObj->critsect.Leave();
INtConnCompleteOperation(ntObj);
if (!continueDispatch)
break;
// certain operations which depend upon the value of bytes (reads & writes)
// can only be dispatched when they are completed normally. To ensure that
// we're not accidentally processing an operation that shouldn't be executed,
// set the bytes field to an invalid value.
bytes = (dword) -1;
}
}
//===========================================================================
static unsigned THREADCALL NtWorkerThreadProc (AsyncThread * thread) {
REF(thread);
ThreadDenyBlock();
unsigned sleepMs = INFINITE;
while (s_running) {
// process I/O operations
{
dword bytes;
NtObject * ntObj;
Operation * op;
(void) GetQueuedCompletionStatus(
s_ioPort,
&bytes,
#ifdef _WIN64
(PULONG_PTR) &ntObj,
#else
(LPDWORD) &ntObj,
#endif
(LPOVERLAPPED *) &op,
sleepMs
);
if (op) {
// Queue for deadlock detection
#ifdef SERVER
void * check = CrashAddDeadlockCheck(thread->handle, L"pnAceNt.NtWorkerThread");
#endif
// Dispatch event to app
INtOpDispatch(ntObj, op, bytes);
// Unqueue from deadlock detection
#ifdef SERVER
CrashRemoveDeadlockCheck(check);
#endif
sleepMs = 0;
continue;
}
}
sleepMs = INFINITE;
continue;
}
return 0;
}
/****************************************************************************
*
* Module functions
*
***/
//===========================================================================
void INtConnPostOperation (NtObject * ntObj, Operation * op, unsigned bytes) {
PostQueuedCompletionStatus(
s_ioPort,
bytes,
#ifdef _WIN64
(ULONG_PTR) ntObj,
#else
(DWORD) ntObj,
#endif
&op->overlapped
);
}
//===========================================================================
AsyncId INtConnSequenceStart (NtObject * ntObj) {
unsigned result;
if (0 == (result = ++ntObj->nextStartSequence))
result = ++ntObj->nextStartSequence;
return (AsyncId) result;
}
//===========================================================================
bool INtConnInitialize (NtObject * ntObj) {
if (!CreateIoCompletionPort(ntObj->handle, s_ioPort, (DWORD) ntObj, 0)) {
LogMsg(kLogFatal, "CreateIoCompletionPort failed");
return false;
}
return true;
}
//===========================================================================
void INtConnCompleteOperation (NtObject * ntObj) {
// are we completing the last operation for this object?
if (InterlockedDecrement(&ntObj->ioCount))
return;
DWORD err = GetLastError();
REF(err);
switch (ntObj->ioType) {
case kNtFile:
INtFileDelete((NtFile *) ntObj);
break;
case kNtSocket:
INtSockDelete((NtSock *) ntObj);
break;
default:
LogMsg(kLogError, "NtConnCompleteOp %p %u", ntObj, ntObj->ioType);
break;
}
}
/*****************************************************************************
*
* Module exports
*
***/
//===========================================================================
void NtInitialize () {
// ensure initialization only occurs once
if (s_running)
return;
s_running = true;
// create a cleanup event
s_waitEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) 0,
true, // manual reset
false, // initial state off
(LPCTSTR) nil // name
);
if (!s_waitEvent)
ErrorFatal(__LINE__, __FILE__, "CreateEvent %#x", GetLastError());
// create IO completion port
if (0 == (s_ioPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)))
ErrorFatal(__LINE__, __FILE__, "CreateIoCompletionPort %#x", GetLastError());
// calculate number of IO worker threads to create
if (!s_pageSizeMask) {
SYSTEM_INFO si;
GetSystemInfo(&si);
s_pageSizeMask = si.dwPageSize - 1;
// Set worker thread count
s_ioThreadCount = si.dwNumberOfProcessors * 2;
if (s_ioThreadCount > kMaxWorkerThreads) {
s_ioThreadCount = kMaxWorkerThreads;
LogMsg(kLogError, "kMaxWorkerThreads too small!");
}
}
// create IO worker threads
for (long thread = 0; thread < s_ioThreadCount; thread++) {
s_ioThreadHandles[thread] = (HANDLE) AsyncThreadCreate(
NtWorkerThreadProc,
(void *) thread,
L"NtWorkerThread"
);
}
INtFileInitialize();
INtSocketInitialize();
}
//===========================================================================
// DANGER: calling this function will slam closed any files which are still open.
// MOST PROGRAMS DO NOT NEED TO CALL THIS FUNCTION. In general, the best way to
// 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
s_running = false;
if (s_ioPort) {
// Post a completion notification to worker threads to wake them up
long thread;
for (thread = 0; thread < s_ioThreadCount; thread++)
PostQueuedCompletionStatus(s_ioPort, 0, 0, 0);
// Close each thread
for (thread = 0; thread < s_ioThreadCount; thread++) {
if (s_ioThreadHandles[thread]) {
WaitForSingleObject(s_ioThreadHandles[thread], exitThreadWaitMs);
CloseHandle(s_ioThreadHandles[thread]);
s_ioThreadHandles[thread] = nil;
}
}
// Cleanup port
CloseHandle(s_ioPort);
s_ioPort = 0;
}
if (s_waitEvent) {
CloseHandle(s_waitEvent);
s_waitEvent = 0;
}
INtFileDestroy();
INtSocketDestroy();
}
//===========================================================================
void NtSignalShutdown () {
SetEvent(s_waitEvent);
}
//===========================================================================
void NtWaitForShutdown () {
if (s_waitEvent)
WaitForSingleObject(s_waitEvent, INFINITE);
}
} using namespace Nt;
/****************************************************************************
*
* Public exports
*
***/
//===========================================================================
void NtGetApi (AsyncApi * api) {
api->initialize = NtInitialize;
api->destroy = NtDestroy;
api->signalShutdown = NtSignalShutdown;
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;
api->socketDelete = NtSocketDelete;
api->socketSend = NtSocketSend;
api->socketWrite = NtSocketWrite;
api->socketSetNotifyProc = NtSocketSetNotifyProc;
api->socketSetBacklogAlloc = NtSocketSetBacklogAlloc;
api->socketStartListening = NtSocketStartListening;
api->socketStopListening = NtSocketStopListening;
api->socketEnableNagling = NtSocketEnableNagling;
}

View File

@ -0,0 +1,64 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceNt.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_NT_PNACENT_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNt.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_NT_PNACENT_H
#ifdef HS_BUILD_FOR_WIN32
/****************************************************************************
*
* Nt API functions
*
***/
void NtGetApi (AsyncApi * api);
#endif // HS_BUILD_FOR_WIN32

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,336 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceNtInt.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_NT_PNACENTINT_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Nt/pnAceNtInt.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_NT_PNACENTINT_H
namespace Nt {
/****************************************************************************
*
* Type definitions
*
***/
enum EIoType {
kNtFile,
kNtSocket,
kIoTypes
};
enum EOpType {
// Completed by GetQueuedCompletionStatus
kOpConnAttempt,
kOpSocketRead,
kOpSocketWrite,
kOpFileRead,
kOpFileWrite,
// opType >= kOpSequence complete when they reach the head of the list
kOpSequence,
kOpFileFlush,
kOpQueuedFileRead,
kOpQueuedFileWrite,
kOpQueuedSocketWrite,
kNumOpTypes
};
class CNtCritSect : public CCritSect {
public:
BOOL TryEnter () { return TryEnterCriticalSection(&m_handle); }
};
class CNtWaitHandle {
long m_refCount;
HANDLE m_event;
public:
CNtWaitHandle ();
~CNtWaitHandle ();
void IncRef ();
void DecRef ();
bool WaitForObject (unsigned timeMs) const;
void SignalObject () const;
};
struct Operation {
OVERLAPPED overlapped;
EOpType opType;
AsyncId asyncId;
bool notify;
unsigned pending;
CNtWaitHandle * signalComplete;
LINK(Operation) link;
#ifdef HS_DEBUGGING
~Operation () {
ASSERT(!signalComplete);
}
#endif
};
struct NtObject {
CNtCritSect critsect;
EIoType ioType;
HANDLE handle;
void * userState;
LISTDECL(Operation, link) opList;
long nextCompleteSequence;
long nextStartSequence;
long ioCount;
bool closed;
};
/****************************************************************************
*
* Nt.cpp internal functions
*
***/
void INtWakeupMainIoThreads ();
void INtConnPostOperation (NtObject * ntObj, Operation * op, unsigned bytes);
AsyncId INtConnSequenceStart (NtObject * ntObj);
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 ();
/*****************************************************************************
*
* NtSocket.cpp internal functions
*
***/
struct NtSock;
struct NtOpConnAttempt;
struct NtOpSocketWrite;
void INtSocketInitialize ();
void INtSocketStartCleanup (unsigned exitThreadWaitMs);
void INtSocketDestroy ();
void INtSockDelete (
NtSock * sock
);
void INtSocketOpCompleteSocketConnect (
NtOpConnAttempt * op
);
void INtSocketOpCompleteSocketRead (
NtSock * sock,
unsigned bytes
);
void INtSocketOpCompleteSocketWrite (
NtSock * sock,
NtOpSocketWrite * op
);
bool INtSocketOpCompleteQueuedSocketWrite (
NtSock * sock,
NtOpSocketWrite * op
);
/*****************************************************************************
*
* NT Async API functions
*
***/
void NtInitialize ();
void NtDestroy (unsigned exitThreadWaitMs);
void NtSignalShutdown ();
void NtWaitForShutdown ();
void NtSleep (unsigned sleepMs);
AsyncFile NtFileOpen (
const wchar fullPath[],
FAsyncNotifyFileProc notifyProc,
EFileError * error,
unsigned desiredAccess,
unsigned openMode,
unsigned shareModeFlags,
void * userState,
qword * fileSize,
qword * fileLastWriteTime
);
void NtFileClose (
AsyncFile file,
qword truncateSize
);
void NtFileSetLastWriteTime (
AsyncFile file,
qword lastWriteTime
);
qword NtFileGetLastWriteTime (
const wchar fileName[]
);
AsyncId NtFileFlushBuffers (
AsyncFile file,
qword truncateSize,
bool notify,
void * param
);
AsyncId NtFileRead (
AsyncFile file,
qword offset,
void * buffer,
unsigned bytes,
unsigned flags,
void * param
);
AsyncId NtFileWrite (
AsyncFile file,
qword offset,
const void *buffer,
unsigned bytes,
unsigned flags,
void * param
);
AsyncId NtFileCreateSequence (
AsyncFile file,
bool notify,
void * param
);
bool NtFileSeek (
AsyncFile file,
qword distance,
EFileSeekFrom from
);
void NtSocketConnect (
AsyncCancelId * cancelId,
const NetAddress & netAddr,
FAsyncNotifySocketProc notifyProc,
void * param,
const void * sendData,
unsigned sendBytes,
unsigned connectMs,
unsigned localPort
);
void NtSocketConnectCancel (
FAsyncNotifySocketProc notifyProc,
AsyncCancelId cancelId
);
void NtSocketDisconnect (
AsyncSocket sock,
bool hardClose
);
void NtSocketDelete (AsyncSocket sock);
bool NtSocketSend (
AsyncSocket sock,
const void * data,
unsigned bytes
);
bool NtSocketWrite (
AsyncSocket sock,
const void * buffer,
unsigned bytes,
void * param
);
void NtSocketSetNotifyProc (
AsyncSocket sock,
FAsyncNotifySocketProc notifyProc
);
void NtSocketSetBacklogAlloc (
AsyncSocket sock,
unsigned bufferSize
);
unsigned NtSocketStartListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
void NtSocketStopListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
void NtSocketEnableNagling (
AsyncSocket conn,
bool enable
);
} // namespace Nt

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceNtThread.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
#include "pnAceNtInt.h"
namespace Nt {
/*****************************************************************************
*
* Module exports
*
***/
//===========================================================================
void NtSleep (unsigned sleepMs) {
ThreadAssertCanBlock(__FILE__, __LINE__);
Sleep(sleepMs);
}
} using namespace Nt;

View File

@ -0,0 +1,64 @@
/*==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 <http://www.gnu.org/licenses/>.
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/Unix/pnAceUx.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_UNIX_PNACEUX_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/Unix/pnAceUx.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_UNIX_PNACEUX_H
#ifdef HS_BUILD_FOR_UNIX
/****************************************************************************
*
* Win9x API functions
*
***/
void UxGetApi (AsyncApi * api);
#endif // HS_BUILD_FOR_UNIX

View File

@ -0,0 +1,91 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceW9x.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
#include "pnAceW9xInt.h"
/****************************************************************************
*
* Exported functions
*
***/
//===========================================================================
void W9xGetApi (AsyncApi * api) {
using namespace W9x;
api->initialize = W9xThreadInitialize;
api->destroy = W9xThreadDestroy;
api->signalShutdown = W9xThreadSignalShutdown;
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;
api->socketDelete = W9xSocketDelete;
api->socketSend = W9xSocketSend;
api->socketWrite = W9xSocketWrite;
api->socketSetNotifyProc = W9xSocketSetNotifyProc;
api->socketSetBacklogAlloc = W9xSocketSetBacklogAlloc;
api->socketStartListening = W9xSocketStartListening;
api->socketStopListening = W9xSocketStopListening;
api->socketEnableNagling = W9xSocketEnableNagling;
}

View File

@ -0,0 +1,64 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceW9x.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_W9X_PNACEW9X_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9x.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_W9X_PNACEW9X_H
#ifdef HS_BUILD_FOR_WIN32
/****************************************************************************
*
* Win9x API functions
*
***/
void W9xGetApi (AsyncApi * api);
#endif // HS_BUILD_FOR_WIN32

View File

@ -0,0 +1,518 @@
/*==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 <http://www.gnu.org/licenses/>.
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 (
qword offset,
void * buffer,
unsigned bytes
);
void SetLastWriteTime (qword lastWriteTime);
void Truncate (qword size);
void Write (
qword offset,
const void * buffer,
unsigned bytes
);
bool Seek (qword 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;
DEL(fileOp);
}
//===========================================================================
void CFile::Read (
qword 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)
MemZero((byte *)buffer + bytesRead, bytes - bytesRead);
if ( (!result && (GetLastError() != ERROR_IO_PENDING)) ||
(bytesRead != bytes) )
LogMsg(kLogFatal, "failed: ReadFile");
}
//===========================================================================
bool CFile::Seek (qword 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);
dword result = SetFilePointer(m_handle, low, &high, from);
if ((result == (dword)-1) && (GetLastError() != NO_ERROR)) {
LogMsg(kLogFatal, "failed: SetFilePointer");
return false;
}
else
return true;
}
//===========================================================================
void CFile::SetLastWriteTime (qword lastWriteTime) {
COMPILER_ASSERT(sizeof(lastWriteTime) == sizeof(FILETIME));
SetFileTime(m_handle, nil, nil, (const FILETIME *)&lastWriteTime);
}
//===========================================================================
void CFile::Truncate (qword size) {
ASSERT(size != kAsyncFileDontTruncate);
if (Seek(size, kFileSeekFromBegin) && !SetEndOfFile(m_handle))
LogMsg(kLogFatal, "failed: SetEndOfFile");
}
//===========================================================================
void CFile::Write (
qword 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,
qword 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,
qword 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 fullPath[],
FAsyncNotifyFileProc notifyProc,
EFileError * error,
unsigned desiredAccess,
unsigned openMode,
unsigned shareModeFlags,
void * userState,
qword * fileSize,
qword * 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 qword size = ((qword) sizeHi << (qword) 32) | (qword) sizeLo;
qword 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,
qword 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 = (byte *)buffer;
op->data.read.bytes = bytes;
return object->Queue(op);
}
}
//===========================================================================
void W9xFileSetLastWriteTime (
AsyncFile file,
qword lastWriteTime
) {
// Dereference the object
CFile * object = (CFile *)file;
// Set the file time
object->SetLastWriteTime(lastWriteTime);
}
//===========================================================================
qword W9xFileGetLastWriteTime (
const wchar fileName[]
) {
WIN32_FILE_ATTRIBUTE_DATA info;
bool f = GetFileAttributesExW(fileName, GetFileExInfoStandard, &info);
return f ? *((qword *) &info.ftLastWriteTime) : 0;
}
//===========================================================================
AsyncId W9xFileWrite (
AsyncFile file,
qword 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 = (byte *)buffer;
op->data.write.bytes = bytes;
return object->Queue(op);
}
}
//============================================================================
bool W9xFileSeek (
AsyncFile file,
qword distance,
EFileSeekFrom from
) {
CFile * object = (CFile *)file;
return object->Seek(distance, from);
}
} // namespace W9x

View File

@ -0,0 +1,197 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceW9xInt.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_W9X_PNACEW9XINT_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/W9x/pnAceW9xInt.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_W9X_PNACEW9XINT_H
namespace W9x {
/*****************************************************************************
*
* Internal types
*
***/
class CThreadDispObject : public AtomicRef {
public:
CThreadDispObject ();
virtual ~CThreadDispObject () { }
void Close ();
virtual void Complete (void * op, CCritSect * critSect, AsyncId asyncId) = 0;
virtual void Delete (void * op) = 0;
AsyncId Queue (void * op);
};
/*****************************************************************************
*
* W9x internal async API
*
***/
void W9xThreadInitialize ();
void W9xThreadDestroy (unsigned exitThreadWaitMs);
void W9xThreadSignalShutdown ();
void W9xThreadWaitForShutdown ();
void W9xThreadSleep (unsigned sleepMs);
bool W9xThreadWaitId (
AsyncFile file,
AsyncId asyncId,
unsigned timeoutMs
);
AsyncFile W9xFileOpen (
const wchar fullPath[],
FAsyncNotifyFileProc notifyProc,
EFileError * error,
unsigned desiredAccess,
unsigned openMode,
unsigned shareModeFlags,
void * userState,
qword * fileSize,
qword * fileLastWriteTime
);
void W9xFileClose (
AsyncFile file,
qword truncateSize
);
void W9xFileSetLastWriteTime (
AsyncFile file,
qword lastWriteTime
);
qword W9xFileGetLastWriteTime (
const wchar fileName[]
);
AsyncId W9xFileFlushBuffers (
AsyncFile file,
qword truncateSize,
bool notify,
void * param
);
AsyncId W9xFileRead (
AsyncFile file,
qword offset,
void * buffer,
unsigned bytes,
unsigned flags,
void * param
);
AsyncId W9xFileWrite (
AsyncFile file,
qword offset,
const void *buffer,
unsigned bytes,
unsigned flags,
void * param
);
AsyncId W9xFileCreateSequence (
AsyncFile file,
bool notify,
void * param
);
bool W9xFileSeek (
AsyncFile file,
qword distance,
EFileSeekFrom from
);
void W9xSocketConnect (
AsyncCancelId * cancelId,
const NetAddress & netAddr,
FAsyncNotifySocketProc notifyProc,
void * param,
const void * sendData,
unsigned sendBytes,
unsigned connectMs,
unsigned localPort
);
void W9xSocketConnectCancel (
FAsyncNotifySocketProc notifyProc,
AsyncCancelId cancelId
);
void W9xSocketDisconnect (
AsyncSocket sock,
bool hardClose
);
void W9xSocketDelete (AsyncSocket sock);
void W9xSocketDestroy ();
bool W9xSocketSend (
AsyncSocket sock,
const void * data,
unsigned bytes
);
bool W9xSocketWrite (
AsyncSocket sock,
const void * buffer,
unsigned bytes,
void * param
);
void W9xSocketSetNotifyProc (
AsyncSocket sock,
FAsyncNotifySocketProc notifyProc
);
void W9xSocketSetBacklogAlloc (
AsyncSocket sock,
unsigned bufferSize
);
unsigned W9xSocketStartListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
void W9xSocketStopListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
void W9xSocketEnableNagling (
AsyncSocket conn,
bool enable
);
} // namespace W9x

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,453 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceW9xThread.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
#include "pnAceW9xInt.h"
namespace W9x {
/*****************************************************************************
*
* Private data
*
***/
const unsigned kThreadCount = 2;
static CCritSect s_critSect;
static bool s_destroying;
static HANDLE s_destroyEvent;
static unsigned s_sequence;
static HANDLE s_shutdownEvent;
static HANDLE s_signalEvent;
static HANDLE s_thread[kThreadCount];
/****************************************************************************
*
* ThreadWaitRec
*
***/
struct ThreadWaitRec {
HANDLE event;
LINK(ThreadWaitRec) link;
};
/****************************************************************************
*
* CThreadDispRec
*
***/
class CThreadDispRec {
private:
CThreadDispObject * m_object;
void * m_op;
AsyncId m_ioId;
LISTDECL(ThreadWaitRec, link) m_waitList;
public:
LINK(CThreadDispRec) m_link;
CThreadDispRec (
CThreadDispObject * object,
void * op,
AsyncId * asyncId
);
~CThreadDispRec ();
void Complete (CCritSect * critSect);
AsyncId GetId () const { return m_ioId; }
void LinkWait (ThreadWaitRec * wait);
};
static LISTDECL(CThreadDispRec, m_link) s_dispList;
static LISTDECL(CThreadDispRec, m_link) s_dispInProcList;
//===========================================================================
CThreadDispRec::CThreadDispRec (
CThreadDispObject * object,
void * op,
AsyncId * asyncId
) :
m_object(object),
m_op(op)
{
s_critSect.Enter();
// Verify that this module is not being destroyed
ASSERT(!s_destroying);
// Increment the owning object's reference count
object->IncRef();
// Assign an id
m_ioId = (AsyncId)++s_sequence;
if (!m_ioId)
m_ioId = (AsyncId)++s_sequence;
*asyncId = m_ioId;
// Link this record to the dispatch list
s_dispList.Link(this);
s_critSect.Leave();
}
//===========================================================================
CThreadDispRec::~CThreadDispRec () {
// Delete the operation data
CThreadDispObject * object = m_object;
object->Delete(m_op);
s_critSect.Enter();
// Unlink this record
m_link.Unlink();
// Wake up all threads blocking on this operation. We must unlink each
// wait record before we signal it.
for (ThreadWaitRec * rec; (rec = m_waitList.Head()) != nil; ) {
m_waitList.Unlink(rec);
SetEvent(rec->event);
}
// Decrement the owning object's reference count
object->DecRef();
s_critSect.Leave();
}
//===========================================================================
void CThreadDispRec::Complete (CCritSect * critSect) {
m_object->Complete(m_op, critSect, m_ioId);
}
//===========================================================================
void CThreadDispRec::LinkWait (ThreadWaitRec * wait) {
// The caller should have already claimed the critical section before
// calling this function
m_waitList.Link(wait);
}
/****************************************************************************
*
* CThreadDispObject
*
***/
//===========================================================================
CThreadDispObject::CThreadDispObject () {
IncRef();
}
//===========================================================================
void CThreadDispObject::Close () {
s_critSect.Enter();
DecRef();
s_critSect.Leave();
}
//===========================================================================
AsyncId CThreadDispObject::Queue (void * op) {
AsyncId asyncId = 0;
NEW(CThreadDispRec)(this, op, &asyncId);
SetEvent(s_signalEvent);
return asyncId;
}
/****************************************************************************
*
* Thread procedure
*
***/
//===========================================================================
static unsigned CALLBACK W9xThreadProc (AsyncThread *) {
// Perform the main thread loop
for (;;) {
unsigned timeout = (unsigned)-1;
// If an operation is queued, complete it and dispatch a notification.
// The code that processes the operation is responsible for leaving
// our critical section. This ensures that operations are completed
// in order.
s_critSect.Enter();
CThreadDispRec * rec = s_dispList.Head();
if (rec) {
s_dispInProcList.Link(rec);
rec->Complete(&s_critSect);
DEL(rec);
timeout = 0;
}
else {
s_critSect.Leave();
}
// Consume events, check for destruction, and block if we have
// nothing to do.
HANDLE events[] = {s_destroyEvent, s_signalEvent};
dword result = WaitForMultipleObjects(
arrsize(events),
events,
FALSE,
INFINITE
);
if (result == WAIT_OBJECT_0)
return 0;
}
}
/****************************************************************************
*
* Exported functions
*
***/
//===========================================================================
void W9xThreadDestroy (
unsigned exitThreadWaitMs
) {
// Wait until all outstanding I/O is complete. We allow new I/O
// operations to be queued while old ones are completing.
s_critSect.Enter();
while (s_dispList.Head() || s_dispInProcList.Head()) {
s_critSect.Leave();
Sleep(10);
s_critSect.Enter();
}
// Once all I/O operations are complete, we disallow any future
// I/O operations from being queued.
s_destroying = true;
s_critSect.Leave();
// Signal thread destruction
if (s_destroyEvent)
SetEvent(s_destroyEvent);
// Wait for thread destruction
for (unsigned thread = kThreadCount; thread--; )
if (s_thread[thread]) {
// Wait for the thread to terminate
WaitForSingleObject(s_thread[thread], exitThreadWaitMs);
// Close the thread handle
CloseHandle(s_thread[thread]);
s_thread[thread] = 0;
}
// Destroy internal modules
W9xSocketDestroy();
// Destroy events
if (s_destroyEvent) {
CloseHandle(s_destroyEvent);
s_destroyEvent = 0;
}
if (s_shutdownEvent) {
CloseHandle(s_shutdownEvent);
s_shutdownEvent = 0;
}
if (s_signalEvent) {
CloseHandle(s_signalEvent);
s_signalEvent = 0;
}
}
//===========================================================================
void W9xThreadInitialize () {
// Reset static variables
s_destroying = false;
// Create a manual reset event to use for signaling thread destruction
if (s_destroyEvent)
ResetEvent(s_destroyEvent);
else {
s_destroyEvent = CreateEvent(nil, TRUE, FALSE, nil);
ASSERT(s_destroyEvent);
}
// Create an auto-reset event to use for signaling the thread to process
// notifications
if (!s_signalEvent) {
s_signalEvent = CreateEvent(nil, FALSE, FALSE, nil);
ASSERT(s_signalEvent);
}
// Create a manual reset event to use for signaling application shutdown
if (s_shutdownEvent)
ResetEvent(s_shutdownEvent);
else {
s_shutdownEvent = CreateEvent(nil, TRUE, FALSE, nil);
ASSERT(s_shutdownEvent);
}
// Create threads
for (unsigned thread = 0; thread < kThreadCount; ++thread) {
if (!s_thread[thread]) {
s_thread[thread] = (HANDLE) AsyncThreadCreate(
W9xThreadProc,
(void *) thread,
L"W9xWorkerThread"
);
}
}
}
//===========================================================================
void W9xThreadSignalShutdown () {
SetEvent(s_shutdownEvent);
}
//===========================================================================
void W9xThreadSleep (
unsigned sleepMs
) {
Sleep(sleepMs);
}
//===========================================================================
void W9xThreadWaitForShutdown () {
// We know that the applicaton is finished initializing at this point.
// While it was still initializing, it may have returned an infinite
// sleep time from the idle procedure, which would prevent us from ever
// calling it again. Therefore, we trigger an idle callback here.
SetEvent(s_signalEvent);
// Wait for the application to signal shutdown
WaitForSingleObject(s_shutdownEvent, INFINITE);
}
//===========================================================================
bool W9xThreadWaitId (
AsyncFile file,
AsyncId asyncId,
unsigned timeoutMs
) {
REF(file);
// Find a pending I/O operation with the given id
s_critSect.Enter();
CThreadDispRec * disp;
for (disp = s_dispList.Head(); disp && (disp->GetId() != asyncId); disp = s_dispList.Next(disp))
;
if (!disp)
for (disp = s_dispInProcList.Head(); disp && (disp->GetId() != asyncId); disp = s_dispInProcList.Next(disp))
;
// If we couldn't find the given id, the operation must have already
// completed, so return true.
if (!disp) {
s_critSect.Leave();
return true;
}
// The operation has not completed. If the timeout is zero, return
// false.
if (!timeoutMs) {
s_critSect.Leave();
return false;
}
// Create a wait event
HANDLE event = CreateEvent(nil, FALSE, FALSE, nil);
// Create a wait record and link it to the I/O operation
ThreadWaitRec wait;
wait.event = event;
disp->LinkWait(&wait);
s_critSect.Leave();
// Wait for the operation to complete
DWORD result = WaitForSingleObject(event, timeoutMs);
// If the operation completed then the dispatcher unlinked our wait
// record before signaling it. We can simply free the event and return.
if (result == WAIT_OBJECT_0) {
CloseHandle(event);
return true;
}
// Unlink our wait record from the I/O operation
s_critSect.Enter();
wait.link.Unlink();
s_critSect.Leave();
// Free the event
CloseHandle(event);
// Return false, because the operation did not complete during the
// timeout period
return false;
}
} // namespace W9x

View File

@ -0,0 +1,400 @@
/*==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 <http://www.gnu.org/licenses/>.
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/Win32/pnAceW32Dns.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private
*
***/
enum {
WM_LOOKUP_EXIT = WM_APP,
WM_LOOKUP_FOUND_HOST
};
const unsigned kMaxLookupName = 128;
struct Lookup {
LINK(Lookup) link;
AsyncCancelId cancelId;
HANDLE cancelHandle;
FAsyncLookupProc lookupProc;
unsigned port;
void * param;
wchar name[kMaxLookupName];
char buffer[MAXGETHOSTSTRUCT];
};
static CCritSect s_critsect;
static LISTDECL(Lookup, link) s_lookupList;
static HANDLE s_lookupThread;
static HWND s_lookupWindow;
static unsigned s_nextLookupCancelId = 1;
/*****************************************************************************
*
* Internal functions
*
***/
//===========================================================================
static void LookupProcess (Lookup * lookup, unsigned error) {
unsigned count = 0;
NetAddress * addrs = nil;
for (ONCE) {
if (error)
break;
const HOSTENT & host = * (HOSTENT *) lookup->buffer;
if (host.h_addrtype != AF_INET)
break;
if (host.h_length != sizeof(in_addr))
break;
if (!host.h_addr_list)
break;
in_addr const * const * const inAddr = (in_addr **) host.h_addr_list;
// count the number of addresses
while (inAddr[count])
++count;
// allocate a buffer large enough to hold all the addresses
addrs = (NetAddress *) _alloca(sizeof(*addrs) * count);
MemZero(addrs, sizeof(*addrs) * count);
// fill in address data
const word port = htons((word) lookup->port);
for (unsigned i = 0; i < count; ++i) {
sockaddr_in * inetaddr = (sockaddr_in *) &addrs[i];
inetaddr->sin_family = AF_INET;
inetaddr->sin_addr = *inAddr[i];
inetaddr->sin_port = port;
}
if (host.h_name && host.h_name[0])
StrToUnicode(lookup->name, host.h_name, arrsize(lookup->name));
}
if (lookup->lookupProc)
lookup->lookupProc(lookup->param, lookup->name, count, addrs);
// we can delete the operation outside an IoConn critical
// section because it isn't linked into an ioConn opList
// and because connection attempts are not waitable
ASSERT(!lookup->link.IsLinked());
DEL(lookup);
PerfSubCounter(kAsyncPerfNameLookupAttemptsCurr, 1);
}
//===========================================================================
static void LookupFindAndProcess (HANDLE cancelHandle, unsigned error) {
// find the operation for this cancel handle
Lookup * lookup;
s_critsect.Enter();
for (lookup = s_lookupList.Head(); lookup; lookup = s_lookupList.Next(lookup)) {
if (lookup->cancelHandle == cancelHandle) {
lookup->cancelHandle = nil;
s_lookupList.Unlink(lookup);
break;
}
}
s_critsect.Leave();
if (lookup)
LookupProcess(lookup, error);
}
//===========================================================================
static unsigned THREADCALL LookupThreadProc (AsyncThread * thread) {
static const char WINDOW_CLASS[] = "AsyncLookupWnd";
WNDCLASS wc;
ZERO(wc);
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = GetModuleHandle(0);
wc.lpszClassName = WINDOW_CLASS;
RegisterClass(&wc);
s_lookupWindow = CreateWindow(
WINDOW_CLASS,
WINDOW_CLASS,
WS_OVERLAPPED,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
(HWND)0,
(HMENU) 0,
wc.hInstance,
0
);
if (!s_lookupWindow)
ErrorFatal(__LINE__, __FILE__, "CreateWindow %#x", GetLastError());
HANDLE lookupStartEvent = (HANDLE) thread->argument;
SetEvent(lookupStartEvent);
MSG msg;
while (GetMessage(&msg, s_lookupWindow, 0, 0)) {
if (msg.message == WM_LOOKUP_FOUND_HOST)
LookupFindAndProcess((HANDLE) msg.wParam, HIWORD(msg.lParam));
else if (msg.message == WM_LOOKUP_EXIT)
break;
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// fail all pending name lookups
for (;;) {
s_critsect.Enter();
Lookup * lookup = s_lookupList.Head();
if (lookup) {
WSACancelAsyncRequest(lookup->cancelHandle);
lookup->cancelHandle = nil;
s_lookupList.Unlink(lookup);
}
s_critsect.Leave();
if (!lookup)
break;
LookupProcess(lookup, (unsigned) -1);
}
// cleanup
DestroyWindow(s_lookupWindow);
s_lookupWindow = nil;
return 0;
}
//===========================================================================
static void StartLookupThread () {
if (s_lookupThread)
return;
// create a shutdown event
HANDLE lookupStartEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) 0,
true, // manual reset
false, // initial state off
(LPCTSTR) 0 // name
);
if (!lookupStartEvent)
ErrorFatal(__LINE__, __FILE__, "CreateEvent %#x", GetLastError());
// create a thread to perform lookups
s_lookupThread = (HANDLE) AsyncThreadCreate(
LookupThreadProc,
lookupStartEvent,
L"AsyncLookupThread"
);
WaitForSingleObject(lookupStartEvent, INFINITE);
CloseHandle(lookupStartEvent);
ASSERT(s_lookupWindow);
}
/*****************************************************************************
*
* Module functions
*
***/
//===========================================================================
void DnsDestroy (unsigned exitThreadWaitMs) {
if (s_lookupThread) {
PostMessage(s_lookupWindow, WM_LOOKUP_EXIT, 0, 0);
WaitForSingleObject(s_lookupThread, exitThreadWaitMs);
CloseHandle(s_lookupThread);
s_lookupThread = nil;
ASSERT(!s_lookupWindow);
}
}
/*****************************************************************************
*
* Public functions
*
***/
//===========================================================================
void AsyncAddressLookupName (
AsyncCancelId * cancelId, // out
FAsyncLookupProc lookupProc,
const wchar name[],
unsigned port,
void * param
) {
ASSERT(lookupProc);
ASSERT(name);
PerfAddCounter(kAsyncPerfNameLookupAttemptsCurr, 1);
PerfAddCounter(kAsyncPerfNameLookupAttemptsTotal, 1);
// Get name/port
char ansiName[kMaxLookupName];
StrToAnsi(ansiName, name, arrsize(ansiName));
if (char * portStr = StrChr(ansiName, ':')) {
if (unsigned newPort = StrToUnsigned(portStr + 1, nil, 10))
port = newPort;
*portStr = 0;
}
// Initialize lookup
Lookup * lookup = NEW(Lookup);
lookup->lookupProc = lookupProc;
lookup->port = port;
lookup->param = param;
StrCopy(lookup->name, name, arrsize(lookup->name));
s_critsect.Enter();
{
// Start the lookup thread if it wasn't started already
StartLookupThread();
s_lookupList.Link(lookup);
// get cancel id; we can avoid checking for zero by always using an odd number
ASSERT(s_nextLookupCancelId & 1);
s_nextLookupCancelId += 2;
*cancelId = lookup->cancelId = (AsyncCancelId) s_nextLookupCancelId;
// Perform async lookup
lookup->cancelHandle = WSAAsyncGetHostByName(
s_lookupWindow,
WM_LOOKUP_FOUND_HOST,
ansiName,
&lookup->buffer[0],
sizeof(lookup->buffer)
);
if (!lookup->cancelHandle) {
PostMessage(s_lookupWindow, WM_LOOKUP_FOUND_HOST, nil, (unsigned) -1);
}
}
s_critsect.Leave();
}
//===========================================================================
void AsyncAddressLookupAddr (
AsyncCancelId * cancelId, // out
FAsyncLookupProc lookupProc,
const NetAddress & address,
void * param
) {
ASSERT(lookupProc);
PerfAddCounter(kAsyncPerfNameLookupAttemptsCurr, 1);
PerfAddCounter(kAsyncPerfNameLookupAttemptsTotal, 1);
// Initialize lookup
Lookup * lookup = NEW(Lookup);
lookup->lookupProc = lookupProc;
lookup->port = 1;
lookup->param = param;
NetAddressToString(
address,
lookup->name,
arrsize(lookup->name),
kNetAddressFormatNodeNumber
);
s_critsect.Enter();
{
// Start the lookup thread if it wasn't started already
StartLookupThread();
s_lookupList.Link(lookup);
// get cancel id; we can avoid checking for zero by always using an odd number
ASSERT(s_nextLookupCancelId & 1);
s_nextLookupCancelId += 2;
*cancelId = lookup->cancelId = (AsyncCancelId) s_nextLookupCancelId;
// Perform async lookup
u_long addr = ((const sockaddr_in *) &address)->sin_addr.S_un.S_addr;
lookup->cancelHandle = WSAAsyncGetHostByAddr(
s_lookupWindow,
WM_LOOKUP_FOUND_HOST,
(const char *) &addr,
sizeof(addr),
AF_INET,
&lookup->buffer[0],
sizeof(lookup->buffer)
);
if (!lookup->cancelHandle) {
PostMessage(s_lookupWindow, WM_LOOKUP_FOUND_HOST, nil, (unsigned) -1);
}
}
s_critsect.Leave();
}
//===========================================================================
void AsyncAddressLookupCancel (
FAsyncLookupProc lookupProc,
AsyncCancelId cancelId // nil = cancel all with specified lookupProc
) {
s_critsect.Enter();
for (Lookup * lookup = s_lookupList.Head(); lookup; lookup = s_lookupList.Next(lookup)) {
if (lookup->lookupProc && (lookup->lookupProc != lookupProc))
continue;
if (cancelId && (lookup->cancelId != cancelId))
continue;
if (!lookup->cancelHandle)
continue;
// cancel this request
WSACancelAsyncRequest(lookup->cancelHandle);
lookup->cancelHandle = nil;
// initiate user callback
PostMessage(s_lookupWindow, WM_LOOKUP_FOUND_HOST, nil, (unsigned) -1);
}
s_critsect.Leave();
}

View File

@ -0,0 +1,280 @@
/*==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 <http://www.gnu.org/licenses/>.
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/Win32/pnAceW32Thread.cpp
*
***/
#include "../../Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private
*
***/
struct AsyncThreadTaskList : AtomicRef {
ENetError error;
AsyncThreadTaskList ();
~AsyncThreadTaskList ();
};
struct ThreadTask {
AsyncThreadTaskList * taskList;
FAsyncThreadTask callback;
void * param;
wchar debugStr[256];
};
static HANDLE s_taskPort;
/*****************************************************************************
*
* AsyncThreadTaskList
*
***/
//===========================================================================
AsyncThreadTaskList::AsyncThreadTaskList ()
: error(kNetSuccess)
{
PerfAddCounter(kAsyncPerfThreadTaskListCount, 1);
}
//============================================================================
AsyncThreadTaskList::~AsyncThreadTaskList () {
PerfSubCounter(kAsyncPerfThreadTaskListCount, 1);
}
/*****************************************************************************
*
* Local functions
*
***/
/****************************************************************************
*
* ThreadTaskProc
*
***/
//===========================================================================
static unsigned THREADCALL ThreadTaskProc (AsyncThread * thread) {
REF(thread);
PerfAddCounter(kAsyncPerfThreadTaskThreadsActive, 1);
for (;;) {
long desired = AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsDesired);
if (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsRunning) > desired) {
long runningCount = PerfSubCounter(kAsyncPerfThreadTaskThreadsRunning, 1) - 1;
if (runningCount >= desired) {
if (runningCount > desired)
PostQueuedCompletionStatus(s_taskPort, 0, 0, 0);
break;
}
PerfAddCounter(kAsyncPerfThreadTaskThreadsRunning, 1);
}
// Get the next work item
DWORD bytes;
ThreadTask * task;
LPOVERLAPPED op;
PerfSubCounter(kAsyncPerfThreadTaskThreadsActive, 1);
(void) GetQueuedCompletionStatus(
s_taskPort,
&bytes,
#ifdef _WIN64
(PULONG_PTR) &task,
#else
(LPDWORD) &task,
#endif
&op,
INFINITE
);
PerfAddCounter(kAsyncPerfThreadTaskThreadsActive, 1);
if (task) {
#ifdef SERVER
void * check = CrashAddDeadlockCheck(thread->handle, task->debugStr);
#endif
task->callback(task->param, task->taskList->error);
#ifdef SERVER
CrashRemoveDeadlockCheck(check);
#endif
task->taskList->DecRef("task");
DEL(task);
}
}
PerfSubCounter(kAsyncPerfThreadTaskThreadsActive, 1);
return 0;
}
//===========================================================================
static unsigned THREADCALL FirstThreadTaskProc (AsyncThread * param) {
while (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsRunning) < AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsDesired)) {
PerfAddCounter(kAsyncPerfThreadTaskThreadsRunning, 1);
AsyncThreadCreate(ThreadTaskProc, nil, L"AsyncThreadTaskList");
}
return ThreadTaskProc(param);
}
/*****************************************************************************
*
* Module functions
*
***/
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
void AsyncThreadTaskInitialize (unsigned threads) {
// Create completion port
s_taskPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
ASSERT(s_taskPort);
// Create threads
AsyncThreadTaskSetThreadCount(threads);
}
//============================================================================
void AsyncThreadTaskDestroy () {
ASSERT(!AsyncPerfGetCounter(kAsyncPerfThreadTaskListCount));
if (s_taskPort) {
PerfSetCounter(kAsyncPerfThreadTaskThreadsDesired, 0);
PostQueuedCompletionStatus(s_taskPort, 0, 0, 0);
// Wait until all threads have exited
while (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsActive))
AsyncSleep(10);
while (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsRunning))
AsyncSleep(10);
// Cleanup completion port
CloseHandle(s_taskPort);
s_taskPort = nil;
}
}
//===========================================================================
unsigned AsyncThreadTaskGetThreadCount () {
return AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsDesired);
}
//===========================================================================
void AsyncThreadTaskSetThreadCount (unsigned threads) {
ASSERT(threads >= kThreadTaskMinThreads);
ASSERT(threads <= kThreadTaskMaxThreads);
if (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsDesired) == (long) threads)
return;
PerfSetCounter(kAsyncPerfThreadTaskThreadsDesired, (long) threads);
if (AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsRunning) < AsyncPerfGetCounter(kAsyncPerfThreadTaskThreadsDesired)) {
PerfAddCounter(kAsyncPerfThreadTaskThreadsRunning, 1);
AsyncThreadCreate(FirstThreadTaskProc, nil, L"ThreadTaskList");
}
else {
PostQueuedCompletionStatus(s_taskPort, 0, 0, 0);
}
}
//===========================================================================
AsyncThreadTaskList * AsyncThreadTaskListCreate () {
ASSERT(s_taskPort);
AsyncThreadTaskList * taskList = NEW(AsyncThreadTaskList);
taskList->IncRef("TaskList");
return taskList;
}
//===========================================================================
void AsyncThreadTaskListDestroy (
AsyncThreadTaskList * taskList,
ENetError error
) {
ASSERT(taskList);
ASSERT(error);
ASSERT(!taskList->error);
taskList->error = error;
taskList->DecRef(); // REF:TaskList
}
//===========================================================================
void AsyncThreadTaskAdd (
AsyncThreadTaskList * taskList,
FAsyncThreadTask callback,
void * param,
const wchar debugStr[],
EThreadTaskPriority priority /* = kThreadTaskPriorityNormal */
) {
ASSERT(s_taskPort);
ASSERT(taskList);
ASSERT(callback);
ASSERT(priority == kThreadTaskPriorityNormal);
REF(priority);
// Allocate a new task record
ThreadTask * task = NEW(ThreadTask);
task->taskList = taskList;
task->callback = callback;
task->param = param;
StrCopy(task->debugStr, debugStr, arrsize(task->debugStr)); // this will be sent with the deadlock checker email if this thread exceeds time set in plServer.ini
taskList->IncRef("Task");
PostQueuedCompletionStatus(s_taskPort, 0, (DWORD) task, NULL);
}

View File

@ -0,0 +1,280 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceInt.h
*
***/
#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_PNACEINT_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnAsyncCoreExe/Private/pnAceInt.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNASYNCCOREEXE_PRIVATE_PNACEINT_H
/*****************************************************************************
*
* Core.cpp
*
***/
// Performance counter functions
long PerfAddCounter (unsigned id, unsigned n);
long PerfSubCounter (unsigned id, unsigned n);
long PerfSetCounter (unsigned id, unsigned n);
/*****************************************************************************
*
* Dns.cpp
*
***/
void DnsDestroy (unsigned exitThreadWaitMs);
/*****************************************************************************
*
* Thread.cpp
*
***/
void ThreadDestroy (unsigned exitThreadWaitMs);
/*****************************************************************************
*
* Timer.cpp
*
***/
void TimerDestroy (unsigned exitThreadWaitMs);
/****************************************************************************
*
* Async API function types
*
***/
// Core
typedef void (* FInitialize) ();
typedef void (* FDestroy) (unsigned exitThreadWaitMs);
typedef void (* FSignalShutdown) ();
typedef void (* FWaitForShutdown) ();
typedef void (* FSleep) (unsigned sleepMs);
// Files
typedef AsyncFile (* FAsyncFileOpen) (
const wchar fullPath[],
FAsyncNotifyFileProc notifyProc,
EFileError * error,
unsigned desiredAccess,
unsigned openMode,
unsigned shareModeFlags,
void * userState,
qword * fileSize,
qword * fileLastWriteTime
);
typedef void (* FAsyncFileClose) (
AsyncFile file,
qword truncateSize
);
typedef void (* FAsyncFileSetLastWriteTime) (
AsyncFile file,
qword lastWriteTime
);
typedef qword (* FAsyncFileGetLastWriteTime) (
const wchar fileName[]
);
typedef AsyncId (* FAsyncFileFlushBuffers) (
AsyncFile file,
qword truncateSize,
bool notify,
void * param
);
typedef AsyncId (* FAsyncFileRead) (
AsyncFile file,
qword offset,
void * buffer,
unsigned bytes,
unsigned flags,
void * param
);
typedef AsyncId (* FAsyncFileWrite) (
AsyncFile file,
qword offset,
const void * buffer,
unsigned bytes,
unsigned flags,
void * param
);
typedef AsyncId (* FAsyncFileCreateSequence) (
AsyncFile file,
bool notify,
void * param
);
typedef bool (* FAsyncFileSeek) (
AsyncFile file,
qword distance,
EFileSeekFrom from
);
typedef bool (* FAsyncFileWaitId) (
AsyncFile file,
AsyncId asyncId,
unsigned timeoutMs
);
// Sockets
typedef void (* FAsyncSocketConnect) (
AsyncCancelId * cancelId,
const NetAddress & netAddr,
FAsyncNotifySocketProc notifyProc,
void * param,
const void * sendData,
unsigned sendBytes,
unsigned connectMs,
unsigned localPort
);
typedef void (* FAsyncSocketConnectCancel) (
FAsyncNotifySocketProc notifyProc,
AsyncCancelId cancelId
);
typedef void (* FAsyncSocketDisconnect) (
AsyncSocket sock,
bool hardClose
);
typedef void (* FAsyncSocketDelete) (AsyncSocket sock);
typedef bool (* FAsyncSocketSend) (
AsyncSocket sock,
const void * data,
unsigned bytes
);
typedef bool (* FAsyncSocketWrite) (
AsyncSocket sock,
const void * buffer,
unsigned bytes,
void * param
);
typedef void (* FAsyncSocketSetNotifyProc) (
AsyncSocket sock,
FAsyncNotifySocketProc notifyProc
);
typedef void (* FAsyncSocketSetBacklogAlloc) (
AsyncSocket sock,
unsigned bufferSize
);
typedef unsigned (* FAsyncSocketStartListening) (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
typedef void (* FAsyncSocketStopListening) (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
);
typedef void (* FAsyncSocketEnableNagling) (
AsyncSocket conn,
bool enable
);
/****************************************************************************
*
* I/O API
*
***/
struct AsyncApi {
// Init
FInitialize initialize;
FDestroy destroy;
FSignalShutdown signalShutdown;
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;
FAsyncSocketDisconnect socketDisconnect;
FAsyncSocketDelete socketDelete;
FAsyncSocketSend socketSend;
FAsyncSocketWrite socketWrite;
FAsyncSocketSetNotifyProc socketSetNotifyProc;
FAsyncSocketSetBacklogAlloc socketSetBacklogAlloc;
FAsyncSocketStartListening socketStartListening;
FAsyncSocketStopListening socketStopListening;
FAsyncSocketEnableNagling socketEnableNagling;
};
extern AsyncApi g_api;

View File

@ -0,0 +1,246 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceCore.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private data
*
***/
static long s_perf[kNumAsyncPerfCounters];
/****************************************************************************
*
* Module data exports
*
***/
AsyncApi g_api;
bool s_transgaming;
/*****************************************************************************
*
* Local functions
*
***/
//============================================================================
static void DoTransgamingCheck () {
#ifdef HS_BUILD_FOR_WIN32
#ifdef CLIENT
HMODULE hMod = GetModuleHandle("ntdll");
if (!hMod)
return;
s_transgaming = GetProcAddress(hMod, "IsTransgaming") != nil;
#endif
#endif
}
//===========================================================================
static void IAsyncInitUseW9x () {
REF(IAsyncInitUseW9x);
#ifdef HS_BUILD_FOR_WIN32
W9xGetApi(&g_api);
#else
ErrorFatal("W9x I/O Not supported on this platform");
#endif
}
//===========================================================================
static void IAsyncInitUseNt () {
REF(IAsyncInitUseNt);
#ifdef HS_BUILD_FOR_WIN32
NtGetApi(&g_api);
#else
ErrorFatal("Nt I/O Not supported on this platform");
#endif
}
//===========================================================================
static void IAsyncInitUseUnix () {
REF(IAsyncInitUseUnix);
#ifdef HS_BUILD_FOR_UNIX
#error Unix I/O not implemented yet
UxGetApi(&g_api);
#else
ErrorFatal(__LINE__, __FILE__, "Unix I/O Not supported on this platform");
#endif
}
//===========================================================================
static void IAsyncInitForClient () {
REF(IAsyncInitForClient);
#ifdef HS_BUILD_FOR_WIN32
DoTransgamingCheck();
if (s_transgaming) {
IAsyncInitUseW9x();
}
else {
IAsyncInitUseNt();
}
#elif HS_BUILD_FOR_UNIX
IAsyncInitUseUnix();
#else
ErrorFatal("AsyncCore: No default implementation for this platform");
#endif
}
//===========================================================================
static void IAsyncInitForServer () {
REF(IAsyncInitForServer);
#ifdef HS_BUILD_FOR_WIN32
IAsyncInitUseNt();
#elif HS_BUILD_FOR_UNIX
IAsyncInitUseUnix();
#else
ErrorFatal("AsyncCore: No default implementation for this platform");
#endif
}
/*****************************************************************************
*
* Module exports
*
***/
//============================================================================
long PerfAddCounter (unsigned id, unsigned n) {
ASSERT(id < kNumAsyncPerfCounters);
return AtomicAdd(&s_perf[id], n);
}
//============================================================================
long PerfSubCounter (unsigned id, unsigned n) {
ASSERT(id < kNumAsyncPerfCounters);
return AtomicAdd(&s_perf[id], -(signed)n);
}
//============================================================================
long PerfSetCounter (unsigned id, unsigned n) {
ASSERT(id < kNumAsyncPerfCounters);
return AtomicSet(&s_perf[id], n);
}
/*****************************************************************************
*
* Public exports
*
***/
//===========================================================================
void AsyncCoreInitialize () {
ASSERTMSG(!g_api.initialize, "AsyncCore already initialized");
#ifdef HS_BUILD_FOR_WIN32
// Initialize WinSock
WSADATA wsaData;
if (WSAStartup(0x101, &wsaData))
ErrorFatal(__LINE__, __FILE__, "WSA startup failed");
if (wsaData.wVersion != 0x101)
ErrorFatal(__LINE__, __FILE__, "WSA version failed");
#endif
#ifdef CLIENT
IAsyncInitForClient();
#elif SERVER
IAsyncInitForServer();
#else
# error "Neither CLIENT nor SERVER defined. Cannot configure AsyncCore for target"
#endif
ASSERT(g_api.initialize);
g_api.initialize();
}
//============================================================================
void AsyncCoreDestroy (unsigned waitMs) {
if (g_api.destroy) {
g_api.destroy(waitMs);
}
DnsDestroy(waitMs);
TimerDestroy(waitMs);
ThreadDestroy(waitMs);
ZERO(g_api);
}
//============================================================================
void AsyncSignalShutdown () {
ASSERT(g_api.signalShutdown);
g_api.signalShutdown();
}
//============================================================================
void AsyncWaitForShutdown () {
ASSERT(g_api.waitForShutdown);
g_api.waitForShutdown();
}
//============================================================================
void AsyncSleep (unsigned sleepMs) {
ASSERT(g_api.sleep);
g_api.sleep(sleepMs);
}
//============================================================================
long AsyncPerfGetCounter (unsigned id) {
COMPILER_ASSERT(arrsize(s_perf) == kNumAsyncPerfCounters);
ASSERT(id < kNumAsyncPerfCounters);
return s_perf[id];
}

View File

@ -0,0 +1,606 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceIo.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/****************************************************************************
*
* ISocketConnHash
*
***/
// socket notification procedures
// connection data format:
// byte connType;
// dword buildId; [optional]
// dword branchId; [optional]
// dword buildType; [optional]
// Uuid productId; [optional]
const unsigned kConnHashFlagsIgnore = 0x01;
const unsigned kConnHashFlagsExactMatch = 0x02;
struct ISocketConnHash {
unsigned connType;
unsigned buildId;
unsigned buildType;
unsigned branchId;
Uuid productId;
unsigned flags;
unsigned GetHash () const;
bool operator== (const ISocketConnHash & rhs) const;
};
struct ISocketConnType : ISocketConnHash {
HASHLINK(ISocketConnType) hashlink;
FAsyncNotifySocketProc notifyProc;
};
static CLock s_notifyProcLock;
static HASHTABLEDECL(
ISocketConnType,
ISocketConnHash,
hashlink
) s_notifyProcs;
//===========================================================================
unsigned ISocketConnHash::GetHash () const {
CHashValue hash;
hash.Hash32(connType);
/*
if (buildId)
hash.Hash32(buildId);
if (buildType)
hash.Hash32(buildType);
if (branchId)
hash.Hash32(branchId);
if (productId != kNilGuid)
hash.Hash(&productId, sizeof(productId));
*/
return hash.GetHash();
}
//===========================================================================
bool ISocketConnHash::operator== (const ISocketConnHash & rhs) const {
ASSERT(flags & kConnHashFlagsIgnore);
for (;;) {
// Check connType
if (connType != rhs.connType)
break;
// Check buildId
if (buildId != rhs.buildId) {
if (rhs.flags & kConnHashFlagsExactMatch)
break;
if (buildId)
break;
}
// Check buildType
if (buildType != rhs.buildType) {
if (rhs.flags & kConnHashFlagsExactMatch)
break;
if (buildType)
break;
}
// Check branchId
if (branchId != rhs.branchId) {
if (rhs.flags & kConnHashFlagsExactMatch)
break;
if (branchId)
break;
}
// Check productId
if (productId != rhs.productId) {
if (rhs.flags & kConnHashFlagsExactMatch)
break;
if (productId != kNilGuid)
break;
}
// Success!
return true;
}
// Failed!
return false;
}
//===========================================================================
static unsigned GetConnHash (
ISocketConnHash * hash,
const byte buffer[],
unsigned bytes
) {
if (!bytes)
return 0;
if (IS_TEXT_CONNTYPE(buffer[0])) {
hash->connType = buffer[0];
hash->buildId = 0;
hash->buildType = 0;
hash->branchId = 0;
hash->productId = 0;
hash->flags = 0;
// one byte consumed
return 1;
}
else {
if (bytes < sizeof(AsyncSocketConnectPacket))
return 0;
const AsyncSocketConnectPacket & connect = * (const AsyncSocketConnectPacket *) buffer;
if (connect.hdrBytes < sizeof(connect))
return 0;
hash->connType = connect.connType;
hash->buildId = connect.buildId;
hash->buildType = connect.buildType;
hash->branchId = connect.branchId;
hash->productId = connect.productId;
hash->flags = 0;
return connect.hdrBytes;
}
}
/****************************************************************************
*
* Public exports
*
***/
//===========================================================================
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 * FileErrorToString (EFileError error) {
static wchar * 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 fullPath[],
FAsyncNotifyFileProc notifyProc,
EFileError * error,
unsigned desiredAccess,
unsigned openMode,
unsigned shareModeFlags,
void * userState,
qword * fileSize,
qword * fileLastWriteTime
) {
ASSERT(g_api.fileOpen);
return g_api.fileOpen(
fullPath,
notifyProc,
error,
desiredAccess,
openMode,
shareModeFlags,
userState,
fileSize,
fileLastWriteTime
);
}
//============================================================================
void AsyncFileClose (
AsyncFile file,
qword truncateSize
) {
ASSERT(g_api.fileClose);
g_api.fileClose(file, truncateSize);
}
//============================================================================
void AsyncFileSetLastWriteTime (
AsyncFile file,
qword lastWriteTime
) {
ASSERT(g_api.fileSetLastWriteTime);
g_api.fileSetLastWriteTime(file, lastWriteTime);
}
//============================================================================
qword AsyncFileGetLastWriteTime (
const wchar fileName[]
) {
ASSERT(g_api.fileGetLastWriteTime);
return g_api.fileGetLastWriteTime(fileName);
}
//============================================================================
AsyncId AsyncFileFlushBuffers (
AsyncFile file,
qword truncateSize,
bool notify,
void * param
) {
ASSERT(g_api.fileFlushBuffers);
return g_api.fileFlushBuffers(file, truncateSize, notify, param);
}
//============================================================================
AsyncId AsyncFileRead (
AsyncFile file,
qword 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,
qword 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,
qword distance,
EFileSeekFrom seekFrom
) {
ASSERT(g_api.fileSeek);
return g_api.fileSeek(file, distance, seekFrom);
}
//===========================================================================
void AsyncSocketConnect (
AsyncCancelId * cancelId,
const NetAddress & netAddr,
FAsyncNotifySocketProc notifyProc,
void * param,
const void * sendData,
unsigned sendBytes,
unsigned connectMs,
unsigned localPort
) {
ASSERT(g_api.socketConnect);
g_api.socketConnect(
cancelId,
netAddr,
notifyProc,
param,
sendData,
sendBytes,
connectMs,
localPort
);
}
//===========================================================================
void AsyncSocketConnectCancel (
FAsyncNotifySocketProc notifyProc,
AsyncCancelId cancelId
) {
ASSERT(g_api.socketConnectCancel);
g_api.socketConnectCancel(notifyProc, cancelId);
}
//===========================================================================
void AsyncSocketDisconnect (
AsyncSocket sock,
bool hardClose
) {
ASSERT(g_api.socketDisconnect);
g_api.socketDisconnect(sock, hardClose);
}
//===========================================================================
void AsyncSocketDelete (AsyncSocket sock) {
ASSERT(g_api.socketDelete);
g_api.socketDelete(sock);
}
//===========================================================================
bool AsyncSocketSend (
AsyncSocket sock,
const void * data,
unsigned bytes
) {
ASSERT(g_api.socketSend);
return g_api.socketSend(sock, data, bytes);
}
//===========================================================================
bool AsyncSocketWrite (
AsyncSocket sock,
const void * buffer,
unsigned bytes,
void * param
) {
ASSERT(g_api.socketWrite);
return g_api.socketWrite(sock, buffer, bytes, param);
}
//===========================================================================
void AsyncSocketSetNotifyProc (
AsyncSocket sock,
FAsyncNotifySocketProc notifyProc
) {
ASSERT(g_api.socketSetNotifyProc);
g_api.socketSetNotifyProc(sock, notifyProc);
}
//===========================================================================
void AsyncSocketSetBacklogAlloc (
AsyncSocket sock,
unsigned bufferSize
) {
ASSERT(g_api.socketSetBacklogAlloc);
g_api.socketSetBacklogAlloc(sock, bufferSize);
}
//===========================================================================
unsigned AsyncSocketStartListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
) {
ASSERT(g_api.socketStartListening);
return g_api.socketStartListening(listenAddr, notifyProc);
}
//===========================================================================
void AsyncSocketStopListening (
const NetAddress & listenAddr,
FAsyncNotifySocketProc notifyProc
) {
ASSERT(g_api.socketStopListening);
g_api.socketStopListening(listenAddr, notifyProc);
}
//============================================================================
void AsyncSocketEnableNagling (
AsyncSocket sock,
bool enable
) {
ASSERT(g_api.socketEnableNagling);
g_api.socketEnableNagling(sock, enable);
}
//===========================================================================
void AsyncSocketRegisterNotifyProc (
byte connType,
FAsyncNotifySocketProc notifyProc,
unsigned buildId,
unsigned buildType,
unsigned branchId,
const Uuid & productId
) {
ASSERT(connType != kConnTypeNil);
ASSERT(notifyProc);
// Perform memory allocation outside lock
ISocketConnType * ct = NEW(ISocketConnType);
ct->notifyProc = notifyProc;
ct->connType = connType;
ct->buildId = buildId;
ct->buildType = buildType;
ct->branchId = branchId;
ct->productId = productId;
ct->flags = kConnHashFlagsIgnore;
s_notifyProcLock.EnterWrite();
{
s_notifyProcs.Add(ct);
}
s_notifyProcLock.LeaveWrite();
}
//===========================================================================
void AsyncSocketUnregisterNotifyProc (
byte connType,
FAsyncNotifySocketProc notifyProc,
unsigned buildId,
unsigned buildType,
unsigned branchId,
const Uuid & productId
) {
ISocketConnHash hash;
hash.connType = connType;
hash.buildId = buildId;
hash.buildType = buildType;
hash.branchId = branchId;
hash.productId = productId;
hash.flags = kConnHashFlagsExactMatch;
ISocketConnType * scan;
s_notifyProcLock.EnterWrite();
{
scan = s_notifyProcs.Find(hash);
for (; scan; scan = s_notifyProcs.FindNext(hash, scan)) {
if (scan->notifyProc != notifyProc)
continue;
// Unlink the object so it can be deleted outside the lock
s_notifyProcs.Unlink(scan);
break;
}
}
s_notifyProcLock.LeaveWrite();
// perform memory deallocation outside the lock
DEL(scan);
}
//===========================================================================
FAsyncNotifySocketProc AsyncSocketFindNotifyProc (
const byte buffer[],
unsigned bytes,
unsigned * bytesProcessed,
unsigned * connType,
unsigned * buildId,
unsigned * buildType,
unsigned * branchId,
Uuid * productId
) {
for (;;) {
// Get the connType
ISocketConnHash hash;
*bytesProcessed = GetConnHash(&hash, buffer, bytes);
if (!*bytesProcessed)
break;
// Lookup notifyProc based on connType
FAsyncNotifySocketProc proc;
s_notifyProcLock.EnterRead();
if (const ISocketConnType * scan = s_notifyProcs.Find(hash))
proc = scan->notifyProc;
else
proc = nil;
s_notifyProcLock.LeaveRead();
if (!proc)
break;
// Success!
*connType = hash.connType;
*buildId = hash.buildId;
*buildType = hash.buildType;
*branchId = hash.branchId;
*productId = hash.productId;
return proc;
}
// Failure!
PerfAddCounter(kAsyncPerfSocketDisconnectInvalidConnType, 1);
*bytesProcessed = 0;
*connType = 0;
*buildId = 0;
*buildType = 0;
*branchId = 0;
*productId = 0;
return nil;
}

View File

@ -0,0 +1,494 @@
/*==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 <http://www.gnu.org/licenses/>.
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) && (BUILD_TYPE == BUILD_TYPE_LIVE)
// If this is an external live 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 s_directory[MAX_PATH];
static CCritSect s_logCrit[kNumLogTypes];
static char * s_logBuf[kNumLogTypes];
static unsigned s_logPos[kNumLogTypes];
static qword 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 * s_logNameFmt[kNumLogTypes] = {
#ifdef SERVER
L"Dbg%02u%02u%02u.%s.log",
L"Inf%02u%02u%02u.%s.log",
L"Err%02u%02u%02u.%s.log",
#else
L"%s%02u%02u%02u.%s.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
) {
REF(file);
REF(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) {
REF(AllocLogBuffer_CS);
ASSERT(!s_logBuf[index]);
s_logBuf[index] = (char *)ALLOC(s_logSize[index]);
s_logPos[index] = 0;
if (!s_logBuf[index])
ErrorAssert(__LINE__, __FILE__, "Out of memory");
}
//============================================================================
static void FreeLogBuffer_CS (unsigned index) {
REF(FreeLogBuffer_CS);
if (s_logBuf[index]) {
FREE(s_logBuf[index]);
s_logBuf[index] = nil;
}
}
//============================================================================
static void GetLogFilename (
unsigned index,
TimeDesc timeDesc,
wchar * filename,
unsigned chars
) {
StrPrintf(
filename,
chars,
s_logNameFmt[index],
#ifndef SERVER
ProductShortName(),
#endif
timeDesc.year % 100,
timeDesc.month,
timeDesc.day,
BuildTypeString()
);
PathAddFilename(filename, s_directory, filename, chars);
}
//============================================================================
static bool OpenLogFile_CS (unsigned index) {
if (s_logFile[index] != nil)
return true;
// Build filename
wchar filename[MAX_PATH];
GetLogFilename(
index,
s_logTime[index],
filename,
arrsize(filename)
);
// Open file
qword 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 Byte 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)
DEL(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
) {
REF(FlushLogFile_CS);
bool close = !s_running || (s_logTime[index].day != timeDesc.day);
WriteLogFile_CS(index, close);
if (close)
s_logTime[index] = timeDesc;
}
//============================================================================
static unsigned FlushLogsTimerCallback (void *) {
REF(FlushLogsTimerCallback);
AsyncLogFlush();
return kAsyncTimeInfinite;
}
} using namespace AsyncLog;
/****************************************************************************
*
* Exported functions
*
***/
//============================================================================
void AsyncLogInitialize (
const wchar 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 facility[],
ELogSeverity severity,
const wchar msg[]
) {
REF(facility);
REF(severity);
REF(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
MemCopy(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 * dest, unsigned destChars) {
ASSERT(dest);
StrCopy(dest, s_directory, destChars);
}

View File

@ -0,0 +1,136 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceThread.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/*****************************************************************************
*
* Private data
*
***/
/*****************************************************************************
*
* Internal functions
*
***/
//===========================================================================
static unsigned CALLBACK CreateThreadProc (LPVOID param) {
PerfAddCounter(kAsyncPerfThreadsTotal, 1);
PerfAddCounter(kAsyncPerfThreadsCurr, 1);
// Initialize thread
AsyncThread * thread = (AsyncThread *) param;
// Call thread procedure
unsigned result = thread->proc(thread);
// Cleanup thread
DEL(thread);
PerfSubCounter(kAsyncPerfThreadsCurr, 1);
return result;
}
/*****************************************************************************
*
* Module functions
*
***/
//============================================================================
void ThreadDestroy (unsigned exitThreadWaitMs) {
unsigned bailAt = TimeGetMs() + exitThreadWaitMs;
while (AsyncPerfGetCounter(kAsyncPerfThreadsCurr) && signed(bailAt - TimeGetMs()) > 0)
AsyncSleep(10);
}
/*****************************************************************************
*
* Public exports
*
***/
//===========================================================================
void * AsyncThreadCreate (
FAsyncThreadProc threadProc,
void * argument,
const wchar name[]
) {
AsyncThread * thread = NEW(AsyncThread);
thread->proc = threadProc;
thread->handle = nil;
thread->argument = argument;
thread->workTimeMs = kAsyncTimeInfinite;
StrCopy(thread->name, name, arrsize(thread->name));
// Create thread suspended
unsigned threadId;
HANDLE handle = (HANDLE) _beginthreadex(
(LPSECURITY_ATTRIBUTES) 0,
0, // stack size
CreateThreadProc,
thread, // argument
0, // initFlag
&threadId
);
if (!handle) {
LogMsg(kLogFatal, "%s (%u)", __FILE__, GetLastError());
ErrorFatal(__LINE__, __FILE__, "_beginthreadex failed");
}
thread->handle = handle;
return handle;
}

View File

@ -0,0 +1,368 @@
/*==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 <http://www.gnu.org/licenses/>.
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/pnAceTimer.cpp
*
***/
#include "Pch.h"
#pragma hdrstop
/****************************************************************************
*
* Private
*
***/
// timer callbacks
struct AsyncTimer {
PRIORITY_TIME(AsyncTimer) priority;
FAsyncTimerProc timerProc;
FAsyncTimerProc destroyProc;
void * param;
LINK(AsyncTimer) deleteLink;
};
static CCritSect s_timerCrit;
static FAsyncTimerProc s_timerCurr;
static HANDLE s_timerThread;
static HANDLE s_timerEvent;
static bool s_running;
static PRIQDECL(
AsyncTimer,
PRIORITY_TIME(AsyncTimer),
priority
) s_timerProcs;
static LISTDECL(
AsyncTimer,
deleteLink
) s_timerDelete;
/****************************************************************************
*
* Timer implementation
*
***/
//===========================================================================
static void UpdateTimer (
AsyncTimer * timer,
unsigned timeMs,
unsigned flags
) {
// If the timer isn't already linked then it doesn't
// matter whether kAsyncTimerUpdateSetPriorityHigher is
// set; just add the timer to the queue
if (!timer->priority.IsLinked()) {
timer->priority.Set(timeMs);
s_timerProcs.Enqueue(timer);
}
else if (((flags & kAsyncTimerUpdateSetPriorityHigher) == 0)
|| !timer->priority.IsPriorityHigher(timeMs)
) {
timer->priority.Set(timeMs);
}
}
//===========================================================================
static unsigned CallTimerProc (AsyncTimer * t, FAsyncTimerProc timerProc) {
// Cache parameters to make timer callback outside critical section
s_timerCurr = timerProc;
// Leave critical section to make timer callback
s_timerCrit.Leave();
unsigned sleepMs = s_timerCurr(t->param);
s_timerCurr = nil;
s_timerCrit.Enter();
return sleepMs;
}
//===========================================================================
// inline because it is called only once
static inline unsigned RunTimers () {
unsigned currTimeMs = TimeGetMs();
for (;;) {
// Delete old timers
while (AsyncTimer * t = s_timerDelete.Head()) {
if (t->destroyProc)
CallTimerProc(t, t->destroyProc);
DEL(t);
}
// Get first timer to run
AsyncTimer * t = s_timerProcs.Root();
if (!t)
return INFINITE;
// If it isn't time to run this timer then exit
unsigned sleepMs;
if (0 < (signed) (sleepMs = (unsigned) t->priority.Get() - currTimeMs))
return sleepMs;
// Remove from timer queue and call timer
s_timerProcs.Dequeue();
sleepMs = CallTimerProc(t, t->timerProc);
// Note if return is kAsyncTimeInfinite, we do not remove the timer
// from the queue. Some users depend on the fact that they can
// call AsyncTimerUpdate and not get overridden by a return from the
// handler at the same time.
// Requeue timer
currTimeMs = TimeGetMs();
if (sleepMs != kAsyncTimeInfinite)
UpdateTimer(t, sleepMs + currTimeMs, kAsyncTimerUpdateSetPriorityHigher);
}
}
//===========================================================================
static unsigned THREADCALL TimerThreadProc (AsyncThread *) {
do {
s_timerCrit.Enter();
const unsigned sleepMs = RunTimers();
s_timerCrit.Leave();
WaitForSingleObject(s_timerEvent, sleepMs);
} while (s_running);
return 0;
}
//===========================================================================
// inline because it is called only once
static inline void InitializeTimer () {
if (!s_timerThread) {
s_running = true;
s_timerEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) nil,
false, // auto-reset event
false, // initial state = off
(LPCTSTR) nil
);
if (!s_timerEvent)
ErrorFatal(__LINE__, __FILE__, "CreateEvent %u", GetLastError());
s_timerThread = (HANDLE) AsyncThreadCreate(
TimerThreadProc,
nil,
L"AsyncTimerThread"
);
}
}
/****************************************************************************
*
* Module functions
*
***/
//===========================================================================
void TimerDestroy (unsigned exitThreadWaitMs) {
s_running = false;
if (s_timerThread) {
SetEvent(s_timerEvent);
WaitForSingleObject(s_timerThread, exitThreadWaitMs);
CloseHandle(s_timerThread);
s_timerThread = nil;
}
if (s_timerEvent) {
CloseHandle(s_timerEvent);
s_timerEvent = nil;
}
// Cleanup any timers that have been stopped but not deleted
s_timerCrit.Enter();
while (AsyncTimer * t = s_timerDelete.Head()) {
if (t->destroyProc)
CallTimerProc(t, t->destroyProc);
DEL(t);
}
s_timerCrit.Leave();
if (AsyncTimer * timer = s_timerProcs.Root())
ErrorFatal(__LINE__, __FILE__, "TimerProc not destroyed: %p", timer->timerProc);
}
/****************************************************************************
*
* Exported functions
*
***/
//===========================================================================
// 1. Timer procs do not get starved by I/O, they are called periodically.
// 2. Timer procs will never be called by multiple threads simultaneously.
void AsyncTimerCreate (
AsyncTimer ** timer,
FAsyncTimerProc timerProc,
unsigned callbackMs,
void * param
) {
ASSERT(timer);
ASSERT(timerProc);
// Allocate timer outside critical section
AsyncTimer * t = NEW(AsyncTimer);
t->timerProc = timerProc;
t->destroyProc = nil;
t->param = param;
t->priority.Set(TimeGetMs() + callbackMs);
// Set result pointer before queueing timer
// so that the value is set before a callback
*timer = t;
bool setEvent;
s_timerCrit.Enter();
{
InitializeTimer();
// Does this timer need to be queued?
if (callbackMs != kAsyncTimeInfinite)
s_timerProcs.Enqueue(t);
// Does the timer thread need to be awakened?
setEvent = t == s_timerProcs.Root();
}
s_timerCrit.Leave();
if (setEvent)
SetEvent(s_timerEvent);
}
//===========================================================================
// Timer procs can be in the process of getting called in
// another thread during the unregister function -- be careful!
// -- waitComplete = will wait until the timer has been unregistered and is
// no longer in the process of being called before returning. The flag may only
// be set by init/destruct threads, not I/O worker threads. In addition, extreme
// care should be used to avoid a deadlock when this flag is set; in general, it
// is a good idea not to hold any locks or critical sections when setting the flag.
void AsyncTimerDelete (
AsyncTimer * timer,
unsigned flags
) {
// If the timer has already been destroyed then exit
ASSERT(timer);
// Wait for timer before exiting function?
FAsyncTimerProc timerProc;
if (flags & kAsyncTimerDestroyWaitComplete)
timerProc = timer->timerProc;
else
timerProc = nil;
AsyncTimerDeleteCallback(timer, nil);
// Wait until the timer procedure completes
if (timerProc) {
// ensure that I/O worker threads don't call this function with waitComplete=true
// to prevent a possible deadlock of a timer callback waiting for itself to complete
ThreadAssertCanBlock(__FILE__, __LINE__);
while (s_timerCurr == timerProc)
Sleep(1);
}
}
//===========================================================================
void AsyncTimerDeleteCallback (
AsyncTimer * timer,
FAsyncTimerProc destroyProc
) {
// If the timer has already been destroyed then exit
ASSERT(timer);
ASSERT(!timer->deleteLink.IsLinked());
// Link the timer to the deletion list
s_timerCrit.Enter();
{
timer->destroyProc = destroyProc;
s_timerDelete.Link(timer);
}
s_timerCrit.Leave();
// Force the timer thread to wake up and perform the deletion
if (destroyProc)
SetEvent(s_timerEvent);
}
//===========================================================================
// To set the time value for a timer, use this function with flags = 0.
// To set the time to MoreRecentOf(nextTimerCallbackMs, callbackMs), use SETPRIORITYHIGHER
void AsyncTimerUpdate (
AsyncTimer * timer,
unsigned callbackMs,
unsigned flags
) {
ASSERT(timer);
bool setEvent;
s_timerCrit.Enter();
{
if (callbackMs != kAsyncTimeInfinite) {
UpdateTimer(timer, callbackMs + TimeGetMs(), flags);
setEvent = timer == s_timerProcs.Root();
}
else {
if ((flags & kAsyncTimerUpdateSetPriorityHigher) == 0)
timer->priority.Unlink();
setEvent = false;
}
}
s_timerCrit.Leave();
if (setEvent)
SetEvent(s_timerEvent);
}