| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 | // | 
 | // Declaration of a Windows event trace consumer base class. | 
 | #ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_ | 
 | #define BASE_WIN_EVENT_TRACE_CONSUMER_H_ | 
 |  | 
 | #include <windows.h> | 
 | #include <wmistr.h> | 
 | #include <evntrace.h> | 
 | #include <stddef.h> | 
 | #include <vector> | 
 |  | 
 | #include "base/macros.h" | 
 |  | 
 | namespace base { | 
 | namespace win { | 
 |  | 
 | // This class is a base class that makes it easier to consume events | 
 | // from realtime or file sessions. Concrete consumers need to subclass | 
 | // a specialization of this class and override the ProcessEvent and/or | 
 | // the ProcessBuffer methods to implement the event consumption logic. | 
 | // Usage might look like: | 
 | // class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> { | 
 | //  protected: | 
 | //    static VOID WINAPI ProcessEvent(PEVENT_TRACE event); | 
 | // }; | 
 | // | 
 | // MyConsumer consumer; | 
 | // consumer.OpenFileSession(file_path); | 
 | // consumer.Consume(); | 
 | template <class ImplClass> | 
 | class EtwTraceConsumerBase { | 
 |  public: | 
 |   // Constructs a closed consumer. | 
 |   EtwTraceConsumerBase() { | 
 |   } | 
 |  | 
 |   ~EtwTraceConsumerBase() { | 
 |     Close(); | 
 |   } | 
 |  | 
 |   // Opens the named realtime session, which must be existent. | 
 |   // Note: You can use OpenRealtimeSession or OpenFileSession | 
 |   //    to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at | 
 |   //    any one time, though only one of them may be a realtime | 
 |   //    session. | 
 |   HRESULT OpenRealtimeSession(const wchar_t* session_name); | 
 |  | 
 |   // Opens the event trace log in "file_name", which must be a full or | 
 |   // relative path to an existing event trace log file. | 
 |   // Note: You can use OpenRealtimeSession or OpenFileSession | 
 |   //    to open as many as kNumSessions at any one time. | 
 |   HRESULT OpenFileSession(const wchar_t* file_name); | 
 |  | 
 |   // Consume all open sessions from beginning to end. | 
 |   HRESULT Consume(); | 
 |  | 
 |   // Close all open sessions. | 
 |   HRESULT Close(); | 
 |  | 
 |  protected: | 
 |   // Override in subclasses to handle events. | 
 |   static void ProcessEvent(EVENT_TRACE* event) { | 
 |   } | 
 |   // Override in subclasses to handle buffers. | 
 |   static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) { | 
 |     return true;  // keep going | 
 |   } | 
 |  | 
 |  protected: | 
 |   // Currently open sessions. | 
 |   std::vector<TRACEHANDLE> trace_handles_; | 
 |  | 
 |  private: | 
 |   // These delegate to ImplClass callbacks with saner signatures. | 
 |   static void WINAPI ProcessEventCallback(EVENT_TRACE* event) { | 
 |     ImplClass::ProcessEvent(event); | 
 |   } | 
 |   static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) { | 
 |     return ImplClass::ProcessBuffer(buffer); | 
 |   } | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase); | 
 | }; | 
 |  | 
 | template <class ImplClass> inline | 
 | HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession( | 
 |     const wchar_t* session_name) { | 
 |   EVENT_TRACE_LOGFILE logfile = {}; | 
 |   logfile.LoggerName = const_cast<wchar_t*>(session_name); | 
 |   logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; | 
 |   logfile.BufferCallback = &ProcessBufferCallback; | 
 |   logfile.EventCallback = &ProcessEventCallback; | 
 |   logfile.Context = this; | 
 |   TRACEHANDLE trace_handle = ::OpenTrace(&logfile); | 
 |   if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle) | 
 |     return HRESULT_FROM_WIN32(::GetLastError()); | 
 |  | 
 |   trace_handles_.push_back(trace_handle); | 
 |   return S_OK; | 
 | } | 
 |  | 
 | template <class ImplClass> inline | 
 | HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession( | 
 |     const wchar_t* file_name) { | 
 |   EVENT_TRACE_LOGFILE logfile = {}; | 
 |   logfile.LogFileName = const_cast<wchar_t*>(file_name); | 
 |   logfile.BufferCallback = &ProcessBufferCallback; | 
 |   logfile.EventCallback = &ProcessEventCallback; | 
 |   logfile.Context = this; | 
 |   TRACEHANDLE trace_handle = ::OpenTrace(&logfile); | 
 |   if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle) | 
 |     return HRESULT_FROM_WIN32(::GetLastError()); | 
 |  | 
 |   trace_handles_.push_back(trace_handle); | 
 |   return S_OK; | 
 | } | 
 |  | 
 | template <class ImplClass> inline | 
 | HRESULT EtwTraceConsumerBase<ImplClass>::Consume() { | 
 |   ULONG err = ::ProcessTrace(&trace_handles_[0], | 
 |                              static_cast<ULONG>(trace_handles_.size()), | 
 |                              NULL, | 
 |                              NULL); | 
 |   return HRESULT_FROM_WIN32(err); | 
 | } | 
 |  | 
 | template <class ImplClass> inline | 
 | HRESULT EtwTraceConsumerBase<ImplClass>::Close() { | 
 |   HRESULT hr = S_OK; | 
 |   for (size_t i = 0; i < trace_handles_.size(); ++i) { | 
 |     if (NULL != trace_handles_[i]) { | 
 |       ULONG ret = ::CloseTrace(trace_handles_[i]); | 
 |       trace_handles_[i] = NULL; | 
 |  | 
 |       if (FAILED(HRESULT_FROM_WIN32(ret))) | 
 |         hr = HRESULT_FROM_WIN32(ret); | 
 |     } | 
 |   } | 
 |   trace_handles_.clear(); | 
 |  | 
 |   return hr; | 
 | } | 
 |  | 
 | }  // namespace win | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_ |