windows-nt/Source/XPSP1/NT/sdktools/perflog/pdlsvc/pdlsvc.c

392 lines
11 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
pdlsvc.c
Abstract:
service to log performance data
Author:
Bob Watson (a-robw) 10 Apr 96
Revision History:
--*/
#ifndef UNICODE
#define UNICODE 1
#endif
#ifndef _UNICODE
#define _UNICODE 1
#endif
//
// Windows Include files
//
#include <windows.h>
#include <tchar.h>
#include "pdlsvc.h"
#include "pdlmsg.h"
// Global variables used by all modules
HANDLE hEventLog = NULL;
PLOG_COUNTER_INFO pFirstCounter = NULL;
SERVICE_STATUS_HANDLE hPerfLogStatus;
SERVICE_STATUS ssPerfLogStatus;
// Static variables used by this module only
static LPLOG_THREAD_DATA pFirstThread = NULL;
static HANDLE *pThreadHandleArray = NULL;
static DWORD dwHandleCount = 0;
static DWORD dwMaxHandleCount = 0;
// this is for the time being, until full multiple log query
// support is added
#define LOCAL_HANDLE_COUNT 1
static HANDLE LocalThreadArray[LOCAL_HANDLE_COUNT];
// functions
void FreeThreadData (
IN LPLOG_THREAD_DATA pThisThread
)
{
if (pThisThread->next != NULL) {
// free the "downstream" entries
FreeThreadData (pThisThread->next);
pThisThread->next = NULL;
}
// now free this entry
if (pThisThread->mszCounterList != NULL) {
G_FREE (pThisThread->mszCounterList);
pThisThread->mszCounterList = NULL;
}
if (pThisThread->hExitEvent != NULL) {
CloseHandle (pThisThread->hExitEvent);
pThisThread->hExitEvent = NULL;
}
if (pThisThread->hKeyQuery != NULL) {
RegCloseKey (pThisThread->hKeyQuery);
pThisThread->hKeyQuery = NULL;
}
G_FREE (pThisThread);
}
void PerfDataLogServiceControlHandler(
IN DWORD dwControl
)
{
LPLOG_THREAD_DATA pThisThread;
switch (dwControl) {
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
// stop logging & close queries and files
// set stop event for all running threads
pThisThread = pFirstThread;
while (pThisThread != NULL) {
SetEvent (pThisThread->hExitEvent);
pThisThread = pThisThread->next;
}
break;
case SERVICE_CONTROL_PAUSE:
// stop logging, close queries and files
// not supported, yet
break;
case SERVICE_CONTROL_CONTINUE:
// reload configuration and restart logging
// not supported, yet
break;
case SERVICE_CONTROL_INTERROGATE:
// update current status
default:
// report to event log that an unrecognized control
// request was received.
;
}
}
void
PerfDataLogServiceStart (
IN DWORD argc,
IN LPTSTR *argv
)
{
LONG lStatus;
HKEY hKeyLogQueries;
HKEY hKeyThisLogQuery;
DWORD dwQueryIndex;
TCHAR szQueryNameBuffer[MAX_PATH];
DWORD dwQueryNameBufferSize;
TCHAR szQueryClassBuffer[MAX_PATH];
DWORD dwQueryClassBufferSize;
LPLOG_THREAD_DATA lpThreadData;
HANDLE hThread;
LPTSTR szStringArray[2];
DWORD dwThreadId;
ssPerfLogStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssPerfLogStatus.dwCurrentState = SERVICE_START_PENDING;
ssPerfLogStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
// SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;
ssPerfLogStatus.dwWin32ExitCode = 0;
ssPerfLogStatus.dwServiceSpecificExitCode = 0;
ssPerfLogStatus.dwCheckPoint = 0;
ssPerfLogStatus.dwWaitHint = 0;
hPerfLogStatus = RegisterServiceCtrlHandler (
TEXT("PerfDataLog"), PerfDataLogServiceControlHandler);
if (hPerfLogStatus == (SERVICE_STATUS_HANDLE)0) {
lStatus = GetLastError();
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE,
0,
PERFLOG_UNABLE_REGISTER_HANDLER,
NULL,
0,
sizeof(DWORD),
NULL,
(LPVOID)&lStatus);
// this is fatal so bail out
return;
}
// registered the service successfully, so load the log queries
// assign the handle buffer
pThreadHandleArray = &LocalThreadArray[0];
dwMaxHandleCount = LOCAL_HANDLE_COUNT;
// open (each) query
lStatus = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Services\\PerfDataLog\\Log Queries"),
0L,
KEY_READ,
&hKeyLogQueries);
if (lStatus != ERROR_SUCCESS) {
// unable to read the log query information from the registry
lStatus = GetLastError();
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE,
0,
PERFLOG_UNABLE_OPEN_LOG_QUERY,
NULL,
0,
sizeof(DWORD),
NULL,
(LPVOID)&lStatus);
// we can't start the service with out the evnt log.
ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
return;
}
// enumerate and start the queries in the registry
dwQueryIndex = 0;
*szQueryNameBuffer = 0;
dwQueryNameBufferSize = MAX_PATH;
*szQueryClassBuffer;
dwQueryClassBufferSize = MAX_PATH;
while ((lStatus = RegEnumKeyEx (
hKeyLogQueries,
dwQueryIndex,
szQueryNameBuffer,
&dwQueryNameBufferSize,
NULL,
szQueryClassBuffer,
&dwQueryClassBufferSize,
NULL)) != ERROR_NO_MORE_ITEMS) {
// open this key
lStatus = RegOpenKeyEx (
hKeyLogQueries,
szQueryNameBuffer,
0L,
KEY_READ | KEY_WRITE,
&hKeyThisLogQuery);
if (lStatus != ERROR_SUCCESS) {
szStringArray[0] = szQueryNameBuffer;
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE,
0,
PERFLOG_UNABLE_READ_LOG_QUERY,
NULL,
1,
sizeof(DWORD),
szStringArray,
(LPVOID)&lStatus);
// skip to next item
goto CONTINUE_ENUM_LOOP;
}
// update the service status
ssPerfLogStatus.dwCheckPoint++;
SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
// allocate a thread info block.
lpThreadData = G_ALLOC (sizeof(LOG_THREAD_DATA));
if (lpThreadData == NULL) {
lStatus = GetLastError();
szStringArray[0] = szQueryNameBuffer;
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE,
0,
PERFLOG_UNABLE_ALLOCATE_DATABLOCK,
NULL,
1,
sizeof(DWORD),
szStringArray,
(LPVOID)&lStatus);
goto CONTINUE_ENUM_LOOP;
}
// initialize the thread data block
lpThreadData->hKeyQuery = hKeyThisLogQuery;
lpThreadData->hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
lpThreadData->bReloadNewConfig = FALSE;
lstrcpy (lpThreadData->szQueryName, szQueryNameBuffer);
// start logging thread
hThread = CreateThread (
NULL, 0, LoggingThreadProc,
(LPVOID)lpThreadData, 0, &dwThreadId);
if (hThread != NULL) {
// add it to the list and continue
if (pFirstThread == NULL) {
// then this is the first thread so add it
lpThreadData->next = NULL;
pFirstThread = lpThreadData;
} else {
// insert this at the head of the list since
// that's the easiest and the order isn't
// really important
lpThreadData->next = pFirstThread;
pFirstThread = lpThreadData;
}
// add thread to array for termination wait
if (dwHandleCount < dwMaxHandleCount) {
pThreadHandleArray[dwHandleCount++] = hThread;
} else {
// realloc buffer and try again
// this will be added when multi-query
// support is added. for now we'll ignore
// ones that don't fit.
}
lpThreadData = NULL; //clear for next lap
} else {
// unable to start thread
lStatus = GetLastError();
szStringArray[0] = szQueryNameBuffer;
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE,
0,
PERFLOG_UNABLE_START_THREAD,
NULL,
1,
sizeof(DWORD),
szStringArray,
(LPVOID)&lStatus);
}
CONTINUE_ENUM_LOOP:
// prepare for next loop
dwQueryIndex++;
// for now we just do the first item in the list
// the full multiple log query feature will be
// added later.
if (dwQueryIndex > 0) break;
// otherwise we would continue here
*szQueryNameBuffer = 0;
dwQueryNameBufferSize = MAX_PATH;
*szQueryClassBuffer;
dwQueryClassBufferSize = MAX_PATH;
} // end enumeration of log queries
// service is now started
ssPerfLogStatus.dwCurrentState = SERVICE_RUNNING;
ssPerfLogStatus.dwCheckPoint++;
SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
// wait for (all) timing and logging threads to complete
lStatus = WaitForMultipleObjects (dwHandleCount,
pThreadHandleArray, TRUE, INFINITE);
ssPerfLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
// when here, all logging threads have terminated so the
// memory can be released and the service can exit and shutdown.
for (dwQueryIndex = 0; dwQueryIndex < dwHandleCount; dwQueryIndex++) {
CloseHandle (pThreadHandleArray[dwQueryIndex]);
}
// release the dynamic memory
FreeThreadData (pFirstThread);
// and update the service status
ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
if (hEventLog != NULL) CloseHandle (hEventLog);
return;
}
void
__cdecl main(void)
/*++
main
Arguments
ReturnValue
0 (ERROR_SUCCESS) if command was processed
Non-Zero if command error was detected.
--*/
{
LONG lStatus;
SERVICE_TABLE_ENTRY DispatchTable[] = {
{TEXT("PerfDataLog"), PerfDataLogServiceStart },
{NULL, NULL }
};
hEventLog = RegisterEventSource (NULL, TEXT("PerfDataLog"));
if (!StartServiceCtrlDispatcher (DispatchTable)) {
lStatus = GetLastError();
// log failure to event log
ReportEvent (hEventLog,
EVENTLOG_ERROR_TYPE,
0,
PERFLOG_UNABLE_START_DISPATCHER,
NULL,
0,
sizeof(DWORD),
NULL,
(LPVOID)&lStatus);
}
return;
}