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
20namespace 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
39class 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
71  Thread* worker() { return &worker_; }
72
73  // Context: Main Thread.  Subclass should override to do pre-work setup.
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.
85  virtual void OnWorkStop() { }
86
87  // Context: Main Thread.  Subclass should override to do post-work cleanup.
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:
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:
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    }
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