mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
PingPlugin.dll: Removed use of TerminateThread
Instead of termination in Finalize(), the thread is left to run and perform required cleanup before exit. This also fixes a memory leak caused by termination in some cases.
This commit is contained in:
parent
5634333e60
commit
e4cceb8512
@ -21,8 +21,6 @@
|
|||||||
#include <Icmpapi.h>
|
#include <Icmpapi.h>
|
||||||
#include "../../Library/Export.h" // Rainmeter's exported functions
|
#include "../../Library/Export.h" // Rainmeter's exported functions
|
||||||
|
|
||||||
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
|
|
||||||
|
|
||||||
struct MeasureData
|
struct MeasureData
|
||||||
{
|
{
|
||||||
IPAddr destAddr;
|
IPAddr destAddr;
|
||||||
@ -30,7 +28,7 @@ struct MeasureData
|
|||||||
double timeoutValue;
|
double timeoutValue;
|
||||||
DWORD updateRate;
|
DWORD updateRate;
|
||||||
DWORD updateCounter;
|
DWORD updateCounter;
|
||||||
HANDLE threadHandle;
|
bool threadActive;
|
||||||
double value;
|
double value;
|
||||||
|
|
||||||
MeasureData() :
|
MeasureData() :
|
||||||
@ -39,26 +37,37 @@ struct MeasureData
|
|||||||
timeoutValue(),
|
timeoutValue(),
|
||||||
updateRate(),
|
updateRate(),
|
||||||
updateCounter(),
|
updateCounter(),
|
||||||
threadHandle(),
|
threadActive(false),
|
||||||
value()
|
value()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static CRITICAL_SECTION g_CriticalSection;
|
static CRITICAL_SECTION g_CriticalSection;
|
||||||
static UINT g_Instances = 0;
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||||
|
{
|
||||||
|
switch (fdwReason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
InitializeCriticalSection(&g_CriticalSection);
|
||||||
|
|
||||||
|
// Disable DLL_THREAD_ATTACH and DLL_THREAD_DETACH notification calls.
|
||||||
|
DisableThreadLibraryCalls(hinstDLL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
DeleteCriticalSection(&g_CriticalSection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
PLUGIN_EXPORT void Initialize(void** data, void* rm)
|
||||||
{
|
{
|
||||||
MeasureData* measure = new MeasureData;
|
MeasureData* measure = new MeasureData;
|
||||||
*data = measure;
|
*data = measure;
|
||||||
|
|
||||||
if (g_Instances == 0)
|
|
||||||
{
|
|
||||||
InitializeCriticalSection(&g_CriticalSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
++g_Instances;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
||||||
@ -108,59 +117,71 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
|
|||||||
measure->timeoutValue = RmReadDouble(rm, L"TimeoutValue", 30000.0);
|
measure->timeoutValue = RmReadDouble(rm, L"TimeoutValue", 30000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI NetworkThreadProc(LPVOID pParam)
|
DWORD WINAPI NetworkThreadProc(void* pParam)
|
||||||
{
|
{
|
||||||
|
// NOTE: Do not use CRT functions (since thread was created by CreateThread())!
|
||||||
|
|
||||||
MeasureData* measure = (MeasureData*)pParam;
|
MeasureData* measure = (MeasureData*)pParam;
|
||||||
|
const DWORD bufferSize = sizeof(ICMP_ECHO_REPLY) + 32;
|
||||||
|
BYTE buffer[bufferSize];
|
||||||
|
|
||||||
const DWORD replySize = sizeof(ICMP_ECHO_REPLY) + 32;
|
double value = 0.0;
|
||||||
BYTE* reply = new BYTE[replySize];
|
|
||||||
|
|
||||||
HANDLE hIcmpFile = IcmpCreateFile();
|
HANDLE hIcmpFile = IcmpCreateFile();
|
||||||
|
|
||||||
if (hIcmpFile != INVALID_HANDLE_VALUE)
|
if (hIcmpFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
IcmpSendEcho(hIcmpFile, measure->destAddr, NULL, 0, NULL, reply, replySize, measure->timeout);
|
IcmpSendEcho(hIcmpFile, measure->destAddr, NULL, 0, NULL, buffer, bufferSize, measure->timeout);
|
||||||
IcmpCloseHandle(hIcmpFile);
|
IcmpCloseHandle(hIcmpFile);
|
||||||
|
|
||||||
|
ICMP_ECHO_REPLY* reply = (ICMP_ECHO_REPLY*)buffer;
|
||||||
|
value = (reply->Status == IP_REQ_TIMED_OUT) ? measure->timeoutValue : reply->RoundTripTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnterCriticalSection(&g_CriticalSection);
|
HMODULE module = NULL;
|
||||||
|
|
||||||
ICMP_ECHO_REPLY* pReply = (ICMP_ECHO_REPLY*)reply;
|
EnterCriticalSection(&g_CriticalSection);
|
||||||
if (pReply->Status == IP_REQ_TIMED_OUT)
|
if (measure->threadActive)
|
||||||
{
|
{
|
||||||
measure->value = measure->timeoutValue;
|
measure->value = value;
|
||||||
|
measure->threadActive = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
measure->value = pReply->RoundTripTime;
|
// Thread is not attached to an existing measure any longer, so delete
|
||||||
|
// unreferenced data.
|
||||||
|
delete measure;
|
||||||
|
|
||||||
|
DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
|
||||||
|
GetModuleHandleEx(flags, (LPCWSTR)DllMain, &module);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] reply;
|
|
||||||
|
|
||||||
CloseHandle(measure->threadHandle);
|
|
||||||
measure->threadHandle = NULL;
|
|
||||||
|
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
|
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
// Decrement the ref count and possibly unload the module if this is
|
||||||
|
// the last instance.
|
||||||
|
FreeLibraryAndExitThread(module, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUGIN_EXPORT double Update(void* data)
|
PLUGIN_EXPORT double Update(void* data)
|
||||||
{
|
{
|
||||||
MeasureData* measure = (MeasureData*)data;
|
MeasureData* measure = (MeasureData*)data;
|
||||||
double value = 0.0;
|
|
||||||
|
|
||||||
EnterCriticalSection(&g_CriticalSection);
|
EnterCriticalSection(&g_CriticalSection);
|
||||||
value = measure->value;
|
if (!measure->threadActive)
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
|
||||||
|
|
||||||
if (measure->threadHandle == NULL)
|
|
||||||
{
|
{
|
||||||
if (measure->updateCounter == 0)
|
if (measure->updateCounter == 0)
|
||||||
{
|
{
|
||||||
// Launch a new thread to fetch the web data
|
// Launch a new thread to fetch the web data
|
||||||
DWORD id;
|
DWORD id;
|
||||||
measure->threadHandle = CreateThread(NULL, 0, NetworkThreadProc, measure, 0, &id);
|
HANDLE thread = CreateThread(NULL, 0, NetworkThreadProc, measure, 0, &id);
|
||||||
|
if (thread)
|
||||||
|
{
|
||||||
|
CloseHandle(thread);
|
||||||
|
measure->threadActive = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measure->updateCounter++;
|
measure->updateCounter++;
|
||||||
@ -170,6 +191,9 @@ PLUGIN_EXPORT double Update(void* data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double value = measure->value;
|
||||||
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,18 +202,20 @@ PLUGIN_EXPORT void Finalize(void* data)
|
|||||||
MeasureData* measure = (MeasureData*)data;
|
MeasureData* measure = (MeasureData*)data;
|
||||||
|
|
||||||
EnterCriticalSection(&g_CriticalSection);
|
EnterCriticalSection(&g_CriticalSection);
|
||||||
if (measure->threadHandle)
|
if (measure->threadActive)
|
||||||
{
|
{
|
||||||
// Should really wait until the thread finishes instead terminating it...
|
// Increment ref count of this module so that it will not be unloaded prior to
|
||||||
TerminateThread(measure->threadHandle, 0);
|
// thread completion.
|
||||||
|
DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
|
||||||
|
HMODULE module;
|
||||||
|
GetModuleHandleEx(flags, (LPCWSTR)DllMain, &module);
|
||||||
|
|
||||||
|
// Thread will perform cleanup.
|
||||||
|
measure->threadActive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete measure;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&g_CriticalSection);
|
LeaveCriticalSection(&g_CriticalSection);
|
||||||
|
|
||||||
--g_Instances;
|
|
||||||
if (g_Instances == 0)
|
|
||||||
{
|
|
||||||
DeleteCriticalSection(&g_CriticalSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete measure;
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user