Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
11 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. pdlsvc.c
  5. Abstract:
  6. service to log performance data
  7. Author:
  8. Bob Watson (a-robw) 10 Apr 96
  9. Revision History:
  10. --*/
  11. #ifndef UNICODE
  12. #define UNICODE 1
  13. #endif
  14. #ifndef _UNICODE
  15. #define _UNICODE 1
  16. #endif
  17. //
  18. // Windows Include files
  19. //
  20. #include <windows.h>
  21. #include <tchar.h>
  22. #include "pdlsvc.h"
  23. #include "pdlmsg.h"
  24. // Global variables used by all modules
  25. HANDLE hEventLog = NULL;
  26. PLOG_COUNTER_INFO pFirstCounter = NULL;
  27. SERVICE_STATUS_HANDLE hPerfLogStatus;
  28. SERVICE_STATUS ssPerfLogStatus;
  29. // Static variables used by this module only
  30. static LPLOG_THREAD_DATA pFirstThread = NULL;
  31. static HANDLE *pThreadHandleArray = NULL;
  32. static DWORD dwHandleCount = 0;
  33. static DWORD dwMaxHandleCount = 0;
  34. // this is for the time being, until full multiple log query
  35. // support is added
  36. #define LOCAL_HANDLE_COUNT 1
  37. static HANDLE LocalThreadArray[LOCAL_HANDLE_COUNT];
  38. // functions
  39. void FreeThreadData (
  40. IN LPLOG_THREAD_DATA pThisThread
  41. )
  42. {
  43. if (pThisThread->next != NULL) {
  44. // free the "downstream" entries
  45. FreeThreadData (pThisThread->next);
  46. pThisThread->next = NULL;
  47. }
  48. // now free this entry
  49. if (pThisThread->mszCounterList != NULL) {
  50. G_FREE (pThisThread->mszCounterList);
  51. pThisThread->mszCounterList = NULL;
  52. }
  53. if (pThisThread->hExitEvent != NULL) {
  54. CloseHandle (pThisThread->hExitEvent);
  55. pThisThread->hExitEvent = NULL;
  56. }
  57. if (pThisThread->hKeyQuery != NULL) {
  58. RegCloseKey (pThisThread->hKeyQuery);
  59. pThisThread->hKeyQuery = NULL;
  60. }
  61. G_FREE (pThisThread);
  62. }
  63. void PerfDataLogServiceControlHandler(
  64. IN DWORD dwControl
  65. )
  66. {
  67. LPLOG_THREAD_DATA pThisThread;
  68. switch (dwControl) {
  69. case SERVICE_CONTROL_SHUTDOWN:
  70. case SERVICE_CONTROL_STOP:
  71. // stop logging & close queries and files
  72. // set stop event for all running threads
  73. pThisThread = pFirstThread;
  74. while (pThisThread != NULL) {
  75. SetEvent (pThisThread->hExitEvent);
  76. pThisThread = pThisThread->next;
  77. }
  78. break;
  79. case SERVICE_CONTROL_PAUSE:
  80. // stop logging, close queries and files
  81. // not supported, yet
  82. break;
  83. case SERVICE_CONTROL_CONTINUE:
  84. // reload configuration and restart logging
  85. // not supported, yet
  86. break;
  87. case SERVICE_CONTROL_INTERROGATE:
  88. // update current status
  89. default:
  90. // report to event log that an unrecognized control
  91. // request was received.
  92. ;
  93. }
  94. }
  95. void
  96. PerfDataLogServiceStart (
  97. IN DWORD argc,
  98. IN LPTSTR *argv
  99. )
  100. {
  101. LONG lStatus;
  102. HKEY hKeyLogQueries;
  103. HKEY hKeyThisLogQuery;
  104. DWORD dwQueryIndex;
  105. TCHAR szQueryNameBuffer[MAX_PATH];
  106. DWORD dwQueryNameBufferSize;
  107. TCHAR szQueryClassBuffer[MAX_PATH];
  108. DWORD dwQueryClassBufferSize;
  109. LPLOG_THREAD_DATA lpThreadData;
  110. HANDLE hThread;
  111. LPTSTR szStringArray[2];
  112. DWORD dwThreadId;
  113. ssPerfLogStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  114. ssPerfLogStatus.dwCurrentState = SERVICE_START_PENDING;
  115. ssPerfLogStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  116. // SERVICE_ACCEPT_PAUSE_CONTINUE |
  117. SERVICE_ACCEPT_SHUTDOWN;
  118. ssPerfLogStatus.dwWin32ExitCode = 0;
  119. ssPerfLogStatus.dwServiceSpecificExitCode = 0;
  120. ssPerfLogStatus.dwCheckPoint = 0;
  121. ssPerfLogStatus.dwWaitHint = 0;
  122. hPerfLogStatus = RegisterServiceCtrlHandler (
  123. TEXT("PerfDataLog"), PerfDataLogServiceControlHandler);
  124. if (hPerfLogStatus == (SERVICE_STATUS_HANDLE)0) {
  125. lStatus = GetLastError();
  126. ReportEvent (hEventLog,
  127. EVENTLOG_ERROR_TYPE,
  128. 0,
  129. PERFLOG_UNABLE_REGISTER_HANDLER,
  130. NULL,
  131. 0,
  132. sizeof(DWORD),
  133. NULL,
  134. (LPVOID)&lStatus);
  135. // this is fatal so bail out
  136. return;
  137. }
  138. // registered the service successfully, so load the log queries
  139. // assign the handle buffer
  140. pThreadHandleArray = &LocalThreadArray[0];
  141. dwMaxHandleCount = LOCAL_HANDLE_COUNT;
  142. // open (each) query
  143. lStatus = RegOpenKeyEx (
  144. HKEY_LOCAL_MACHINE,
  145. TEXT("SYSTEM\\CurrentControlSet\\Services\\PerfDataLog\\Log Queries"),
  146. 0L,
  147. KEY_READ,
  148. &hKeyLogQueries);
  149. if (lStatus != ERROR_SUCCESS) {
  150. // unable to read the log query information from the registry
  151. lStatus = GetLastError();
  152. ReportEvent (hEventLog,
  153. EVENTLOG_ERROR_TYPE,
  154. 0,
  155. PERFLOG_UNABLE_OPEN_LOG_QUERY,
  156. NULL,
  157. 0,
  158. sizeof(DWORD),
  159. NULL,
  160. (LPVOID)&lStatus);
  161. // we can't start the service with out the evnt log.
  162. ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED;
  163. SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
  164. return;
  165. }
  166. // enumerate and start the queries in the registry
  167. dwQueryIndex = 0;
  168. *szQueryNameBuffer = 0;
  169. dwQueryNameBufferSize = MAX_PATH;
  170. *szQueryClassBuffer;
  171. dwQueryClassBufferSize = MAX_PATH;
  172. while ((lStatus = RegEnumKeyEx (
  173. hKeyLogQueries,
  174. dwQueryIndex,
  175. szQueryNameBuffer,
  176. &dwQueryNameBufferSize,
  177. NULL,
  178. szQueryClassBuffer,
  179. &dwQueryClassBufferSize,
  180. NULL)) != ERROR_NO_MORE_ITEMS) {
  181. // open this key
  182. lStatus = RegOpenKeyEx (
  183. hKeyLogQueries,
  184. szQueryNameBuffer,
  185. 0L,
  186. KEY_READ | KEY_WRITE,
  187. &hKeyThisLogQuery);
  188. if (lStatus != ERROR_SUCCESS) {
  189. szStringArray[0] = szQueryNameBuffer;
  190. ReportEvent (hEventLog,
  191. EVENTLOG_WARNING_TYPE,
  192. 0,
  193. PERFLOG_UNABLE_READ_LOG_QUERY,
  194. NULL,
  195. 1,
  196. sizeof(DWORD),
  197. szStringArray,
  198. (LPVOID)&lStatus);
  199. // skip to next item
  200. goto CONTINUE_ENUM_LOOP;
  201. }
  202. // update the service status
  203. ssPerfLogStatus.dwCheckPoint++;
  204. SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
  205. // allocate a thread info block.
  206. lpThreadData = G_ALLOC (sizeof(LOG_THREAD_DATA));
  207. if (lpThreadData == NULL) {
  208. lStatus = GetLastError();
  209. szStringArray[0] = szQueryNameBuffer;
  210. ReportEvent (hEventLog,
  211. EVENTLOG_WARNING_TYPE,
  212. 0,
  213. PERFLOG_UNABLE_ALLOCATE_DATABLOCK,
  214. NULL,
  215. 1,
  216. sizeof(DWORD),
  217. szStringArray,
  218. (LPVOID)&lStatus);
  219. goto CONTINUE_ENUM_LOOP;
  220. }
  221. // initialize the thread data block
  222. lpThreadData->hKeyQuery = hKeyThisLogQuery;
  223. lpThreadData->hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  224. lpThreadData->bReloadNewConfig = FALSE;
  225. lstrcpy (lpThreadData->szQueryName, szQueryNameBuffer);
  226. // start logging thread
  227. hThread = CreateThread (
  228. NULL, 0, LoggingThreadProc,
  229. (LPVOID)lpThreadData, 0, &dwThreadId);
  230. if (hThread != NULL) {
  231. // add it to the list and continue
  232. if (pFirstThread == NULL) {
  233. // then this is the first thread so add it
  234. lpThreadData->next = NULL;
  235. pFirstThread = lpThreadData;
  236. } else {
  237. // insert this at the head of the list since
  238. // that's the easiest and the order isn't
  239. // really important
  240. lpThreadData->next = pFirstThread;
  241. pFirstThread = lpThreadData;
  242. }
  243. // add thread to array for termination wait
  244. if (dwHandleCount < dwMaxHandleCount) {
  245. pThreadHandleArray[dwHandleCount++] = hThread;
  246. } else {
  247. // realloc buffer and try again
  248. // this will be added when multi-query
  249. // support is added. for now we'll ignore
  250. // ones that don't fit.
  251. }
  252. lpThreadData = NULL; //clear for next lap
  253. } else {
  254. // unable to start thread
  255. lStatus = GetLastError();
  256. szStringArray[0] = szQueryNameBuffer;
  257. ReportEvent (hEventLog,
  258. EVENTLOG_WARNING_TYPE,
  259. 0,
  260. PERFLOG_UNABLE_START_THREAD,
  261. NULL,
  262. 1,
  263. sizeof(DWORD),
  264. szStringArray,
  265. (LPVOID)&lStatus);
  266. }
  267. CONTINUE_ENUM_LOOP:
  268. // prepare for next loop
  269. dwQueryIndex++;
  270. // for now we just do the first item in the list
  271. // the full multiple log query feature will be
  272. // added later.
  273. if (dwQueryIndex > 0) break;
  274. // otherwise we would continue here
  275. *szQueryNameBuffer = 0;
  276. dwQueryNameBufferSize = MAX_PATH;
  277. *szQueryClassBuffer;
  278. dwQueryClassBufferSize = MAX_PATH;
  279. } // end enumeration of log queries
  280. // service is now started
  281. ssPerfLogStatus.dwCurrentState = SERVICE_RUNNING;
  282. ssPerfLogStatus.dwCheckPoint++;
  283. SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
  284. // wait for (all) timing and logging threads to complete
  285. lStatus = WaitForMultipleObjects (dwHandleCount,
  286. pThreadHandleArray, TRUE, INFINITE);
  287. ssPerfLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
  288. SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
  289. // when here, all logging threads have terminated so the
  290. // memory can be released and the service can exit and shutdown.
  291. for (dwQueryIndex = 0; dwQueryIndex < dwHandleCount; dwQueryIndex++) {
  292. CloseHandle (pThreadHandleArray[dwQueryIndex]);
  293. }
  294. // release the dynamic memory
  295. FreeThreadData (pFirstThread);
  296. // and update the service status
  297. ssPerfLogStatus.dwCurrentState = SERVICE_STOPPED;
  298. SetServiceStatus (hPerfLogStatus, &ssPerfLogStatus);
  299. if (hEventLog != NULL) CloseHandle (hEventLog);
  300. return;
  301. }
  302. void
  303. __cdecl main(void)
  304. /*++
  305. main
  306. Arguments
  307. ReturnValue
  308. 0 (ERROR_SUCCESS) if command was processed
  309. Non-Zero if command error was detected.
  310. --*/
  311. {
  312. LONG lStatus;
  313. SERVICE_TABLE_ENTRY DispatchTable[] = {
  314. {TEXT("PerfDataLog"), PerfDataLogServiceStart },
  315. {NULL, NULL }
  316. };
  317. hEventLog = RegisterEventSource (NULL, TEXT("PerfDataLog"));
  318. if (!StartServiceCtrlDispatcher (DispatchTable)) {
  319. lStatus = GetLastError();
  320. // log failure to event log
  321. ReportEvent (hEventLog,
  322. EVENTLOG_ERROR_TYPE,
  323. 0,
  324. PERFLOG_UNABLE_START_DISPATCHER,
  325. NULL,
  326. 0,
  327. sizeof(DWORD),
  328. NULL,
  329. (LPVOID)&lStatus);
  330. }
  331. return;
  332. }