1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2009, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifndef TALK_BASE_SIGNALTHREAD_H_ 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define TALK_BASE_SIGNALTHREAD_H_ 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <string> 323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/thread.h" 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/sigslot.h" 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base { 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/////////////////////////////////////////////////////////////////////////////// 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// SignalThread - Base class for worker threads. The main thread should call 40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Start() to begin work, and then follow one of these models: 41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Normal: Wait for SignalWorkDone, and then call Release to destroy. 42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Cancellation: Call Release(true), to abort the worker thread. 43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Fire-and-forget: Call Release(false), which allows the thread to run to 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// completion, and then self-destruct without further notification. 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// again to repeat the task. When the instance isn't needed anymore, 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// call Release. DoWork, OnWorkStart and OnWorkStop are called again, 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// on a new thread. 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// The subclass should override DoWork() to perform the background task. By 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// periodically calling ContinueWork(), it can check for cancellation. 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// tasks in the context of the main thread. 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/////////////////////////////////////////////////////////////////////////////// 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass SignalThread : public sigslot::has_slots<>, protected MessageHandler { 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalThread(); 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Context: Main Thread. Call before Start to change the worker's name. 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool SetName(const std::string& name, const void* obj); 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. Call before Start to change the worker's priority. 633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool SetPriority(ThreadPriority priority); 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. Call to begin the worker thread. 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void Start(); 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. If the worker thread is not running, deletes the 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // object immediately. Otherwise, asks the worker thread to abort processing, 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // and schedules the object to be deleted once the worker exits. 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // SignalWorkDone will not be signalled. If wait is true, does not return 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // until the thread is deleted. 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void Destroy(bool wait); 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. If the worker thread is complete, deletes the 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // object immediately. Otherwise, schedules the object to be deleted once 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // the worker thread completes. SignalWorkDone will be signalled. 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void Release(); 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. Signalled when work is complete. 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sigslot::signal1<SignalThread *> SignalWorkDone; 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch protected: 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual ~SignalThread(); 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Thread* worker() { return &worker_; } 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. Subclass should override to do pre-work setup. 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnWorkStart() { } 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Worker Thread. Subclass should override to do work. 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void DoWork() = 0; 95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Worker Thread. Subclass should call periodically to 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // dispatch messages and determine if the thread should terminate. 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool ContinueWork(); 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Worker Thread. Subclass should override when extra work is 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // needed to abort the worker thread. 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnWorkStop() { } 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Main Thread. Subclass should override to do post-work cleanup. 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnWorkDone() { } 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Context: Any Thread. If subclass overrides, be sure to call the base 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnMessage(Message *msg); 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private: 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch enum State { 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kInit, // Initialized, but not started 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kRunning, // Started and doing work 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kReleasing, // Same as running, but to be deleted when work is done 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kComplete, // Work is done 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kStopping, // Work is being interrupted 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch }; 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch friend class Worker; 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch class Worker : public Thread { 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalThread* parent_; 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void Run() { parent_->Run(); } 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch }; 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch friend class EnterExit; 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch class EnterExit { 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch explicit EnterExit(SignalThread* t) : t_(t) { 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch t_->cs_.Enter(); 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch t_->refcount_ += 1; 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ~EnterExit() { 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool d = (0 == (--(t_->refcount_))); 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch t_->cs_.Leave(); 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (d) 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete t_; 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private: 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalThread* t_; 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch }; 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void Run(); 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void OnMainThreadDestroyed(); 146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Thread* main_; 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Worker worker_; 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CriticalSection cs_; 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch State state_; 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int refcount_; 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/////////////////////////////////////////////////////////////////////////////// 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base 157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // TALK_BASE_SIGNALTHREAD_H_ 159