|  | // 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_ |