DFG worklist should use AutomaticThread
[WebKit-https.git] / Source / WTF / wtf / AutomaticThread.cpp
1 /*
2  * Copyright (C) 2016 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "AutomaticThread.h"
28
29 #include "DataLog.h"
30
31 namespace WTF {
32
33 static const bool verbose = false;
34
35 RefPtr<AutomaticThreadCondition> AutomaticThreadCondition::create()
36 {
37     return adoptRef(new AutomaticThreadCondition());
38 }
39
40 AutomaticThreadCondition::AutomaticThreadCondition()
41 {
42 }
43
44 AutomaticThreadCondition::~AutomaticThreadCondition()
45 {
46 }
47
48 void AutomaticThreadCondition::notifyOne(const LockHolder& locker)
49 {
50     if (m_condition.notifyOne())
51         return;
52     
53     if (m_threads.isEmpty())
54         return;
55     
56     m_threads.takeLast()->start(locker);
57 }
58
59 void AutomaticThreadCondition::notifyAll(const LockHolder& locker)
60 {
61     m_condition.notifyAll();
62     
63     for (AutomaticThread* thread : m_threads)
64         thread->start(locker);
65     m_threads.clear();
66 }
67
68 void AutomaticThreadCondition::add(const LockHolder&, AutomaticThread* thread)
69 {
70     ASSERT(!m_threads.contains(thread));
71     m_threads.append(thread);
72 }
73
74 void AutomaticThreadCondition::remove(const LockHolder&, AutomaticThread* thread)
75 {
76     ASSERT(m_threads.contains(thread));
77     m_threads.removeFirst(thread);
78     ASSERT(!m_threads.contains(thread));
79 }
80
81 bool AutomaticThreadCondition::contains(const LockHolder&, AutomaticThread* thread)
82 {
83     return m_threads.contains(thread);
84 }
85
86 AutomaticThread::AutomaticThread(const LockHolder& locker, Box<Lock> lock, RefPtr<AutomaticThreadCondition> condition)
87     : m_lock(lock)
88     , m_condition(condition)
89 {
90     m_condition->add(locker, this);
91 }
92
93 AutomaticThread::~AutomaticThread()
94 {
95     LockHolder locker(*m_lock);
96     
97     // It's possible that we're in a waiting state with the thread shut down. This is a goofy way to
98     // die, but it could happen.
99     m_condition->remove(locker, this);
100 }
101
102 void AutomaticThread::join()
103 {
104     LockHolder locker(*m_lock);
105     while (m_isRunning)
106         m_isRunningCondition.wait(*m_lock);
107 }
108
109 class AutomaticThread::ThreadScope {
110 public:
111     ThreadScope(AutomaticThread& thread)
112         : m_thread(thread)
113     {
114         m_thread.threadDidStart();
115     }
116     
117     ~ThreadScope()
118     {
119         m_thread.threadWillStop();
120     }
121
122 private:
123     AutomaticThread& m_thread;
124 };
125
126 void AutomaticThread::start(const LockHolder&)
127 {
128     RefPtr<AutomaticThread> preserveThisForThread = this;
129     
130     ThreadIdentifier thread = createThread(
131         "WTF::AutomaticThread",
132         [=] () {
133             if (verbose)
134                 dataLog("Running automatic thread!\n");
135             RefPtr<AutomaticThread> preserveThisInThread = preserveThisForThread;
136             
137             {
138                 LockHolder locker(*m_lock);
139                 ASSERT(!m_condition->contains(locker, this));
140             }
141             
142             ThreadScope threadScope(*this);
143             
144             auto stop = [&] (const LockHolder&) {
145                 m_isRunning = false;
146                 m_isRunningCondition.notifyAll();
147             };
148             
149             for (;;) {
150                 {
151                     LockHolder locker(*m_lock);
152                     for (;;) {
153                         PollResult result = poll(locker);
154                         if (result == PollResult::Work)
155                             break;
156                         if (result == PollResult::Stop)
157                             return stop(locker);
158                         RELEASE_ASSERT(result == PollResult::Wait);
159                         // Shut the thread down after one second.
160                         double timeout = monotonicallyIncreasingTime() + 1;
161                         bool awokenByNotify =
162                             m_condition->m_condition.waitUntilMonotonicClockSeconds(*m_lock, timeout);
163                         if (!awokenByNotify) {
164                             if (verbose)
165                                 dataLog("Going to sleep!\n");
166                             m_condition->add(locker, this);
167                             return;
168                         }
169                     }
170                 }
171                 
172                 WorkResult result = work();
173                 if (result == WorkResult::Stop) {
174                     LockHolder locker(*m_lock);
175                     return stop(locker);
176                 }
177                 RELEASE_ASSERT(result == WorkResult::Continue);
178             }
179         });
180     detachThread(thread);
181 }
182
183 void AutomaticThread::threadDidStart()
184 {
185 }
186
187 void AutomaticThread::threadWillStop()
188 {
189 }
190
191 } // namespace WTF
192