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 to begin the worker thread. 49 void Start(); 50 51 // Context: Main Thread. If the worker thread is not running, deletes the 52 // object immediately. Otherwise, asks the worker thread to abort processing, 53 // and schedules the object to be deleted once the worker exits. 54 // SignalWorkDone will not be signalled. If wait is true, does not return 55 // until the thread is deleted. 56 void Destroy(bool wait); 57 58 // Context: Main Thread. If the worker thread is complete, deletes the 59 // object immediately. Otherwise, schedules the object to be deleted once 60 // the worker thread completes. SignalWorkDone will be signalled. 61 void Release(); 62 63 // Context: Main Thread. Signalled when work is complete. 64 sigslot::signal1<SignalThread *> SignalWorkDone; 65 66 enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; 67 68 protected: 69 ~SignalThread() override; 70 worker()71 Thread* worker() { return &worker_; } 72 73 // Context: Main Thread. Subclass should override to do pre-work setup. OnWorkStart()74 virtual void OnWorkStart() { } 75 76 // Context: Worker Thread. Subclass should override to do work. 77 virtual void DoWork() = 0; 78 79 // Context: Worker Thread. Subclass should call periodically to 80 // dispatch messages and determine if the thread should terminate. 81 bool ContinueWork(); 82 83 // Context: Worker Thread. Subclass should override when extra work is 84 // needed to abort the worker thread. OnWorkStop()85 virtual void OnWorkStop() { } 86 87 // Context: Main Thread. Subclass should override to do post-work cleanup. OnWorkDone()88 virtual void OnWorkDone() { } 89 90 // Context: Any Thread. If subclass overrides, be sure to call the base 91 // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) 92 void OnMessage(Message* msg) override; 93 94 private: 95 enum State { 96 kInit, // Initialized, but not started 97 kRunning, // Started and doing work 98 kReleasing, // Same as running, but to be deleted when work is done 99 kComplete, // Work is done 100 kStopping, // Work is being interrupted 101 }; 102 103 class Worker : public Thread { 104 public: Worker(SignalThread * parent)105 explicit Worker(SignalThread* parent) : parent_(parent) {} 106 ~Worker() override; 107 void Run() override; 108 109 private: 110 SignalThread* parent_; 111 112 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Worker); 113 }; 114 115 class SCOPED_LOCKABLE EnterExit { 116 public: EnterExit(SignalThread * t)117 explicit EnterExit(SignalThread* t) EXCLUSIVE_LOCK_FUNCTION(t->cs_) 118 : t_(t) { 119 t_->cs_.Enter(); 120 // If refcount_ is zero then the object has already been deleted and we 121 // will be double-deleting it in ~EnterExit()! (shouldn't happen) 122 ASSERT(t_->refcount_ != 0); 123 ++t_->refcount_; 124 } UNLOCK_FUNCTION()125 ~EnterExit() UNLOCK_FUNCTION() { 126 bool d = (0 == --t_->refcount_); 127 t_->cs_.Leave(); 128 if (d) 129 delete t_; 130 } 131 132 private: 133 SignalThread* t_; 134 135 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit); 136 }; 137 138 void Run(); 139 void OnMainThreadDestroyed(); 140 141 Thread* main_; 142 Worker worker_; 143 CriticalSection cs_; 144 State state_; 145 int refcount_; 146 147 RTC_DISALLOW_COPY_AND_ASSIGN(SignalThread); 148 }; 149 150 /////////////////////////////////////////////////////////////////////////////// 151 152 } // namespace rtc 153 154 #endif // WEBRTC_BASE_SIGNALTHREAD_H_ 155