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 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
74  Thread* worker() { return &worker_; }
75
76  // Context: Main Thread.  Subclass should override to do pre-work setup.
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.
88  virtual void OnWorkStop() { }
89
90  // Context: Main Thread.  Subclass should override to do post-work cleanup.
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:
108    explicit Worker(SignalThread* parent) : parent_(parent) {}
109    virtual ~Worker() { Stop(); }
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:
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    }
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