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,379 +1,379 @@
|
||||
/*==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/pnIniExe/Private/Win32/pnW32IniChange.cpp
|
||||
*
|
||||
***/
|
||||
|
||||
#include "../../Pch.h"
|
||||
#pragma hdrstop
|
||||
|
||||
|
||||
#ifdef HS_BUILD_FOR_WIN32
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private
|
||||
*
|
||||
***/
|
||||
|
||||
struct IniChangeFile;
|
||||
|
||||
struct IniChangeReg {
|
||||
LINK(IniChangeReg) fLink;
|
||||
FIniFileChangeCallback fNotify;
|
||||
qword fLastWriteTime;
|
||||
wchar fFileName[MAX_PATH];
|
||||
};
|
||||
|
||||
static CLock s_lock;
|
||||
static HANDLE s_event;
|
||||
static HANDLE s_signal;
|
||||
static HANDLE s_thread;
|
||||
static HANDLE s_change;
|
||||
static bool s_running;
|
||||
static IniChangeReg * s_dispatch;
|
||||
static wchar s_directory[MAX_PATH];
|
||||
static LISTDECL(IniChangeReg, fLink) s_callbacks;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Change notification
|
||||
*
|
||||
***/
|
||||
|
||||
//===========================================================================
|
||||
static qword GetFileTimestamp (const wchar fileName[]) {
|
||||
HANDLE find;
|
||||
WIN32_FIND_DATAW fd;
|
||||
qword lastWriteTime;
|
||||
if (INVALID_HANDLE_VALUE != (find = FindFirstFileW(fileName, &fd))) {
|
||||
COMPILER_ASSERT(sizeof(lastWriteTime) == sizeof(fd.ftLastWriteTime));
|
||||
lastWriteTime = * (const qword *) &fd.ftLastWriteTime;
|
||||
FindClose(find);
|
||||
}
|
||||
else {
|
||||
lastWriteTime = 1; // any non-zero, non-valid number
|
||||
}
|
||||
|
||||
return lastWriteTime;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
static void ChangeDispatch_WL (IniChangeReg * marker) {
|
||||
|
||||
while (nil != (s_dispatch = s_callbacks.Next(marker))) {
|
||||
// Move the marker to the next location
|
||||
s_callbacks.Link(marker, kListLinkAfter, s_dispatch);
|
||||
|
||||
// If the file record time matches the file data time
|
||||
// then there's no need to reprocess the callbacks
|
||||
qword lastWriteTime = GetFileTimestamp(s_dispatch->fFileName);
|
||||
if (s_dispatch->fLastWriteTime == lastWriteTime)
|
||||
continue;
|
||||
s_dispatch->fLastWriteTime = lastWriteTime;
|
||||
|
||||
// Leave lock to perform callback
|
||||
s_lock.LeaveWrite();
|
||||
s_dispatch->fNotify(s_dispatch->fFileName);
|
||||
s_lock.EnterWrite();
|
||||
}
|
||||
|
||||
// List traversal complete
|
||||
SetEvent(s_signal);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
static unsigned THREADCALL IniSrvThreadProc (AsyncThread * thread) {
|
||||
IniChangeReg marker;
|
||||
marker.fNotify = nil;
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Link(&marker, kListHead);
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
HANDLE handles[2];
|
||||
handles[0] = s_change;
|
||||
handles[1] = s_event;
|
||||
unsigned sleepMs = INFINITE;
|
||||
for (;;) {
|
||||
|
||||
// Wait until something happens
|
||||
unsigned result = WaitForMultipleObjects(
|
||||
arrsize(handles),
|
||||
handles,
|
||||
false,
|
||||
sleepMs
|
||||
);
|
||||
if (!s_running)
|
||||
break;
|
||||
|
||||
// reset the sleep time
|
||||
sleepMs = INFINITE;
|
||||
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
if (!FindNextChangeNotification(s_change)) {
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniSrv: FindNextChangeNotification() failed %#x",
|
||||
GetLastError()
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// a change notification occurs when a file is created, even
|
||||
// though it may take a number of seconds before the file data
|
||||
// has been copied. Wait a few seconds after the last change
|
||||
// notification so that files have a chance to stabilize.
|
||||
sleepMs = 5 * 1000;
|
||||
|
||||
// When the timeout occurs, reprocess the entire list
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Link(&marker, kListHead);
|
||||
s_lock.LeaveWrite();
|
||||
}
|
||||
else if ((result == WAIT_OBJECT_0 + 1) || (result == WAIT_TIMEOUT)) {
|
||||
// Queue for deadlock check
|
||||
#ifdef SERVER
|
||||
void * check = CrashAddDeadlockCheck(thread->handle, L"plW32IniChange.NtWorkerThreadProc");
|
||||
#endif
|
||||
|
||||
s_lock.EnterWrite();
|
||||
ChangeDispatch_WL(&marker);
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Unqueue for deadlock check
|
||||
#ifdef SERVER
|
||||
CrashRemoveDeadlockCheck(check);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniChange: WaitForMultipleObjects failed %#x",
|
||||
GetLastError()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Unlink(&marker);
|
||||
s_lock.LeaveWrite();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exports
|
||||
*
|
||||
***/
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeInitialize (const wchar dir[]) {
|
||||
ASSERT(!s_running);
|
||||
s_running = true;
|
||||
|
||||
const char * function;
|
||||
for (;;) {
|
||||
// Create the config directory
|
||||
PathGetProgramDirectory(s_directory, arrsize(s_directory));
|
||||
PathAddFilename(s_directory, s_directory, dir, arrsize(s_directory));
|
||||
if (EPathCreateDirError error = PathCreateDirectory(s_directory, 0))
|
||||
LogMsg(kLogError, "IniChange: CreateDir failed %u", error);
|
||||
|
||||
// Open change notification for directory
|
||||
s_change = FindFirstChangeNotificationW(
|
||||
s_directory,
|
||||
false, // watchSubTree = false
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME
|
||||
);
|
||||
if (!s_change) {
|
||||
function = "FindFirstChangeNotification";
|
||||
break;
|
||||
}
|
||||
|
||||
// create thread event
|
||||
s_event = CreateEvent(
|
||||
(LPSECURITY_ATTRIBUTES) 0,
|
||||
false, // auto-reset
|
||||
false, // initial state off
|
||||
(LPCTSTR) 0 // name
|
||||
);
|
||||
if (!s_event) {
|
||||
function = "CreateEvent";
|
||||
break;
|
||||
}
|
||||
|
||||
// create signal event
|
||||
s_signal = CreateEvent(
|
||||
(LPSECURITY_ATTRIBUTES) 0,
|
||||
true, // manual-reset
|
||||
false, // initial state off
|
||||
(LPCTSTR) 0 // name
|
||||
);
|
||||
if (!s_signal) {
|
||||
function = "CreateEvent";
|
||||
break;
|
||||
}
|
||||
|
||||
// create thread
|
||||
s_thread = (HANDLE) AsyncThreadCreate(
|
||||
IniSrvThreadProc,
|
||||
nil,
|
||||
L"IniSrvChange"
|
||||
);
|
||||
if (!s_thread) {
|
||||
function = "AsyncThreadCreate";
|
||||
break;
|
||||
}
|
||||
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
|
||||
// Failure!
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniChange: %s failed (%#x)",
|
||||
function,
|
||||
GetLastError()
|
||||
);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeDestroy () {
|
||||
s_running = false;
|
||||
|
||||
if (s_thread) {
|
||||
SetEvent(s_event);
|
||||
WaitForSingleObject(s_thread, INFINITE);
|
||||
CloseHandle(s_thread);
|
||||
s_thread = nil;
|
||||
}
|
||||
if (s_event) {
|
||||
CloseHandle(s_event);
|
||||
s_event = nil;
|
||||
}
|
||||
if (s_signal) {
|
||||
CloseHandle(s_signal);
|
||||
s_signal = nil;
|
||||
}
|
||||
if (s_change) {
|
||||
FindCloseChangeNotification(s_change);
|
||||
s_change = nil;
|
||||
}
|
||||
|
||||
ASSERT(!s_callbacks.Head());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeAdd (
|
||||
const wchar fileName[],
|
||||
FIniFileChangeCallback callback,
|
||||
IniChangeReg ** changePtr
|
||||
) {
|
||||
ASSERT(fileName);
|
||||
ASSERT(callback);
|
||||
ASSERT(changePtr);
|
||||
ASSERT(s_running);
|
||||
|
||||
// Create a callback record
|
||||
IniChangeReg * change = NEW(IniChangeReg);
|
||||
change->fNotify = callback;
|
||||
change->fLastWriteTime = 0;
|
||||
PathAddFilename(
|
||||
change->fFileName,
|
||||
s_directory,
|
||||
fileName,
|
||||
arrsize(change->fFileName)
|
||||
);
|
||||
PathRemoveExtension(change->fFileName, change->fFileName, arrsize(change->fFileName));
|
||||
PathAddExtension(change->fFileName, change->fFileName, L".ini", arrsize(change->fFileName));
|
||||
|
||||
// Set result before callback to avoid race condition
|
||||
*changePtr = change;
|
||||
|
||||
// Signal change record for immediate callback
|
||||
// and wait for callback completion
|
||||
IniChangeSignal(change, true);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeRemove (
|
||||
IniChangeReg * change,
|
||||
bool wait
|
||||
) {
|
||||
ASSERT(change);
|
||||
|
||||
s_lock.EnterWrite();
|
||||
{
|
||||
// Wait until the callback is no longer being dispatched
|
||||
if (wait) {
|
||||
while (s_dispatch == change) {
|
||||
s_lock.LeaveWrite();
|
||||
AsyncSleep(10);
|
||||
s_lock.EnterWrite();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove change object from list so that
|
||||
// it can be deleted outside the lock
|
||||
change->fLink.Unlink();
|
||||
}
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Delete object outside critical section
|
||||
DEL(change);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeSignal (
|
||||
IniChangeReg * change,
|
||||
bool wait
|
||||
) {
|
||||
ASSERT(change);
|
||||
|
||||
s_lock.EnterWrite();
|
||||
{
|
||||
s_callbacks.Link(change, kListTail);
|
||||
change->fLastWriteTime = 0;
|
||||
ResetEvent(s_signal);
|
||||
}
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Wake up the change thread to process this request
|
||||
SetEvent(s_event);
|
||||
|
||||
// Wait until the request has been processed
|
||||
if (wait)
|
||||
WaitForSingleObject(s_signal, INFINITE);
|
||||
}
|
||||
|
||||
#endif // HS_BUILD_FOR_WIN32
|
||||
/*==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/pnIniExe/Private/Win32/pnW32IniChange.cpp
|
||||
*
|
||||
***/
|
||||
|
||||
#include "../../Pch.h"
|
||||
#pragma hdrstop
|
||||
|
||||
|
||||
#ifdef HS_BUILD_FOR_WIN32
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private
|
||||
*
|
||||
***/
|
||||
|
||||
struct IniChangeFile;
|
||||
|
||||
struct IniChangeReg {
|
||||
LINK(IniChangeReg) fLink;
|
||||
FIniFileChangeCallback fNotify;
|
||||
qword fLastWriteTime;
|
||||
wchar fFileName[MAX_PATH];
|
||||
};
|
||||
|
||||
static CLock s_lock;
|
||||
static HANDLE s_event;
|
||||
static HANDLE s_signal;
|
||||
static HANDLE s_thread;
|
||||
static HANDLE s_change;
|
||||
static bool s_running;
|
||||
static IniChangeReg * s_dispatch;
|
||||
static wchar s_directory[MAX_PATH];
|
||||
static LISTDECL(IniChangeReg, fLink) s_callbacks;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Change notification
|
||||
*
|
||||
***/
|
||||
|
||||
//===========================================================================
|
||||
static qword GetFileTimestamp (const wchar fileName[]) {
|
||||
HANDLE find;
|
||||
WIN32_FIND_DATAW fd;
|
||||
qword lastWriteTime;
|
||||
if (INVALID_HANDLE_VALUE != (find = FindFirstFileW(fileName, &fd))) {
|
||||
COMPILER_ASSERT(sizeof(lastWriteTime) == sizeof(fd.ftLastWriteTime));
|
||||
lastWriteTime = * (const qword *) &fd.ftLastWriteTime;
|
||||
FindClose(find);
|
||||
}
|
||||
else {
|
||||
lastWriteTime = 1; // any non-zero, non-valid number
|
||||
}
|
||||
|
||||
return lastWriteTime;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
static void ChangeDispatch_WL (IniChangeReg * marker) {
|
||||
|
||||
while (nil != (s_dispatch = s_callbacks.Next(marker))) {
|
||||
// Move the marker to the next location
|
||||
s_callbacks.Link(marker, kListLinkAfter, s_dispatch);
|
||||
|
||||
// If the file record time matches the file data time
|
||||
// then there's no need to reprocess the callbacks
|
||||
qword lastWriteTime = GetFileTimestamp(s_dispatch->fFileName);
|
||||
if (s_dispatch->fLastWriteTime == lastWriteTime)
|
||||
continue;
|
||||
s_dispatch->fLastWriteTime = lastWriteTime;
|
||||
|
||||
// Leave lock to perform callback
|
||||
s_lock.LeaveWrite();
|
||||
s_dispatch->fNotify(s_dispatch->fFileName);
|
||||
s_lock.EnterWrite();
|
||||
}
|
||||
|
||||
// List traversal complete
|
||||
SetEvent(s_signal);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
static unsigned THREADCALL IniSrvThreadProc (AsyncThread * thread) {
|
||||
IniChangeReg marker;
|
||||
marker.fNotify = nil;
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Link(&marker, kListHead);
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
HANDLE handles[2];
|
||||
handles[0] = s_change;
|
||||
handles[1] = s_event;
|
||||
unsigned sleepMs = INFINITE;
|
||||
for (;;) {
|
||||
|
||||
// Wait until something happens
|
||||
unsigned result = WaitForMultipleObjects(
|
||||
arrsize(handles),
|
||||
handles,
|
||||
false,
|
||||
sleepMs
|
||||
);
|
||||
if (!s_running)
|
||||
break;
|
||||
|
||||
// reset the sleep time
|
||||
sleepMs = INFINITE;
|
||||
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
if (!FindNextChangeNotification(s_change)) {
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniSrv: FindNextChangeNotification() failed %#x",
|
||||
GetLastError()
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// a change notification occurs when a file is created, even
|
||||
// though it may take a number of seconds before the file data
|
||||
// has been copied. Wait a few seconds after the last change
|
||||
// notification so that files have a chance to stabilize.
|
||||
sleepMs = 5 * 1000;
|
||||
|
||||
// When the timeout occurs, reprocess the entire list
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Link(&marker, kListHead);
|
||||
s_lock.LeaveWrite();
|
||||
}
|
||||
else if ((result == WAIT_OBJECT_0 + 1) || (result == WAIT_TIMEOUT)) {
|
||||
// Queue for deadlock check
|
||||
#ifdef SERVER
|
||||
void * check = CrashAddDeadlockCheck(thread->handle, L"plW32IniChange.NtWorkerThreadProc");
|
||||
#endif
|
||||
|
||||
s_lock.EnterWrite();
|
||||
ChangeDispatch_WL(&marker);
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Unqueue for deadlock check
|
||||
#ifdef SERVER
|
||||
CrashRemoveDeadlockCheck(check);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniChange: WaitForMultipleObjects failed %#x",
|
||||
GetLastError()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
s_lock.EnterWrite();
|
||||
s_callbacks.Unlink(&marker);
|
||||
s_lock.LeaveWrite();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Exports
|
||||
*
|
||||
***/
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeInitialize (const wchar dir[]) {
|
||||
ASSERT(!s_running);
|
||||
s_running = true;
|
||||
|
||||
const char * function;
|
||||
for (;;) {
|
||||
// Create the config directory
|
||||
PathGetProgramDirectory(s_directory, arrsize(s_directory));
|
||||
PathAddFilename(s_directory, s_directory, dir, arrsize(s_directory));
|
||||
if (EPathCreateDirError error = PathCreateDirectory(s_directory, 0))
|
||||
LogMsg(kLogError, "IniChange: CreateDir failed %u", error);
|
||||
|
||||
// Open change notification for directory
|
||||
s_change = FindFirstChangeNotificationW(
|
||||
s_directory,
|
||||
false, // watchSubTree = false
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME
|
||||
);
|
||||
if (!s_change) {
|
||||
function = "FindFirstChangeNotification";
|
||||
break;
|
||||
}
|
||||
|
||||
// create thread event
|
||||
s_event = CreateEvent(
|
||||
(LPSECURITY_ATTRIBUTES) 0,
|
||||
false, // auto-reset
|
||||
false, // initial state off
|
||||
(LPCTSTR) 0 // name
|
||||
);
|
||||
if (!s_event) {
|
||||
function = "CreateEvent";
|
||||
break;
|
||||
}
|
||||
|
||||
// create signal event
|
||||
s_signal = CreateEvent(
|
||||
(LPSECURITY_ATTRIBUTES) 0,
|
||||
true, // manual-reset
|
||||
false, // initial state off
|
||||
(LPCTSTR) 0 // name
|
||||
);
|
||||
if (!s_signal) {
|
||||
function = "CreateEvent";
|
||||
break;
|
||||
}
|
||||
|
||||
// create thread
|
||||
s_thread = (HANDLE) AsyncThreadCreate(
|
||||
IniSrvThreadProc,
|
||||
nil,
|
||||
L"IniSrvChange"
|
||||
);
|
||||
if (!s_thread) {
|
||||
function = "AsyncThreadCreate";
|
||||
break;
|
||||
}
|
||||
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
|
||||
// Failure!
|
||||
LogMsg(
|
||||
kLogError,
|
||||
"IniChange: %s failed (%#x)",
|
||||
function,
|
||||
GetLastError()
|
||||
);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeDestroy () {
|
||||
s_running = false;
|
||||
|
||||
if (s_thread) {
|
||||
SetEvent(s_event);
|
||||
WaitForSingleObject(s_thread, INFINITE);
|
||||
CloseHandle(s_thread);
|
||||
s_thread = nil;
|
||||
}
|
||||
if (s_event) {
|
||||
CloseHandle(s_event);
|
||||
s_event = nil;
|
||||
}
|
||||
if (s_signal) {
|
||||
CloseHandle(s_signal);
|
||||
s_signal = nil;
|
||||
}
|
||||
if (s_change) {
|
||||
FindCloseChangeNotification(s_change);
|
||||
s_change = nil;
|
||||
}
|
||||
|
||||
ASSERT(!s_callbacks.Head());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeAdd (
|
||||
const wchar fileName[],
|
||||
FIniFileChangeCallback callback,
|
||||
IniChangeReg ** changePtr
|
||||
) {
|
||||
ASSERT(fileName);
|
||||
ASSERT(callback);
|
||||
ASSERT(changePtr);
|
||||
ASSERT(s_running);
|
||||
|
||||
// Create a callback record
|
||||
IniChangeReg * change = NEW(IniChangeReg);
|
||||
change->fNotify = callback;
|
||||
change->fLastWriteTime = 0;
|
||||
PathAddFilename(
|
||||
change->fFileName,
|
||||
s_directory,
|
||||
fileName,
|
||||
arrsize(change->fFileName)
|
||||
);
|
||||
PathRemoveExtension(change->fFileName, change->fFileName, arrsize(change->fFileName));
|
||||
PathAddExtension(change->fFileName, change->fFileName, L".ini", arrsize(change->fFileName));
|
||||
|
||||
// Set result before callback to avoid race condition
|
||||
*changePtr = change;
|
||||
|
||||
// Signal change record for immediate callback
|
||||
// and wait for callback completion
|
||||
IniChangeSignal(change, true);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeRemove (
|
||||
IniChangeReg * change,
|
||||
bool wait
|
||||
) {
|
||||
ASSERT(change);
|
||||
|
||||
s_lock.EnterWrite();
|
||||
{
|
||||
// Wait until the callback is no longer being dispatched
|
||||
if (wait) {
|
||||
while (s_dispatch == change) {
|
||||
s_lock.LeaveWrite();
|
||||
AsyncSleep(10);
|
||||
s_lock.EnterWrite();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove change object from list so that
|
||||
// it can be deleted outside the lock
|
||||
change->fLink.Unlink();
|
||||
}
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Delete object outside critical section
|
||||
DEL(change);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
void IniChangeSignal (
|
||||
IniChangeReg * change,
|
||||
bool wait
|
||||
) {
|
||||
ASSERT(change);
|
||||
|
||||
s_lock.EnterWrite();
|
||||
{
|
||||
s_callbacks.Link(change, kListTail);
|
||||
change->fLastWriteTime = 0;
|
||||
ResetEvent(s_signal);
|
||||
}
|
||||
s_lock.LeaveWrite();
|
||||
|
||||
// Wake up the change thread to process this request
|
||||
SetEvent(s_event);
|
||||
|
||||
// Wait until the request has been processed
|
||||
if (wait)
|
||||
WaitForSingleObject(s_signal, INFINITE);
|
||||
}
|
||||
|
||||
#endif // HS_BUILD_FOR_WIN32
|
||||
|
Reference in New Issue
Block a user