mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 02:27:40 -04:00
Fix line endings and tabs
This commit is contained in:
@ -1,384 +1,384 @@
|
||||
/*==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/>.
|
||||
|
||||
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();
|
||||
}
|
||||
/*==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/>.
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -1,261 +1,261 @@
|
||||
/*==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/>.
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
/*==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/>.
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user