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 "platform/heap/Handle.h"
36#include "wtf/HashMap.h"
37#include "wtf/Threading.h"
38#include "wtf/ThreadingPrimitives.h"
39#include "wtf/Vector.h"
40#include "wtf/text/StringHash.h"
41#include "wtf/text/WTFString.h"
42
43namespace blink {
44
45class InspectorClient;
46
47class TraceEventDispatcher {
48    WTF_MAKE_NONCOPYABLE(TraceEventDispatcher);
49public:
50    class TraceEvent {
51    public:
52        TraceEvent()
53            : m_name(0)
54            , m_argumentCount(0)
55        {
56        }
57
58        TraceEvent(double timestamp, char phase, const char* name, unsigned long long id, ThreadIdentifier threadIdentifier,
59            int argumentCount, const char* const* argumentNames, const unsigned char* argumentTypes, const unsigned long long* argumentValues)
60            : m_timestamp(timestamp)
61            , m_phase(phase)
62            , m_name(name)
63            , m_id(id)
64            , m_threadIdentifier(threadIdentifier)
65            , m_argumentCount(argumentCount)
66        {
67            if (m_argumentCount > MaxArguments) {
68                ASSERT_NOT_REACHED();
69                m_argumentCount = MaxArguments;
70            }
71            for (int i = 0; i < m_argumentCount; ++i) {
72                m_argumentNames[i] = argumentNames[i];
73                if (argumentTypes[i] == TRACE_VALUE_TYPE_COPY_STRING) {
74                    m_stringArguments[i] = reinterpret_cast<const char*>(argumentValues[i]);
75                    m_argumentValues[i].m_string = reinterpret_cast<const char*>(m_stringArguments[i].characters8());
76                    m_argumentTypes[i] = TRACE_VALUE_TYPE_STRING;
77                } else {
78                    m_argumentValues[i].m_int = argumentValues[i];
79                    m_argumentTypes[i] = argumentTypes[i];
80                }
81            }
82        }
83
84        double timestamp() const { return m_timestamp; }
85        char phase() const { return m_phase; }
86        const char* name() const { return m_name; }
87        unsigned long long id() const { return m_id; }
88        ThreadIdentifier threadIdentifier() const { return m_threadIdentifier; }
89        int argumentCount() const { return m_argumentCount; }
90        bool isNull() const { return !m_name; }
91
92        bool asBool(const char* name) const
93        {
94            return parameter(name, TRACE_VALUE_TYPE_BOOL).m_bool;
95        }
96        long long asInt(const char* name) const
97        {
98            size_t index = findParameter(name);
99            if (index == kNotFound || (m_argumentTypes[index] != TRACE_VALUE_TYPE_INT && m_argumentTypes[index] != TRACE_VALUE_TYPE_UINT)) {
100                ASSERT_NOT_REACHED();
101                return 0;
102            }
103            return reinterpret_cast<const blink::TraceEvent::TraceValueUnion*>(m_argumentValues + index)->m_int;
104        }
105        unsigned long long asUInt(const char* name) const
106        {
107            return asInt(name);
108        }
109        double asDouble(const char* name) const
110        {
111            return parameter(name, TRACE_VALUE_TYPE_DOUBLE).m_double;
112        }
113        const char* asString(const char* name) const
114        {
115            return parameter(name, TRACE_VALUE_TYPE_STRING).m_string;
116        }
117
118    private:
119        enum { MaxArguments = 2 };
120
121        size_t findParameter(const char*) const;
122        const blink::TraceEvent::TraceValueUnion& parameter(const char* name, unsigned char expectedType) const;
123
124        double m_timestamp;
125        char m_phase;
126        const char* m_name;
127        unsigned long long m_id;
128        ThreadIdentifier m_threadIdentifier;
129        int m_argumentCount;
130        const char* m_argumentNames[MaxArguments];
131        unsigned char m_argumentTypes[MaxArguments];
132        blink::TraceEvent::TraceValueUnion m_argumentValues[MaxArguments];
133        // These are only used as buffers for TRACE_VALUE_TYPE_COPY_STRING.
134        // Consider allocating the entire vector of buffered trace events and their copied arguments out of a special arena
135        // to make things more compact.
136        String m_stringArguments[MaxArguments];
137    };
138
139    class TraceEventListener : public NoBaseWillBeGarbageCollected<TraceEventListener> {
140    public:
141#if !ENABLE(OILPAN)
142        virtual ~TraceEventListener() { }
143#endif
144        virtual void call(const TraceEventDispatcher::TraceEvent&) = 0;
145        virtual void* target() = 0;
146        virtual void trace(Visitor*) { }
147    };
148
149    static TraceEventDispatcher* instance()
150    {
151        DEFINE_STATIC_LOCAL(TraceEventDispatcher, instance, ());
152        return &instance;
153    }
154
155    void addListener(const char* name, char phase, PassOwnPtrWillBeRawPtr<TraceEventListener>, InspectorClient*);
156
157    void removeAllListeners(void*, InspectorClient*);
158    void processBackgroundEvents();
159
160private:
161    typedef std::pair<String, int> EventSelector;
162    typedef WillBeHeapHashMap<EventSelector, OwnPtrWillBeMember<WillBeHeapVector<OwnPtrWillBeMember<TraceEventListener> > > > ListenersMap;
163
164    TraceEventDispatcher()
165        : m_listeners(adoptPtrWillBeNoop(new ListenersMap()))
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(double timestamp, char phase, const char* name, unsigned long long id, ThreadIdentifier,
176        int argumentCount, const char* const* argumentNames, const unsigned char* argumentTypes, const unsigned long long* argumentValues);
177    void processBackgroundEventsTask();
178
179    Mutex m_mutex;
180    OwnPtrWillBePersistent<ListenersMap> m_listeners;
181    Vector<TraceEvent> m_backgroundEvents;
182    bool m_processEventsTaskInFlight;
183    double m_lastEventProcessingTime;
184};
185
186} // namespace blink
187
188#endif // TraceEventDispatcher_h
189