1/*
2* Copyright (C) 2013 Google Inc. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7*
8*     * Redistributions of source code must retain the above copyright
9* notice, this list of conditions and the following disclaimer.
10*     * Redistributions in binary form must reproduce the above
11* copyright notice, this list of conditions and the following disclaimer
12* in the documentation and/or other materials provided with the
13* distribution.
14*     * Neither the name of Google Inc. nor the names of its
15* contributors may be used to endorse or promote products derived from
16* this software without specific prior written permission.
17*
18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30
31#ifndef TraceEventDispatcher_h
32#define TraceEventDispatcher_h
33
34#include "platform/TraceEvent.h"
35#include "wtf/HashMap.h"
36#include "wtf/Threading.h"
37#include "wtf/ThreadingPrimitives.h"
38#include "wtf/Vector.h"
39#include "wtf/text/WTFString.h"
40
41namespace WebCore {
42
43class InspectorClient;
44
45struct TraceEventTargetBase {
46    virtual ~TraceEventTargetBase() { }
47};
48
49template<typename C> struct TraceEventTarget;
50
51class TraceEventDispatcher {
52    WTF_MAKE_NONCOPYABLE(TraceEventDispatcher);
53public:
54    class TraceEvent {
55    public:
56        TraceEvent()
57            : m_name(0)
58            , m_argumentCount(0)
59        {
60        }
61
62        TraceEvent(double timestamp, char phase, const char* name, unsigned long long id, ThreadIdentifier threadIdentifier,
63            int argumentCount, const char* const* argumentNames, const unsigned char* argumentTypes, const unsigned long long* argumentValues)
64            : m_timestamp(timestamp)
65            , m_phase(phase)
66            , m_name(name)
67            , m_id(id)
68            , m_threadIdentifier(threadIdentifier)
69            , m_argumentCount(argumentCount)
70        {
71            if (m_argumentCount > MaxArguments) {
72                ASSERT_NOT_REACHED();
73                m_argumentCount = MaxArguments;
74            }
75            for (int i = 0; i < m_argumentCount; ++i) {
76                m_argumentNames[i] = argumentNames[i];
77                m_argumentTypes[i] = argumentTypes[i];
78                m_argumentValues[i] = argumentValues[i];
79            }
80        }
81
82        double timestamp() const { return m_timestamp; }
83        char phase() const { return m_phase; }
84        const char* name() const { return m_name; }
85        unsigned long long id() const { return m_id; }
86        ThreadIdentifier threadIdentifier() const { return m_threadIdentifier; }
87        int argumentCount() const { return m_argumentCount; }
88        bool isNull() const { return !m_name; }
89
90        bool asBool(const char* name) const
91        {
92            return parameter(name, TRACE_VALUE_TYPE_BOOL).m_bool;
93        }
94        long long asInt(const char* name) const
95        {
96            size_t index = findParameter(name);
97            if (index == kNotFound || (m_argumentTypes[index] != TRACE_VALUE_TYPE_INT && m_argumentTypes[index] != TRACE_VALUE_TYPE_UINT)) {
98                ASSERT_NOT_REACHED();
99                return 0;
100            }
101            return reinterpret_cast<const WebCore::TraceEvent::TraceValueUnion*>(m_argumentValues + index)->m_int;
102        }
103        unsigned long long asUInt(const char* name) const
104        {
105            return asInt(name);
106        }
107        double asDouble(const char* name) const
108        {
109            return parameter(name, TRACE_VALUE_TYPE_DOUBLE).m_double;
110        }
111        const char* asString(const char* name) const
112        {
113            return parameter(name, TRACE_VALUE_TYPE_STRING).m_string;
114        }
115
116    private:
117        enum { MaxArguments = 2 };
118
119        size_t findParameter(const char*) const;
120        const WebCore::TraceEvent::TraceValueUnion& parameter(const char* name, unsigned char expectedType) const;
121
122        double m_timestamp;
123        char m_phase;
124        const char* m_name;
125        unsigned long long m_id;
126        ThreadIdentifier m_threadIdentifier;
127        int m_argumentCount;
128        const char* m_argumentNames[MaxArguments];
129        unsigned char m_argumentTypes[MaxArguments];
130        unsigned long long m_argumentValues[MaxArguments];
131    };
132
133    typedef void (TraceEventTargetBase::*TraceEventHandlerMethod)(const TraceEvent&);
134
135    static TraceEventDispatcher* instance()
136    {
137        DEFINE_STATIC_LOCAL(TraceEventDispatcher, instance, ());
138        return &instance;
139    }
140
141    template<typename ListenerClass>
142    void addListener(const char* name, char phase, ListenerClass* instance, typename TraceEventTarget<ListenerClass>::TraceEventHandler handler, InspectorClient* client)
143    {
144        innerAddListener(name, phase, instance, static_cast<TraceEventHandlerMethod>(handler), client);
145    }
146
147    void removeAllListeners(TraceEventTargetBase*, InspectorClient*);
148    void processBackgroundEvents();
149
150private:
151    struct BoundTraceEventHandler {
152        TraceEventTargetBase* instance;
153        TraceEventHandlerMethod method;
154
155        BoundTraceEventHandler() : instance(0), method(0) { }
156        BoundTraceEventHandler(TraceEventTargetBase* instance, TraceEventHandlerMethod method)
157            : instance(instance)
158            , method(method)
159        {
160        }
161    };
162    typedef std::pair<String, int> EventSelector;
163    typedef HashMap<EventSelector, Vector<BoundTraceEventHandler> > HandlersMap;
164
165    TraceEventDispatcher()
166        : m_processEventsTaskInFlight(false)
167        , m_lastEventProcessingTime(0)
168    {
169    }
170
171    static void dispatchEventOnAnyThread(char phase, const unsigned char*, const char* name, unsigned long long id,
172        int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
173        unsigned char flags, double timestamp);
174
175    void enqueueEvent(const TraceEvent&);
176    void innerAddListener(const char* name, char phase, TraceEventTargetBase*, TraceEventHandlerMethod, InspectorClient*);
177    void processBackgroundEventsTask();
178
179    Mutex m_mutex;
180    HandlersMap m_handlers;
181    Vector<TraceEvent> m_backgroundEvents;
182    bool m_processEventsTaskInFlight;
183    double m_lastEventProcessingTime;
184};
185
186template<typename C> struct TraceEventTarget : public TraceEventTargetBase {
187    typedef void (C::*TraceEventHandler)(const TraceEventDispatcher::TraceEvent&);
188};
189
190} // namespace WebCore
191
192#endif // TraceEventDispatcher_h
193