1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef WEBRTC_BASE_SIGNALTHREAD_H_ 12 #define WEBRTC_BASE_SIGNALTHREAD_H_ 13 14 #include <string> 15 16 #include "webrtc/base/constructormagic.h" 17 #include "webrtc/base/sigslot.h" 18 #include "webrtc/base/thread.h" 19 20 namespace rtc { 21 22 /////////////////////////////////////////////////////////////////////////////// 23 // SignalThread - Base class for worker threads. The main thread should call 24 // Start() to begin work, and then follow one of these models: 25 // Normal: Wait for SignalWorkDone, and then call Release to destroy. 26 // Cancellation: Call Release(true), to abort the worker thread. 27 // Fire-and-forget: Call Release(false), which allows the thread to run to 28 // completion, and then self-destruct without further notification. 29 // Periodic tasks: Wait for SignalWorkDone, then eventually call Start() 30 // again to repeat the task. When the instance isn't needed anymore, 31 // call Release. DoWork, OnWorkStart and OnWorkStop are called again, 32 // on a new thread. 33 // The subclass should override DoWork() to perform the background task. By 34 // periodically calling ContinueWork(), it can check for cancellation. 35 // OnWorkStart and OnWorkDone can be overridden to do pre- or post-work 36 // tasks in the context of the main thread. 37 /////////////////////////////////////////////////////////////////////////////// 38 39 class SignalThread 40 : public sigslot::has_slots<>, 41 protected MessageHandler { 42 public: 43 SignalThread(); 44 45 // Context: Main Thread. Call before Start to change the worker's name. 46 bool SetName(const std::string& name, const void* obj); 47 48 // Context: Main Thread. Call before Start to change the worker's priority. 49 bool SetPriority(ThreadPriority priority); 50 51 // Context: Main Thread. Call to begin the worker thread. 52 void Start(); 53 54 // Context: Main Thread. If the worker thread is not running, deletes the 55 // object immediately. Otherwise, asks the worker thread to abort processing, 56 // and schedules the object to be deleted once the worker exits. 57 // SignalWorkDone will not be signalled. If wait is true, does not return 58 // until the thread is deleted. 59 void Destroy(bool wait); 60 61 // Context: Main Thread. If the worker thread is complete, deletes the 62 // object immediately. Otherwise, schedules the object to be deleted once 63 // the worker thread completes. SignalWorkDone will be signalled. 64 void Release(); 65 66 // Context: Main Thread. Signalled when work is complete. 67 sigslot::signal1<SignalThread *> SignalWorkDone; 68 69 enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; 70 71 protected: 72 virtual ~SignalThread(); 73 worker()74 Thread* worker() { return &worker_; } 75 76 // Context: Main Thread. Subclass should override to do pre-work setup. OnWorkStart()77 virtual void OnWorkStart() { } 78 79 // Context: Worker Thread. Subclass should override to do work. 80 virtual void DoWork() = 0; 81 82 // Context: Worker Thread. Subclass should call periodically to 83 // dispatch messages and determine if the thread should terminate. 84 bool ContinueWork(); 85 86 // Context: Worker Thread. Subclass should override when extra work is 87 // needed to abort the worker thread. OnWorkStop()88 virtual void OnWorkStop() { } 89 90 // Context: Main Thread. Subclass should override to do post-work cleanup. OnWorkDone()91 virtual void OnWorkDone() { } 92 93 // Context: Any Thread. If subclass overrides, be sure to call the base 94 // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) 95 virtual void OnMessage(Message *msg); 96 97 private: 98 enum State { 99 kInit, // Initialized, but not started 100 kRunning, // Started and doing work 101 kReleasing, // Same as running, but to be deleted when work is done 102 kComplete, // Work is done 103 kStopping, // Work is being interrupted 104 }; 105 106 class Worker : public Thread { 107 public: Worker(SignalThread * parent)108 explicit Worker(SignalThread* parent) : parent_(parent) {} ~Worker()109 virtual ~Worker() { Stop(); } Run()110 virtual void Run() { parent_->Run(); } 111 112 private: 113 SignalThread* parent_; 114 115 DISALLOW_IMPLICIT_CONSTRUCTORS(Worker); 116 }; 117 118 class SCOPED_LOCKABLE EnterExit { 119 public: EnterExit(SignalThread * t)120 explicit EnterExit(SignalThread* t) EXCLUSIVE_LOCK_FUNCTION(t->cs_) 121 : t_(t) { 122 t_->cs_.Enter(); 123 // If refcount_ is zero then the object has already been deleted and we 124 // will be double-deleting it in ~EnterExit()! (shouldn't happen) 125 ASSERT(t_->refcount_ != 0); 126 ++t_->refcount_; 127 } UNLOCK_FUNCTION()128 ~EnterExit() UNLOCK_FUNCTION() { 129 bool d = (0 == --t_->refcount_); 130 t_->cs_.Leave(); 131 if (d) 132 delete t_; 133 } 134 135 private: 136 SignalThread* t_; 137 138 DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit); 139 }; 140 141 void Run(); 142 void OnMainThreadDestroyed(); 143 144 Thread* main_; 145 Worker worker_; 146 CriticalSection cs_; 147 State state_; 148 int refcount_; 149 150 DISALLOW_COPY_AND_ASSIGN(SignalThread); 151 }; 152 153 /////////////////////////////////////////////////////////////////////////////// 154 155 } // namespace rtc 156 157 #endif // WEBRTC_BASE_SIGNALTHREAD_H_ 158