Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WTF / wtf / AutomaticThread.h
1 /*
2  * Copyright (C) 2016-2017 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 #ifndef WTF_AutomaticThread_h
27 #define WTF_AutomaticThread_h
28
29 #include <wtf/Box.h>
30 #include <wtf/Condition.h>
31 #include <wtf/Lock.h>
32 #include <wtf/ThreadSafeRefCounted.h>
33 #include <wtf/Vector.h>
34
35 namespace WTF {
36
37 // Often, we create threads that have this as their body:
38 //
39 //     for (;;) {
40 //         {
41 //             LockHolder locker(m_lock);
42 //             for (;;) {
43 //  [1]            stuff that could break, return, or fall through;
44 //                 m_condition.wait(m_lock);
45 //             }
46 //         }
47 //         
48 //  [2]    do work;
49 //     }
50 //
51 // When we do this, we don't always do a good job of managing this thread's lifetime, which may lead
52 // to this thread sitting around even when it is not needed.
53 //
54 // AutomaticThread is here to help you in these situations. It encapsulates a lock, a condition
55 // variable, and a thread. It will automatically shut the thread down after a timeout of inactivity.
56 // You use AutomaticThread by subclassing it, and put any state that is needed between [1] and [2]
57 // in the subclass.
58 //
59 // The terminology we use is:
60 //
61 // [1] PollResult AutomaticThread::poll()
62 // [2] WorkResult AutomaticThread::work()
63 //
64 // Note that poll() and work() may not be called on the same thread every time, since this will shut
65 // down the thread as necessary. This is legal since m_condition.wait(m_lock) can drop the lock, and
66 // so there is no reason to keep the thread around.
67
68 class AutomaticThread;
69
70 class AutomaticThreadCondition : public ThreadSafeRefCounted<AutomaticThreadCondition> {
71 public:
72     static WTF_EXPORT_PRIVATE Ref<AutomaticThreadCondition> create();
73     
74     WTF_EXPORT_PRIVATE ~AutomaticThreadCondition();
75     
76     WTF_EXPORT_PRIVATE void notifyOne(const AbstractLocker&);
77     WTF_EXPORT_PRIVATE void notifyAll(const AbstractLocker&);
78     
79     // You can reuse this condition for other things, just as you would any other condition.
80     // However, since conflating conditions could lead to thundering herd, it's best to avoid it.
81     // One known-good case for one-true-condition is when the communication involves just two
82     // threads. In such cases, the thread doing the notifyAll() can wake up at most one thread -
83     // its partner.
84     WTF_EXPORT_PRIVATE void wait(Lock&);
85     WTF_EXPORT_PRIVATE bool waitFor(Lock&, Seconds);
86     
87 private:
88     friend class AutomaticThread;
89     
90     WTF_EXPORT_PRIVATE AutomaticThreadCondition();
91
92     void add(const AbstractLocker&, AutomaticThread*);
93     void remove(const AbstractLocker&, AutomaticThread*);
94     bool contains(const AbstractLocker&, AutomaticThread*);
95     
96     Condition m_condition;
97     Vector<AutomaticThread*> m_threads;
98 };
99
100 class WTF_EXPORT_PRIVATE AutomaticThread : public ThreadSafeRefCounted<AutomaticThread> {
101 public:
102     // Note that if you drop all of your references to an AutomaticThread then as soon as there is a
103     // timeout during which it doesn't get woken up, it will simply die on its own. This is a
104     // permanent kind of death where the AutomaticThread object goes away, rather than the temporary
105     // kind of death where AutomaticThread lives but its underlying thread dies. All you have to do
106     // to prevent permanent death is keep a ref to AutomaticThread. At time of writing, every user of
107     // AutomaticThread keeps a ref to it and does join() as part of the shutdown process, so only the
108     // temporary kind of automatic death happens in practice. We keep the permanent death feature
109     // because it leads to an easy-to-understand reference counting discipline (AutomaticThread holds
110     // strong ref to AutomaticThreadCondition and the underlying thread holds a strong ref to
111     // AutomaticThread).
112     virtual ~AutomaticThread();
113     
114     // Sometimes it's possible to optimize for the case that there is no underlying thread.
115     bool hasUnderlyingThread(const AbstractLocker&) const { return m_hasUnderlyingThread; }
116     
117     // This attempts to quickly stop the thread. This will succeed if the thread happens to not be
118     // running. Returns true if the thread has been stopped. A good idiom for stopping your automatic
119     // thread is to first try this, and if that doesn't work, to tell the thread using your own
120     // mechanism (set some flag and then notify the condition).
121     bool tryStop(const AbstractLocker&);
122
123     bool isWaiting(const AbstractLocker&);
124
125     bool notify(const AbstractLocker&);
126
127     void join();
128
129     virtual const char* name() const { return "WTF::AutomaticThread"; }
130
131 protected:
132     // This logically creates the thread, but in reality the thread won't be created until someone
133     // calls AutomaticThreadCondition::notifyOne() or notifyAll().
134     AutomaticThread(const AbstractLocker&, Box<Lock>, Ref<AutomaticThreadCondition>&&, Seconds timeout = 10_s);
135     
136     // To understand PollResult and WorkResult, imagine that poll() and work() are being called like
137     // so:
138     //
139     // void AutomaticThread::runThread()
140     // {
141     //     for (;;) {
142     //         {
143     //             LockHolder locker(m_lock);
144     //             for (;;) {
145     //                 PollResult result = poll();
146     //                 if (result == PollResult::Work)
147     //                     break;
148     //                 if (result == PollResult::Stop)
149     //                     return;
150     //                 RELEASE_ASSERT(result == PollResult::Wait);
151     //                 m_condition.wait(m_lock);
152     //             }
153     //         }
154     //         
155     //         WorkResult result = work();
156     //         if (result == WorkResult::Stop)
157     //             return;
158     //         RELEASE_ASSERT(result == WorkResult::Continue);
159     //     }
160     // }
161     
162     enum class PollResult { Work, Stop, Wait };
163     virtual PollResult poll(const AbstractLocker&) = 0;
164     
165     enum class WorkResult { Continue, Stop };
166     virtual WorkResult work() = 0;
167     
168     // It's sometimes useful to allocate resources while the thread is running, and to destroy them
169     // when the thread dies. These methods let you do this. You can override these methods, and you
170     // can be sure that the default ones don't do anything (so you don't need a super call).
171     virtual void threadDidStart();
172     virtual void threadIsStopping(const AbstractLocker&);
173
174     // Control whether this automatic thread should sleep when timeout happens.
175     // By overriding this function, we can customize how automatic threads will sleep.
176     // For example, when you have thread pool, you can decrease active threads moderately.
177     virtual bool shouldSleep(const AbstractLocker&) { return true; }
178     
179 private:
180     friend class AutomaticThreadCondition;
181     
182     void start(const AbstractLocker&);
183     
184     Box<Lock> m_lock;
185     Ref<AutomaticThreadCondition> m_condition;
186     Seconds m_timeout;
187     bool m_isRunning { true };
188     bool m_isWaiting { false };
189     bool m_hasUnderlyingThread { false };
190     Condition m_waitCondition;
191     Condition m_isRunningCondition;
192 };
193
194 } // namespace WTF
195
196 using WTF::AutomaticThread;
197 using WTF::AutomaticThreadCondition;
198
199 #endif // WTF_AutomaticThread_h
200