Leaked source code of windows server 2003
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.

1482 lines
41 KiB

  1. /*----------------------------------------------------------------------
  2. ASYNCTRC.C
  3. Implementation of the async tracing library
  4. Copyright (C) 1994 Microsoft Corporation
  5. All rights reserved.
  6. Authors:
  7. gordm Gord Mangione
  8. History:
  9. 01/30/95 gordm Created.
  10. ----------------------------------------------------------------------*/
  11. #ifndef WIN32_LEAN_AND_MEAN
  12. #define WIN32_LEAN_AND_MEAN
  13. #endif
  14. #define _DBGTRACE_DLL_IMPLEMENTATION
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <stdarg.h>
  18. //
  19. // #define TRACE_ENABLED
  20. //
  21. #include "traceint.h"
  22. #include "randint.h"
  23. //
  24. // Per Process global variables
  25. //
  26. PENDQ PendQ;
  27. BOOL fInitialized;
  28. HANDLE hShutdownEvent;
  29. DWORD dwInitializations = 0;
  30. CHAR mszModules[MODULES_BUFFER_SIZE] = {0};
  31. // critical section to protect against the race condition
  32. // where one service is starting and a second service is
  33. // terminating.
  34. CRITICAL_SECTION g_csInitialize;
  35. //
  36. // critical section to protect reentracy on Write routine
  37. // Also used by the signal thread to ensure that no threads
  38. // are using hFile as it dynamically opens and closes trace file.
  39. // During Async mode the background thread will be able to grab
  40. // this critSec each time without waiting unless we're in the
  41. // process of shutting down.
  42. //
  43. CRITICAL_SECTION critSecWrite;
  44. //
  45. // critical section to protect reentracy on Flush routine
  46. //
  47. CRITICAL_SECTION critSecFlush;
  48. //
  49. // exported trace flag used by trace macros to determine if the trace
  50. // statement should be executed
  51. //
  52. DbgTraceDLL DWORD __dwEnabledTraces;
  53. DWORD dwMaxFileSize;
  54. DWORD dwNumTraces;
  55. DWORD dwTraceOutputType;
  56. DWORD dwAsyncTraceFlag;
  57. int nAsyncThreadPriority;
  58. DWORD dwIncrementSize;
  59. DWORD dwTlsIndex = 0xFFFFFFFF;
  60. //
  61. // pointer to the previous top level exception handler
  62. //
  63. LPTOP_LEVEL_EXCEPTION_FILTER lpfnPreviousFilter = NULL;
  64. //
  65. // Internal Function to debugger tracing if DEBUG is defined.
  66. // see traceint.h for the INT_TRACE macro which can be
  67. // inserted at the appropriate point and has the same
  68. // parameters as printf.
  69. //
  70. #ifdef TRACE_ENABLED
  71. void CDECL InternalTrace( const char *s, ... )
  72. {
  73. char sz[256];
  74. va_list marker;
  75. va_start( marker, s );
  76. wvsprintf( sz, s, marker );
  77. OutputDebugString( sz );
  78. va_end( marker );
  79. }
  80. #endif
  81. //+---------------------------------------------------------------
  82. //
  83. // Function: TopLevelExceptionFilter
  84. //
  85. // Synopsis: exception handler to flush the PendQ before hitting
  86. // the debugger
  87. //
  88. // Arguments: see Win32 help file
  89. //
  90. // Returns: always returns EXCEPTION_CONTINUE_SEARCH
  91. //
  92. //----------------------------------------------------------------
  93. LONG WINAPI TopLevelExceptionFilter( EXCEPTION_POINTERS *lpExceptionInfo )
  94. {
  95. DWORD dwLastError = GetLastError();
  96. //
  97. // flush the background queue; ignore the ret code
  98. //
  99. FlushAsyncTrace();
  100. //
  101. // restore the overwritten last error code
  102. //
  103. SetLastError( dwLastError );
  104. //
  105. // chain the ret code if there is a previous exception handler
  106. // else continue the search
  107. //
  108. return lpfnPreviousFilter != NULL ?
  109. (*lpfnPreviousFilter)( lpExceptionInfo ) :
  110. EXCEPTION_CONTINUE_SEARCH ;
  111. }
  112. //+---------------------------------------------------------------
  113. //
  114. // Function: SetTraceBufferInfo
  115. //
  116. // Synopsis: used to set the non-sprintf trace variables
  117. //
  118. // Arguments: LPTRACEBUF: target buffer
  119. // int: line number of the exception
  120. // LPSTR: source file of the exception
  121. // LPSTR: function name of the exception
  122. // DWORD: type of trace
  123. //
  124. // Returns: void
  125. //
  126. //----------------------------------------------------------------
  127. __inline void SetTraceBufferInfo(
  128. LPTRACEBUF lpBuf,
  129. int iLine,
  130. LPSTR pszFile,
  131. LPSTR pszFunction,
  132. DWORD dwTraceMask,
  133. DWORD dwError )
  134. {
  135. LPSTR psz;
  136. WORD wVariableOffset = 0;
  137. PFIXEDTR pFixed = &lpBuf->Fixed;
  138. lpBuf->dwLastError = dwError;
  139. pFixed->wSignature = 0xCAFE;
  140. pFixed->wLength = sizeof(FIXEDTRACE);
  141. pFixed->wLine = LOWORD( iLine );
  142. pFixed->dwTraceMask = dwTraceMask;
  143. pFixed->dwThreadId = GetCurrentThreadId();
  144. pFixed->dwProcessId = PendQ.dwProcessId;
  145. GetLocalTime( &pFixed->TraceTime );
  146. if ( pszFile )
  147. {
  148. if ( (psz = strrchr( pszFile, '\\' )) != NULL )
  149. {
  150. psz++; // fully qualified path name - strip path
  151. }
  152. else
  153. {
  154. psz = pszFile; // simple file name
  155. }
  156. lstrcpyn( lpBuf->Buffer, psz, MAX_FILENAME_SIZE );
  157. pFixed->wFileNameOffset = sizeof(FIXEDTRACE) + wVariableOffset;
  158. wVariableOffset = lstrlen( psz ) + 1;
  159. }
  160. else
  161. {
  162. pFixed->wFileNameOffset = 0;
  163. }
  164. if ( pszFunction != NULL )
  165. {
  166. lstrcpyn( lpBuf->Buffer + wVariableOffset, pszFunction, MAX_FUNCTNAME_SIZE );
  167. pFixed->wFunctNameOffset = sizeof(FIXEDTRACE) + wVariableOffset;
  168. wVariableOffset += lstrlen( pszFunction ) + 1;
  169. }
  170. else
  171. {
  172. pFixed->wFunctNameOffset = 0;
  173. }
  174. //
  175. // set the current offset into the variable buffer
  176. //
  177. pFixed->wVariableLength = wVariableOffset;
  178. }
  179. //+---------------------------------------------------------------
  180. //
  181. // Function: CommitTraceBuffer
  182. //
  183. // Synopsis: deal with the buffer; either sync write or async queue
  184. //
  185. // Arguments: LPTRACEBUF lpBuf: the buffer to commit
  186. //
  187. // Returns: void
  188. //
  189. //----------------------------------------------------------------
  190. __inline void CommitTraceBuffer( LPTRACEBUF lpBuf )
  191. {
  192. DWORD dwError = lpBuf->dwLastError;
  193. if ( dwAsyncTraceFlag == 0 )
  194. {
  195. WriteTraceBuffer( lpBuf );
  196. FreeTraceBuffer( lpBuf );
  197. }
  198. else
  199. {
  200. QueueAsyncTraceBuffer( lpBuf );
  201. }
  202. //
  203. // restore last error before initial Trace call
  204. //
  205. SetLastError( dwError );
  206. }
  207. //+---------------------------------------------------------------
  208. //
  209. // Function: DllEntryPoint
  210. //
  211. // Synopsis: only relevence is allocating thread local storage var
  212. //
  213. // Arguments: see Win32 SDK
  214. //
  215. // Returns: see Win32 SDK
  216. //
  217. //----------------------------------------------------------------
  218. DbgTraceDLL BOOL WINAPI DllEntryPoint( HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved )
  219. {
  220. //
  221. // InitAsyncTrace and TermAsyncTrace cannot be called from this entrypoint
  222. // because they create and interact with background threads
  223. // See CreateThread in Win32 Help file for more info
  224. //
  225. switch( dwReason )
  226. {
  227. case DLL_PROCESS_ATTACH:
  228. InitializeCriticalSection(&g_csInitialize);
  229. return TRUE;
  230. // return InitAsyncTrace();
  231. case DLL_THREAD_ATTACH:
  232. if(fInitialized) // TlsAlloc hasn't been called till fInitialized = TRUE
  233. {
  234. TlsSetValue( dwTlsIndex, (LPVOID)NULL );
  235. TlsSetValue( dwRandFailTlsIndex, (LPVOID)NULL );
  236. }
  237. break;
  238. case DLL_PROCESS_DETACH:
  239. if (lpReserved == NULL)
  240. DeleteCriticalSection(&g_csInitialize);
  241. // TermAsyncTrace();
  242. return FALSE;
  243. }
  244. return TRUE;
  245. }
  246. //+---------------------------------------------------------------
  247. //
  248. // Function: SetAsyncTraceParams
  249. //
  250. // Synopsis: exported function to setup trace buffer with
  251. // required fields
  252. //
  253. // This is the first call for a trace statement.
  254. // Second call is different for strings or binary
  255. //
  256. // Arguments: LPSTR: source file of the exception
  257. // int: line number of the exception
  258. // LPSTR: function name of the exception
  259. // DWORD: type of trace
  260. //
  261. // Returns: returns a BOOL 1 if successful; 0 on failure
  262. //
  263. // Note: Feb 24, 1999. This function obsoleted by SetAsyncTraceParamsEx.
  264. // This function is retained purely for code that linked with
  265. // this dll, but won't be rebuilt to call SetAsyncTraceParamsEx.
  266. //
  267. //----------------------------------------------------------------
  268. DbgTraceDLL int WINAPI SetAsyncTraceParams( LPSTR pszFile,
  269. int iLine,
  270. LPSTR pszFunction,
  271. DWORD dwTraceMask )
  272. {
  273. LPTRACEBUF lpBuf;
  274. DWORD dwError = GetLastError();
  275. if ( fInitialized == FALSE )
  276. {
  277. return 0;
  278. }
  279. if ( ShouldLogModule("ALL") == FALSE )
  280. {
  281. return 0;
  282. }
  283. if ( lpBuf = GetTraceBuffer() )
  284. {
  285. SetTraceBufferInfo( lpBuf, iLine, pszFile, pszFunction, dwTraceMask, dwError );
  286. TlsSetValue( dwTlsIndex, (LPVOID)lpBuf );
  287. return 1;
  288. }
  289. else return 0;
  290. }
  291. //+---------------------------------------------------------------
  292. //
  293. // Function: SetAsyncTraceParamsEx
  294. //
  295. // Synopsis: exported function to setup trace buffer with
  296. // required fields.
  297. //
  298. // This is the first call for a trace statement.
  299. // Second call is different for strings or binary
  300. //
  301. // Arguments: LPSTR: module name
  302. // LPSTR: source file of the exception
  303. // int: line number of the exception
  304. // LPSTR: function name of the exception
  305. // DWORD: type of trace
  306. //
  307. // Returns: returns a BOOL 1 if successful; 0 on failure
  308. //
  309. //----------------------------------------------------------------
  310. DbgTraceDLL int WINAPI SetAsyncTraceParamsEx(
  311. LPSTR pszModule,
  312. LPSTR pszFile,
  313. int iLine,
  314. LPSTR pszFunction,
  315. DWORD dwTraceMask )
  316. {
  317. LPTRACEBUF lpBuf;
  318. DWORD dwError = GetLastError();
  319. if ( fInitialized == FALSE )
  320. {
  321. return 0;
  322. }
  323. if (ShouldLogModule(pszModule) == FALSE)
  324. {
  325. return 0;
  326. }
  327. if ( lpBuf = GetTraceBuffer() )
  328. {
  329. SetTraceBufferInfo( lpBuf, iLine, pszFile, pszFunction, dwTraceMask, dwError );
  330. TlsSetValue( dwTlsIndex, (LPVOID)lpBuf );
  331. return 1;
  332. }
  333. else return 0;
  334. }
  335. //+---------------------------------------------------------------
  336. //
  337. // Function: AsyncStringTrace
  338. //
  339. // Synopsis: exported function to finish setting up trace buffer
  340. // with optional fields for sprintf style traces
  341. //
  342. // Arguments: LPARAM: 32bit trace param used app level filtering
  343. // LPCSTR: format string
  344. // va_list: marker for vsprintf functions
  345. //
  346. // Returns: returns length of the trace statement
  347. //
  348. //----------------------------------------------------------------
  349. DbgTraceDLL int WINAPI AsyncStringTrace(LPARAM lParam,
  350. LPCSTR szFormat,
  351. va_list marker )
  352. {
  353. LPTRACEBUF lpBuf;
  354. PFIXEDTR pFixed;
  355. int iLength;
  356. int iMaxLength;
  357. if ( fInitialized == FALSE )
  358. {
  359. return 0;
  360. }
  361. if ( (lpBuf = (LPTRACEBUF)TlsGetValue( dwTlsIndex )) != NULL )
  362. {
  363. TlsSetValue( dwTlsIndex, NULL );
  364. pFixed = &lpBuf->Fixed;
  365. iMaxLength = MAX_VARIABLE_SIZE - pFixed->wVariableLength;
  366. iLength =
  367. _vsnprintf( lpBuf->Buffer + pFixed->wVariableLength,
  368. iMaxLength,
  369. szFormat,
  370. marker ) + 1;
  371. if ( iLength == 0 || iLength == iMaxLength + 1 )
  372. {
  373. iLength = iMaxLength;
  374. lpBuf->Buffer[MAX_VARIABLE_SIZE-1] = '\0';
  375. }
  376. _ASSERT( iLength <= iMaxLength );
  377. pFixed->wBinaryOffset = sizeof(FIXEDTRACE) + pFixed->wVariableLength;
  378. pFixed->wVariableLength += LOWORD( (DWORD)iLength );
  379. pFixed->wBinaryType = TRACE_STRING;
  380. pFixed->dwParam = (DWORD)lParam; // This is a 32-bit flag so the cast is OK
  381. //
  382. // this is a specific area where the app can overwrite
  383. // data. Could have used vnsprintf to avoid the overwrite
  384. // but this woudl have dragged in the C runtime and
  385. // introduced its overhead and own critical sections
  386. //
  387. ASSERT( pFixed->wVariableLength <= MAX_VARIABLE_SIZE );
  388. CommitTraceBuffer( lpBuf );
  389. //
  390. // need to use dwLength since we relinquish lpBuf
  391. // after we return from QueueAsyncTraceBuffer which
  392. // cannot fail
  393. //
  394. return iLength;
  395. }
  396. else return 0;
  397. }
  398. //+---------------------------------------------------------------
  399. //
  400. // Function: AsyncBinaryTrace
  401. //
  402. // Synopsis: exported function to finish setting up trace buffer
  403. // with optional fields for binary traces
  404. //
  405. // Arguments: LPARAM: 32bit trace param used app level filtering
  406. // DWORD: type of binary data ( ie Message, User... )
  407. // LPBYTE: ptr to the data
  408. // DWORD: length of the data
  409. //
  410. // Returns: returns length of the trace statement
  411. //
  412. //----------------------------------------------------------------
  413. DbgTraceDLL int WINAPI AsyncBinaryTrace(LPARAM lParam,
  414. DWORD dwBinaryType,
  415. LPBYTE pbData,
  416. DWORD cbData )
  417. {
  418. LPTRACEBUF lpBuf;
  419. WORD wLength;
  420. PFIXEDTR pFixed;
  421. if ( fInitialized == FALSE )
  422. {
  423. return 0;
  424. }
  425. if ( (lpBuf = (LPTRACEBUF)TlsGetValue( dwTlsIndex )) != NULL )
  426. {
  427. TlsSetValue( dwTlsIndex, NULL );
  428. pFixed = &lpBuf->Fixed;
  429. wLength = LOWORD( min( cbData, MAX_BUFFER_SIZE ) );
  430. CopyMemory( lpBuf->Buffer + pFixed->wVariableLength, pbData, wLength );
  431. pFixed->wBinaryOffset = sizeof(FIXEDTRACE) + pFixed->wVariableLength;
  432. pFixed->wVariableLength += wLength;
  433. pFixed->wBinaryType = LOWORD( dwBinaryType );
  434. pFixed->dwParam = (DWORD)lParam; // This is a 32-bit flag so the cast is OK
  435. CommitTraceBuffer( lpBuf );
  436. //
  437. // need to use dwLength since we relinquish lpBuf
  438. // after we return from QueueAsyncTraceBuffer which
  439. // cannot fail
  440. //
  441. return (int)wLength;
  442. }
  443. else return 0;
  444. }
  445. //+---------------------------------------------------------------
  446. //
  447. // Function: FlushAsyncTrace
  448. //
  449. // Synopsis: exported function to empty the pending queue. All
  450. // threads which call this function block until the
  451. // queue is empty
  452. //
  453. // Arguments: void
  454. //
  455. // Returns: BOOL: whether it worked
  456. //
  457. //----------------------------------------------------------------
  458. DllExport BOOL WINAPI FlushAsyncTrace( void )
  459. {
  460. static long lPendingFlushs = -1;
  461. if ( fInitialized == FALSE )
  462. {
  463. return FALSE;
  464. }
  465. else
  466. {
  467. EnterCriticalSection( &critSecFlush );
  468. if ( PendQ.dwCount > 0 )
  469. {
  470. SetEvent( PendQ.hFlushEvent );
  471. if ( nAsyncThreadPriority < THREAD_PRIORITY_ABOVE_NORMAL )
  472. {
  473. SetThreadPriority( PendQ.hWriteThread,
  474. THREAD_PRIORITY_ABOVE_NORMAL );
  475. }
  476. WaitForSingleObject( PendQ.hFlushedEvent, INFINITE );
  477. if ( nAsyncThreadPriority < THREAD_PRIORITY_ABOVE_NORMAL )
  478. {
  479. SetThreadPriority( PendQ.hWriteThread,
  480. nAsyncThreadPriority );
  481. }
  482. ResetEvent( PendQ.hFlushedEvent );
  483. }
  484. LeaveCriticalSection( &critSecFlush );
  485. return TRUE;
  486. }
  487. }
  488. //+---------------------------------------------------------------
  489. //
  490. // Function: InitAsyncTrace
  491. //
  492. // Synopsis: exported required function to rev things up.
  493. //
  494. // Arguments: void
  495. //
  496. // Returns: BOOL: whether it worked
  497. //
  498. //----------------------------------------------------------------
  499. DllExport BOOL WINAPI InitAsyncTrace( void )
  500. {
  501. static BOOL bInitializing = FALSE;
  502. BOOL bRC = FALSE;
  503. DWORD dwThreadId;
  504. EnterCriticalSection(&g_csInitialize);
  505. if ( fInitialized )
  506. {
  507. //
  508. // inc the count of successful initializations for this process
  509. //
  510. InterlockedIncrement( &dwInitializations );
  511. LeaveCriticalSection(&g_csInitialize);
  512. return TRUE;
  513. }
  514. if ( InterlockedExchange( (LPLONG)&bInitializing, (LONG)TRUE ) )
  515. {
  516. //
  517. // inc the count of successful initializations for this process
  518. //
  519. InterlockedIncrement( &dwInitializations );
  520. LeaveCriticalSection(&g_csInitialize);
  521. return TRUE;
  522. }
  523. // to guard against race condition when the initializing thread is about to execute
  524. // 'InterlockedExchange( (LPLONG)&bInitializing, (LONG)FALSE )', while
  525. // there is another thread that passed the
  526. // if ( InterlockedExchange( (LPLONG)&bInitializing, (LONG)TRUE )) condition
  527. //
  528. if ( fInitialized)
  529. {
  530. //
  531. // inc the count of successful initializations for this process
  532. //
  533. InterlockedIncrement( &dwInitializations );
  534. InterlockedExchange( (LPLONG)&bInitializing, (LONG)FALSE );
  535. LeaveCriticalSection(&g_csInitialize);
  536. return TRUE;
  537. }
  538. // will read from registry later
  539. //
  540. dwNumTraces = 0;
  541. PendQ.dwProcessId = GetCurrentProcessId();
  542. PendQ.hFile = INVALID_HANDLE_VALUE;
  543. PendQ.cbBufferEnd = 0;
  544. PendQ.dwThresholdCount = DEFAULT_MAX_FILE_SIZE / AVERAGE_TRACE_SIZE;
  545. __try {
  546. InitializeCriticalSection( &PendQ.critSecTail );
  547. InitializeCriticalSection( &critSecWrite );
  548. InitializeCriticalSection( &critSecFlush );
  549. if ( (dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF )
  550. {
  551. LeaveCriticalSection(&g_csInitialize);
  552. return FALSE;
  553. }
  554. if ( (dwRandFailTlsIndex = TlsAlloc()) == 0xFFFFFFFF )
  555. {
  556. LeaveCriticalSection(&g_csInitialize);
  557. return FALSE;
  558. }
  559. if ( GetTraceFlagsFromRegistry() == FALSE )
  560. {
  561. LeaveCriticalSection(&g_csInitialize);
  562. return FALSE;
  563. }
  564. //
  565. // Initialize the pool of trace buffers
  566. // must happen after reading the registy
  567. //
  568. if ( InitTraceBuffers( PendQ.dwThresholdCount, dwIncrementSize ) == FALSE )
  569. {
  570. LeaveCriticalSection(&g_csInitialize);
  571. return FALSE;
  572. }
  573. PendQ.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  574. if ( PendQ.hEvent == NULL )
  575. {
  576. LeaveCriticalSection(&g_csInitialize);
  577. return FALSE;
  578. }
  579. //
  580. // PendQ.hFlushedEvent is manual reset so multiple threads can wait
  581. //
  582. PendQ.hFlushedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  583. if ( PendQ.hFlushedEvent == NULL )
  584. {
  585. LeaveCriticalSection(&g_csInitialize);
  586. return FALSE;
  587. }
  588. PendQ.hFlushEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  589. if ( PendQ.hFlushEvent == NULL )
  590. {
  591. LeaveCriticalSection(&g_csInitialize);
  592. return FALSE;
  593. }
  594. //
  595. // hShutdownEvent is manual reset so multiple threads can be awaken
  596. //
  597. hShutdownEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  598. if ( hShutdownEvent == NULL )
  599. {
  600. LeaveCriticalSection(&g_csInitialize);
  601. return FALSE;
  602. }
  603. ASSERT( PendQ.hRegNotifyThread == NULL );
  604. PendQ.hRegNotifyThread =
  605. CreateThread( NULL,
  606. 0,
  607. (LPTHREAD_START_ROUTINE)RegNotifyThread,
  608. NULL,
  609. 0,
  610. &dwThreadId );
  611. if ( PendQ.hRegNotifyThread == NULL )
  612. {
  613. LeaveCriticalSection(&g_csInitialize);
  614. return FALSE;
  615. }
  616. else
  617. {
  618. //
  619. // bumping the priority onthis almost always dorminate thread
  620. // ensures that trace changes are applied soon after the
  621. // registry changes
  622. //
  623. SetThreadPriority( PendQ.hRegNotifyThread, THREAD_PRIORITY_ABOVE_NORMAL );
  624. }
  625. ASSERT( PendQ.hWriteThread == NULL );
  626. PendQ.hWriteThread =
  627. CreateThread( NULL,
  628. 0,
  629. (LPTHREAD_START_ROUTINE)WriteTraceThread,
  630. NULL,
  631. 0,
  632. &dwThreadId );
  633. if ( PendQ.hWriteThread == NULL )
  634. {
  635. LeaveCriticalSection(&g_csInitialize);
  636. return FALSE;
  637. }
  638. else
  639. {
  640. //
  641. // setting the priority on this thread ensures that the
  642. // physical writing of the traces will not impact performance
  643. // of the main application task. Default is BELOW_NORMAL although
  644. // its controlled by a reg entry
  645. //
  646. SetThreadPriority( PendQ.hWriteThread, nAsyncThreadPriority );
  647. }
  648. PendQ.pHead = PendQ.pTail = (LPTRACEBUF)&PendQ.Special;
  649. //
  650. // set our top level exception handler
  651. //
  652. lpfnPreviousFilter = SetUnhandledExceptionFilter( TopLevelExceptionFilter );
  653. fInitialized = TRUE;
  654. InterlockedExchange( (LPLONG)&bInitializing, (LONG)FALSE );
  655. //
  656. // inc the count of successful initializations for this process
  657. //
  658. InterlockedIncrement( &dwInitializations );
  659. bRC = TRUE;
  660. }
  661. __finally
  662. {
  663. if ( bRC == FALSE )
  664. {
  665. DWORD dwLastError = GetLastError();
  666. AsyncTraceCleanup();
  667. SetLastError( dwLastError );
  668. }
  669. }
  670. LeaveCriticalSection(&g_csInitialize);
  671. return bRC;
  672. }
  673. //+---------------------------------------------------------------
  674. //
  675. // Function: TermAsyncTrace
  676. //
  677. // Synopsis: exported required function to wind things down.
  678. //
  679. // Arguments: void
  680. //
  681. // Returns: BOOL: whether it worked
  682. //
  683. //----------------------------------------------------------------
  684. DllExport BOOL WINAPI TermAsyncTrace( void )
  685. {
  686. EnterCriticalSection(&g_csInitialize);
  687. if ( fInitialized )
  688. {
  689. if ( InterlockedDecrement( &dwInitializations ) == 0 )
  690. {
  691. BOOL fRet;
  692. fRet = AsyncTraceCleanup();
  693. LeaveCriticalSection(&g_csInitialize);
  694. return fRet;
  695. }
  696. LeaveCriticalSection(&g_csInitialize);
  697. return TRUE;
  698. }
  699. else
  700. {
  701. LeaveCriticalSection(&g_csInitialize);
  702. return FALSE;
  703. }
  704. }
  705. //+---------------------------------------------------------------
  706. //
  707. // Function: DebugAssert
  708. //
  709. // Synopsis: exported required function for enhanced asserts
  710. //
  711. // Arguments: DWORD dwLine: source code line of the _ASSERT
  712. // LPSTR lpszFunction source code filename of the _ASSERT
  713. // LPSTR lpszExpression stringized version of _ASSERT param
  714. //
  715. // Returns: void
  716. //
  717. //----------------------------------------------------------------
  718. char szAssertOutput[512];
  719. DllExport void WINAPI DebugAssert( DWORD dwLine,
  720. LPSTR lpszFunction,
  721. LPSTR lpszExpression )
  722. {
  723. DWORD dwError = GetLastError();
  724. wsprintf( szAssertOutput, "\nASSERT: %s,\n File: %s,\n Line: %d\n Error: %d\n\n",
  725. lpszExpression, lpszFunction, dwLine, dwError );
  726. OutputDebugString( szAssertOutput );
  727. SetLastError( dwError );
  728. DebugBreak();
  729. }
  730. //+---------------------------------------------------------------
  731. //
  732. // Function: QueueAsyncTraceBuffer
  733. //
  734. // Synopsis: Routine to implement the appending of TRACEBUF to
  735. // the FIFO PendQ
  736. //
  737. // Arguments: LPTRACEBUF: the buffer
  738. //
  739. // Returns: void
  740. //
  741. //----------------------------------------------------------------
  742. void QueueAsyncTraceBuffer( LPTRACEBUF lpBuf )
  743. {
  744. LPTRACEBUF pPrevTail;
  745. ASSERT( lpBuf != NULL );
  746. ASSERT( lpBuf->dwSignature == TRACE_SIGNATURE );
  747. lpBuf->pNext = NULL;
  748. EnterCriticalSection( &PendQ.critSecTail );
  749. //
  750. // number of buffers on the queue can only decrease while
  751. // in this critical section since WriteTraceThread can continue
  752. // to pull buffers from the queue.
  753. //
  754. // WriteAsyncThread will not write this buffer until it has
  755. // been appended to the queue by incrementing PendQ.dwCount
  756. //
  757. // PendQ.pTail is only modified here and in a special case on the
  758. // background writer thread. The special case is when Special needs
  759. // to be moved from the Head of the queue to the Tail. Only during
  760. // this brief special case can both the background writer and the
  761. // foreground appender thread be operating on the same trace buffer.
  762. //
  763. pPrevTail = PendQ.pTail;
  764. pPrevTail->pNext = PendQ.pTail = lpBuf;
  765. LeaveCriticalSection( &PendQ.critSecTail );
  766. InterlockedIncrement( &PendQ.dwCount );
  767. //
  768. // wake up WriteTraceThread if necessary. It may not be since
  769. // WriteTraceThread will always empty its queue before sleeping
  770. //
  771. SetEvent( PendQ.hEvent );
  772. }
  773. //+---------------------------------------------------------------
  774. //
  775. // Function: DequeueAsyncTraceBuffer
  776. //
  777. // Synopsis: Routine to dequeue the top Trace Buffer from
  778. // the FIFO PendQ
  779. //
  780. // Arguments: void
  781. //
  782. // Returns: LPTRACEBUF: the buffer
  783. //
  784. //----------------------------------------------------------------
  785. LPTRACEBUF DequeueAsyncTraceBuffer( void )
  786. {
  787. LPTRACEBUF lpBuf;
  788. LPTRACEBUF pPrevTail;
  789. //
  790. // check to see if Special is at the head of the queue. If so, move
  791. // it to the end of the queue
  792. //
  793. if ( PendQ.pHead == (LPTRACEBUF)&PendQ.Special )
  794. {
  795. //
  796. // need to NULL Special.pNext before the Exchange so the list
  797. // is terminated as soon as we do the exchange. We can lazily
  798. // set the old Tails next pointer since we're the only thread
  799. // that would dereference this pointer once its not the last
  800. // buffer in the FIFO
  801. //
  802. PendQ.pHead = PendQ.Special.pNext;
  803. PendQ.Special.pNext = NULL;
  804. EnterCriticalSection( &PendQ.critSecTail );
  805. //
  806. // see comment in QueueAsyncTraceBuffer to describe why we
  807. // to grab the Tail critical section here. If we did not
  808. // include this Special buffer then we would have to grab
  809. // the critSec each time.
  810. //
  811. pPrevTail = PendQ.pTail;
  812. pPrevTail->pNext = PendQ.pTail = (LPTRACEBUF)&PendQ.Special;
  813. LeaveCriticalSection( &PendQ.critSecTail );
  814. }
  815. //
  816. // again no critical section required since we're the only thread
  817. // accessing these PendQ.pHead. This needs to be remembered if we
  818. // were to add integratity checking to the queues at a later date
  819. // since this queue is effectively in a corrupt state.
  820. //
  821. lpBuf = PendQ.pHead;
  822. PendQ.pHead = lpBuf->pNext;
  823. InterlockedDecrement( &PendQ.dwCount );
  824. ASSERT( lpBuf != NULL );
  825. ASSERT( lpBuf->dwSignature == TRACE_SIGNATURE );
  826. return lpBuf;
  827. }
  828. //+---------------------------------------------------------------
  829. //
  830. // Function: AsyncTraceCleanup
  831. //
  832. // Synopsis: internla routine to clean things up
  833. // the FIFO PendQ
  834. //
  835. // Arguments: void
  836. //
  837. // Returns: BOOL: whether it worked
  838. //
  839. //----------------------------------------------------------------
  840. BOOL AsyncTraceCleanup( void )
  841. {
  842. HANDLE hThreads[2];
  843. int nObjects = 0;
  844. DWORD dw;
  845. INT_TRACE( "AsyncTraceCleanup Enter\n" );
  846. if ( InterlockedExchange( &PendQ.fShutdown, TRUE ) == TRUE )
  847. {
  848. return FALSE;
  849. }
  850. if ( dwTlsIndex != 0xFFFFFFFF )
  851. {
  852. TlsFree( dwTlsIndex );
  853. }
  854. if ( dwRandFailTlsIndex != 0xFFFFFFFF )
  855. {
  856. TlsFree( dwRandFailTlsIndex );
  857. }
  858. //
  859. // restore the initial Exception filter; NULL signifies use the default
  860. //
  861. SetUnhandledExceptionFilter( lpfnPreviousFilter );
  862. if ( hShutdownEvent != NULL )
  863. {
  864. INT_TRACE( "AsyncTraceCleanup Calling SetEvent( hShutdownEvent )\n" );
  865. SetEvent( hShutdownEvent );
  866. INT_TRACE( "AsyncTraceCleanup Called SetEvent: Error: 0x%X\n", GetLastError() );
  867. }
  868. if ( PendQ.hWriteThread != NULL )
  869. {
  870. hThreads[nObjects++] = PendQ.hWriteThread;
  871. }
  872. if ( PendQ.hRegNotifyThread != NULL )
  873. {
  874. hThreads[nObjects++] = PendQ.hRegNotifyThread;
  875. }
  876. //
  877. // allow background threads forever to shutdown
  878. //
  879. if ( nObjects != 0 )
  880. {
  881. INT_TRACE( "AsyncTraceCleanup Calling WFMO\n" );
  882. dw = WaitForMultipleObjects(nObjects,
  883. hThreads,
  884. TRUE,
  885. INFINITE );
  886. INT_TRACE( "AsyncTraceCleanup Called WFMO: dw: 0x%X Error: 0x%X\n",
  887. dw, GetLastError() );
  888. }
  889. if ( PendQ.hWriteThread != NULL )
  890. {
  891. CloseHandle( PendQ.hWriteThread );
  892. PendQ.hWriteThread = NULL;
  893. }
  894. if ( PendQ.hRegNotifyThread != NULL )
  895. {
  896. CloseHandle( PendQ.hRegNotifyThread );
  897. PendQ.hRegNotifyThread = NULL;
  898. }
  899. if ( PendQ.hEvent != NULL )
  900. {
  901. CloseHandle( PendQ.hEvent );
  902. PendQ.hEvent = NULL;
  903. }
  904. if ( PendQ.hFlushEvent != NULL )
  905. {
  906. CloseHandle( PendQ.hFlushEvent );
  907. PendQ.hFlushEvent = NULL;
  908. }
  909. if ( PendQ.hFlushedEvent != NULL )
  910. {
  911. CloseHandle( PendQ.hFlushedEvent );
  912. PendQ.hFlushedEvent = NULL;
  913. }
  914. if ( hShutdownEvent != NULL )
  915. {
  916. CloseHandle( hShutdownEvent );
  917. hShutdownEvent = NULL;
  918. }
  919. #if FALSE
  920. INT_TRACE( "TailCritSec - Contention: %d, Entry: %d\n",
  921. PendQ.critSecTail.DebugInfo->ContentionCount,
  922. PendQ.critSecTail.DebugInfo->EntryCount );
  923. INT_TRACE( "WriteCritSec - Contention: %d, Entry: %d\n",
  924. critSecWrite.DebugInfo->ContentionCount,
  925. critSecWrite.DebugInfo->EntryCount );
  926. INT_TRACE( "FlushCritSec - Contention: %d, Entry: %d\n",
  927. critSecFlush.DebugInfo->ContentionCount,
  928. critSecFlush.DebugInfo->EntryCount );
  929. #endif
  930. DeleteCriticalSection( &PendQ.critSecTail );
  931. DeleteCriticalSection( &critSecWrite );
  932. DeleteCriticalSection( &critSecFlush );
  933. if ( PendQ.hFile != INVALID_HANDLE_VALUE )
  934. {
  935. CloseHandle( PendQ.hFile );
  936. }
  937. PendQ.pHead = PendQ.pTail = (LPTRACEBUF)&PendQ.Special;
  938. PendQ.Special.pNext = (LPTRACEBUF)NULL;
  939. //
  940. // free up the trace buffer CPool
  941. //
  942. TermTraceBuffers();
  943. INT_TRACE( "Total number of traces: %d\n", dwNumTraces );
  944. InterlockedExchange( &PendQ.fShutdown, FALSE );
  945. fInitialized = FALSE;
  946. return TRUE;
  947. }
  948. //+---------------------------------------------------------------
  949. //
  950. // Function: FlushBufferedWrites
  951. //
  952. // Synopsis: internal routine to write the PendQ temporary buffer
  953. // to disk. Used to avoid multiple OS calls and increase
  954. // the write buffers.
  955. //
  956. // Arguments: void
  957. //
  958. // Returns: BOOL: whether it worked
  959. //
  960. //----------------------------------------------------------------
  961. BOOL FlushBufferedWrites( void )
  962. {
  963. BOOL b = TRUE;
  964. DWORD dwBytes;
  965. BOOL bRetry = TRUE;
  966. //
  967. // need to lock the file since multiple process on multiple machines
  968. // may be tracing the same file and both writes have to complete as one.
  969. //
  970. if ( PendQ.cbBufferEnd )
  971. {
  972. DWORD dwOffset;
  973. ASSERT( PendQ.cbBufferEnd < MAX_WRITE_BUFFER_SIZE );
  974. dwOffset = SetFilePointer( PendQ.hFile, 0, 0, FILE_END );
  975. //
  976. // if the file is too big then we need to truncate it
  977. //
  978. if (dwOffset > dwMaxFileSize)
  979. {
  980. SetFilePointer(PendQ.hFile, 0, 0, FILE_BEGIN);
  981. SetEndOfFile(PendQ.hFile);
  982. }
  983. try_again:
  984. b = WriteFile( PendQ.hFile,
  985. PendQ.Buffer,
  986. PendQ.cbBufferEnd,
  987. &dwBytes,
  988. NULL );
  989. if ( b == FALSE || dwBytes != PendQ.cbBufferEnd )
  990. {
  991. DWORD dwError = GetLastError();
  992. if( dwError && bRetry )
  993. {
  994. bRetry = FALSE;
  995. Sleep( 100 );
  996. goto try_again;
  997. }
  998. // ASSERT( FALSE );
  999. INT_TRACE( "Error writing to file: %d, number of bytes %d:%d\n",
  1000. dwError,
  1001. PendQ.cbBufferEnd,
  1002. dwBytes );
  1003. }
  1004. }
  1005. PendQ.cbBufferEnd = 0;
  1006. return b;
  1007. }
  1008. //+---------------------------------------------------------------
  1009. //
  1010. // Function: WriteTraceBuffer
  1011. //
  1012. // Synopsis: internal routine to route the trace info to the
  1013. // appropriate trace log
  1014. //
  1015. // Arguments: LPTRACEBUF: the buffer to write
  1016. //
  1017. // Returns: BOOL: whether it worked
  1018. //
  1019. //----------------------------------------------------------------
  1020. BOOL WriteTraceBuffer( LPTRACEBUF lpBuf )
  1021. {
  1022. ASSERT( lpBuf != NULL );
  1023. ASSERT( lpBuf->dwSignature == TRACE_SIGNATURE );
  1024. InterlockedIncrement( &dwNumTraces );
  1025. EnterCriticalSection( &critSecWrite );
  1026. if ( IsTraceFile( dwTraceOutputType ) && PendQ.hFile != INVALID_HANDLE_VALUE )
  1027. {
  1028. DWORD dwWrite;
  1029. //
  1030. // assert must be handled inside critical section
  1031. //
  1032. ASSERT( PendQ.cbBufferEnd+MAX_TRACE_ENTRY_SIZE < MAX_WRITE_BUFFER_SIZE );
  1033. CopyMemory( PendQ.Buffer + PendQ.cbBufferEnd,
  1034. (char *)&lpBuf->Fixed,
  1035. dwWrite = sizeof(FIXEDTRACE) + lpBuf->Fixed.wVariableLength );
  1036. PendQ.cbBufferEnd += dwWrite;
  1037. if ( PendQ.cbBufferEnd + MAX_TRACE_ENTRY_SIZE >= MAX_WRITE_BUFFER_SIZE ||
  1038. dwAsyncTraceFlag == 0 )
  1039. {
  1040. FlushBufferedWrites();
  1041. }
  1042. }
  1043. else if ( dwTraceOutputType & TRACE_OUTPUT_DEBUG )
  1044. {
  1045. char szThread[16];
  1046. LPSTR lpsz;
  1047. EnterCriticalSection( &critSecWrite );
  1048. wsprintf( szThread, "0x%08X: ", lpBuf->Fixed.dwThreadId );
  1049. OutputDebugString( szThread );
  1050. switch( lpBuf->Fixed.wBinaryType )
  1051. {
  1052. case TRACE_STRING:
  1053. //
  1054. // lstrcat may appear wasteful here; but it is less expensive than an
  1055. // additional call to OutputDebugString( "\r\n" ); which works by
  1056. // raising an exception.
  1057. //
  1058. // although appending \r\n on already full buffer is even worse
  1059. //
  1060. lpsz = lpBuf->Buffer + lpBuf->Fixed.wBinaryOffset - sizeof(FIXEDTRACE);
  1061. OutputDebugString( lpsz );
  1062. OutputDebugString( "\r\n" );
  1063. break;
  1064. case TRACE_BINARY:
  1065. OutputDebugString( "Binary Trace\r\n" );
  1066. break;
  1067. case TRACE_MESSAGE:
  1068. OutputDebugString( "Message Trace\r\n" );
  1069. break;
  1070. }
  1071. LeaveCriticalSection( &critSecWrite );
  1072. }
  1073. else if ( dwTraceOutputType & TRACE_OUTPUT_DISCARD )
  1074. {
  1075. //
  1076. // fastest way to remove buffers. Used to find
  1077. // deadlocks and race conditions
  1078. //
  1079. }
  1080. else if ( dwTraceOutputType & TRACE_OUTPUT_INVALID )
  1081. {
  1082. InterlockedDecrement( &dwNumTraces );
  1083. //
  1084. // unknown trace output type
  1085. //
  1086. ASSERT( FALSE );
  1087. }
  1088. LeaveCriticalSection( &critSecWrite );
  1089. return TRUE;
  1090. }
  1091. //+---------------------------------------------------------------
  1092. //
  1093. // Function: FlushAsyncPendingQueue
  1094. //
  1095. // Synopsis: internal routine to empty the PendQ queue from the
  1096. // background thread
  1097. // Assumes it is not called re-entrantly: actually the
  1098. // FIFO queue assumes only one thread dequeues buffers
  1099. //
  1100. // Arguments: void
  1101. //
  1102. // Returns: BOOL: whether it worked
  1103. //
  1104. //----------------------------------------------------------------
  1105. void FlushAsyncPendingQueue( void )
  1106. {
  1107. LPTRACEBUF lpBuf;
  1108. while( PendQ.dwCount > 0 )
  1109. {
  1110. lpBuf = DequeueAsyncTraceBuffer();
  1111. //
  1112. // if we've buffered more than we'll write before
  1113. // truncating the file then throw away the trace
  1114. //
  1115. if ( PendQ.dwCount < PendQ.dwThresholdCount )
  1116. {
  1117. WriteTraceBuffer( lpBuf );
  1118. }
  1119. else
  1120. {
  1121. INT_TRACE( "Discarding traces: %u\n", PendQ.dwCount );
  1122. }
  1123. FreeTraceBuffer( lpBuf );
  1124. }
  1125. FlushBufferedWrites();
  1126. }
  1127. #define NUM_WRITE_THREAD_OBJECTS 3
  1128. //+---------------------------------------------------------------
  1129. //
  1130. // Function: WriteTraceThread
  1131. //
  1132. // Synopsis: background thread routine for pulling and writing
  1133. // trace buffers from PendQ FIFO queue.
  1134. //
  1135. // Arguments: see Win32 SDK - ignored here
  1136. //
  1137. // Returns: DWORD: 0 if we exitted gracefully
  1138. //
  1139. //----------------------------------------------------------------
  1140. DWORD WriteTraceThread( LPDWORD lpdw )
  1141. {
  1142. HANDLE Handles[NUM_WRITE_THREAD_OBJECTS];
  1143. DWORD dw;
  1144. //
  1145. // preference given to Shutdown, FlushEvent and then the
  1146. // normal buffer event. This ensures that provide a quick
  1147. // response on both shutdown and to a lesser extent Flush
  1148. // since other threads are waiting for this thread to respond.
  1149. //
  1150. Handles[0] = hShutdownEvent;
  1151. Handles[1] = PendQ.hFlushEvent;
  1152. Handles[2] = PendQ.hEvent;
  1153. INT_TRACE( "WriteTraceThreadId 0x%X\n", GetCurrentThreadId() );
  1154. for ( ;; )
  1155. {
  1156. dw = WaitForMultipleObjects(NUM_WRITE_THREAD_OBJECTS,
  1157. Handles,
  1158. FALSE,
  1159. INFINITE );
  1160. switch( dw )
  1161. {
  1162. //
  1163. // normal signalled event
  1164. //
  1165. case WAIT_OBJECT_0+2:
  1166. FlushAsyncPendingQueue();
  1167. break;
  1168. //
  1169. // signalled by a foreground thread to flush our Q
  1170. //
  1171. case WAIT_OBJECT_0+0:
  1172. case WAIT_OBJECT_0+1:
  1173. FlushAsyncPendingQueue();
  1174. if ( dw == WAIT_OBJECT_0+1 )
  1175. {
  1176. SetEvent( PendQ.hFlushedEvent );
  1177. }
  1178. else
  1179. {
  1180. INT_TRACE( "Exiting WriteTraceThread for hShutdownEvent\n" );
  1181. return 0;
  1182. }
  1183. break;
  1184. default:
  1185. GetLastError();
  1186. ASSERT( FALSE );
  1187. }
  1188. }
  1189. INT_TRACE( "Exiting WriteTraceThread abnormally\n" );
  1190. }
  1191. //+---------------------------------------------------------------------------
  1192. //
  1193. // Function: ShouldLogModule
  1194. //
  1195. // Synopsis: Figures out whether a particular module is on the list of
  1196. // modules to be logged.
  1197. //
  1198. // Arguments: [szModule] -- Name of module to check
  1199. //
  1200. // Returns: TRUE if module should log, FALSE if logging is disabled for
  1201. // MODULE
  1202. //
  1203. // Notes:
  1204. //
  1205. //----------------------------------------------------------------------------
  1206. BOOL
  1207. ShouldLogModule(
  1208. LPCSTR szModule)
  1209. {
  1210. LPSTR szEntry;
  1211. //
  1212. // If a list of modules has not been specified, then all modules are to be
  1213. // logged
  1214. //
  1215. if (mszModules[0] == 0) {
  1216. return TRUE;
  1217. }
  1218. //
  1219. // Otherwise, we check to see if the name of the module is in the list
  1220. // mszModule is expected to be a set of NULL terminated strings, with the
  1221. // last string double-null-terminated.
  1222. //
  1223. szEntry = mszModules;
  1224. while (szEntry[0] != 0) {
  1225. if (lstrcmpi(szEntry, szModule) == 0) {
  1226. return TRUE;
  1227. }
  1228. szEntry += (strlen(szEntry) + 1);
  1229. }
  1230. return FALSE;
  1231. }