diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WTF/wtf/AutomaticThread.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WTF/wtf/AutomaticThread.h')
-rw-r--r-- | Source/WTF/wtf/AutomaticThread.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/Source/WTF/wtf/AutomaticThread.h b/Source/WTF/wtf/AutomaticThread.h new file mode 100644 index 000000000..ec6ba438f --- /dev/null +++ b/Source/WTF/wtf/AutomaticThread.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WTF_AutomaticThread_h +#define WTF_AutomaticThread_h + +#include <wtf/Box.h> +#include <wtf/Condition.h> +#include <wtf/Lock.h> +#include <wtf/Ref.h> +#include <wtf/ThreadSafeRefCounted.h> +#include <wtf/Threading.h> +#include <wtf/Vector.h> + +namespace WTF { + +// Often, we create threads that have this as their body: +// +// for (;;) { +// { +// LockHolder locker(m_lock); +// for (;;) { +// [1] stuff that could break, return, or fall through; +// m_condition.wait(m_lock); +// } +// } +// +// [2] do work; +// } +// +// When we do this, we don't always do a good job of managing this thread's lifetime, which may lead +// to this thread sitting around even when it is not needed. +// +// AutomaticThread is here to help you in these situations. It encapsulates a lock, a condition +// variable, and a thread. It will automatically shut the thread down after 1 second of inactivity. +// You use AutomaticThread by subclassing it, and put any state that is needed between [1] and [2] +// in the subclass. +// +// The terminology we use is: +// +// [1] PollResult AutomaticThread::poll() +// [2] WordResult AutomaticThread::work() +// +// Note that poll() and work() may not be called on the same thread every time, since this will shut +// down the thread as necessary. This is legal since m_condition.wait(m_lock) can drop the lock, and +// so there is no reason to keep the thread around. + +class AutomaticThread; + +class AutomaticThreadCondition : public ThreadSafeRefCounted<AutomaticThreadCondition> { +public: + static WTF_EXPORT_PRIVATE RefPtr<AutomaticThreadCondition> create(); + + WTF_EXPORT_PRIVATE ~AutomaticThreadCondition(); + + WTF_EXPORT_PRIVATE void notifyOne(const AbstractLocker&); + WTF_EXPORT_PRIVATE void notifyAll(const AbstractLocker&); + + // You can reuse this condition for other things, just as you would any other condition. + // However, since conflating conditions could lead to thundering herd, it's best to avoid it. + // One known-good case for one-true-condition is when the communication involves just two + // threads. In such cases, the thread doing the notifyAll() can wake up at most one thread - + // its partner. + WTF_EXPORT_PRIVATE void wait(Lock&); + +private: + friend class AutomaticThread; + + WTF_EXPORT_PRIVATE AutomaticThreadCondition(); + + void add(const AbstractLocker&, AutomaticThread*); + void remove(const AbstractLocker&, AutomaticThread*); + bool contains(const AbstractLocker&, AutomaticThread*); + + Condition m_condition; + Vector<AutomaticThread*> m_threads; +}; + +class WTF_EXPORT_PRIVATE AutomaticThread : public ThreadSafeRefCounted<AutomaticThread> { +public: + // Note that if you drop all of your references to an AutomaticThread then as soon as there is a + // second during which it doesn't get woken up, it will simply die on its own. This is a + // permanent kind of death where the AutomaticThread object goes away, rather than the temporary + // kind of death where AutomaticThread lives but its underlying thread dies. All you have to do + // to prevent permanent death is keep a ref to AutomaticThread. At time of writing, every user of + // AutomaticThread keeps a ref to it and does join() as part of the shutdown process, so only the + // temporary kind of automatic death happens in practice. We keep the permanent death feature + // because it leads to an easy-to-understand reference counting discipline (AutomaticThread holds + // strong ref to AutomaticThreadCondition and the underlying thread holds a strong ref to + // AutomaticThread). + virtual ~AutomaticThread(); + + // Sometimes it's possible to optimize for the case that there is no underlying thread. + bool hasUnderlyingThread(const AbstractLocker&) const { return m_hasUnderlyingThread; } + + // This attempts to quickly stop the thread. This will succeed if the thread happens to not be + // running. Returns true if the thread has been stopped. A good idiom for stopping your automatic + // thread is to first try this, and if that doesn't work, to tell the thread using your own + // mechanism (set some flag and then notify the condition). + bool tryStop(const AbstractLocker&); + + bool isWaiting(const AbstractLocker&); + + bool notify(const AbstractLocker&); + + void join(); + +protected: + // This logically creates the thread, but in reality the thread won't be created until someone + // calls AutomaticThreadCondition::notifyOne() or notifyAll(). + AutomaticThread(const AbstractLocker&, Box<Lock>, RefPtr<AutomaticThreadCondition>); + + // To understand PollResult and WorkResult, imagine that poll() and work() are being called like + // so: + // + // void AutomaticThread::runThread() + // { + // for (;;) { + // { + // LockHolder locker(m_lock); + // for (;;) { + // PollResult result = poll(); + // if (result == PollResult::Work) + // break; + // if (result == PollResult::Stop) + // return; + // RELEASE_ASSERT(result == PollResult::Wait); + // m_condition.wait(m_lock); + // } + // } + // + // WorkResult result = work(); + // if (result == WorkResult::Stop) + // return; + // RELEASE_ASSERT(result == WorkResult::Continue); + // } + // } + + enum class PollResult { Work, Stop, Wait }; + virtual PollResult poll(const AbstractLocker&) = 0; + + enum class WorkResult { Continue, Stop }; + virtual WorkResult work() = 0; + + // It's sometimes useful to allocate resources while the thread is running, and to destroy them + // when the thread dies. These methods let you do this. You can override these methods, and you + // can be sure that the default ones don't do anything (so you don't need a super call). + virtual void threadDidStart(); + virtual void threadIsStopping(const AbstractLocker&); + +private: + friend class AutomaticThreadCondition; + + void start(const AbstractLocker&); + + Box<Lock> m_lock; + RefPtr<AutomaticThreadCondition> m_condition; + bool m_isRunning { true }; + bool m_isWaiting { false }; + bool m_hasUnderlyingThread { false }; + Condition m_waitCondition; + Condition m_isRunningCondition; +}; + +} // namespace WTF + +using WTF::AutomaticThread; +using WTF::AutomaticThreadCondition; + +#endif // WTF_AutomaticThread_h + |