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