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 AsyncMethodRunner_h
32#define AsyncMethodRunner_h
33
34#include "platform/Timer.h"
35#include "wtf/FastAllocBase.h"
36#include "wtf/Noncopyable.h"
37
38namespace blink {
39
40template <typename TargetClass>
41class AsyncMethodRunner FINAL {
42    WTF_MAKE_NONCOPYABLE(AsyncMethodRunner);
43    WTF_MAKE_FAST_ALLOCATED;
44public:
45    typedef void (TargetClass::*TargetMethod)();
46
47    AsyncMethodRunner(TargetClass* object, TargetMethod method)
48        : m_timer(this, &AsyncMethodRunner<TargetClass>::fired)
49        , m_object(object)
50        , m_method(method)
51        , m_suspended(false)
52        , m_runWhenResumed(false)
53    {
54    }
55
56    // Schedules to run the method asynchronously. Do nothing if it's already
57    // scheduled. If it's suspended, remember to schedule to run the method when
58    // resume() is called.
59    void runAsync()
60    {
61        if (m_suspended) {
62            ASSERT(!m_timer.isActive());
63            m_runWhenResumed = true;
64            return;
65        }
66
67        // FIXME: runAsync should take a TraceLocation and pass it to timer here.
68        if (!m_timer.isActive())
69            m_timer.startOneShot(0, FROM_HERE);
70    }
71
72    // If it's scheduled to run the method, cancel it and remember to schedule
73    // it again when resume() is called. Mainly for implementing
74    // ActiveDOMObject::suspend().
75    void suspend()
76    {
77        if (m_suspended)
78            return;
79        m_suspended = true;
80
81        if (!m_timer.isActive())
82            return;
83
84        m_timer.stop();
85        m_runWhenResumed = true;
86    }
87
88    // Resumes pending method run.
89    void resume()
90    {
91        if (!m_suspended)
92            return;
93        m_suspended = false;
94
95        if (!m_runWhenResumed)
96            return;
97
98        m_runWhenResumed = false;
99        // FIXME: resume should take a TraceLocation and pass it to timer here.
100        m_timer.startOneShot(0, FROM_HERE);
101    }
102
103    void stop()
104    {
105        if (m_suspended) {
106            ASSERT(!m_timer.isActive());
107            m_runWhenResumed = false;
108            m_suspended = false;
109            return;
110        }
111
112        ASSERT(!m_runWhenResumed);
113        if (m_timer.isActive())
114            m_timer.stop();
115    }
116
117    bool isActive() const
118    {
119        return m_timer.isActive();
120    }
121
122private:
123    void fired(Timer<AsyncMethodRunner<TargetClass> >*) { (m_object->*m_method)(); }
124
125    Timer<AsyncMethodRunner<TargetClass> > m_timer;
126
127    // FIXME: oilpan: AsyncMethodRunner should be moved to the heap and m_object should be traced.
128    // This raw pointer is safe as long as AsyncMethodRunner<X> is held by the X itself
129    // (That's the case in the current code base).
130    GC_PLUGIN_IGNORE("363031")
131    TargetClass* m_object;
132    TargetMethod m_method;
133
134    bool m_suspended;
135    bool m_runWhenResumed;
136};
137
138}
139
140#endif
141