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.

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