blob: 9a20ad252bce8b173595d5ec3ad16be96c207e6c [file] [log] [blame]
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +08001/*
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
Hsin-Yu Chaof76cafb2019-04-01 13:54:10 +080011#ifndef RTC_BASE_SIGNAL_THREAD_H_
12#define RTC_BASE_SIGNAL_THREAD_H_
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080013
14#include <string>
15
16#include "rtc_base/checks.h"
Hsin-Yu Chaof76cafb2019-04-01 13:54:10 +080017#include "rtc_base/constructor_magic.h"
18#include "rtc_base/critical_section.h"
19#include "rtc_base/message_handler.h"
20#include "rtc_base/message_queue.h"
Hsin-Yu Chao640d48b2018-11-09 16:51:50 +080021#include "rtc_base/third_party/sigslot/sigslot.h"
22#include "rtc_base/thread.h"
23#include "rtc_base/thread_annotations.h"
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080024
25namespace rtc {
26
27///////////////////////////////////////////////////////////////////////////////
28// SignalThread - Base class for worker threads. The main thread should call
29// Start() to begin work, and then follow one of these models:
30// Normal: Wait for SignalWorkDone, and then call Release to destroy.
31// Cancellation: Call Release(true), to abort the worker thread.
32// Fire-and-forget: Call Release(false), which allows the thread to run to
33// completion, and then self-destruct without further notification.
34// Periodic tasks: Wait for SignalWorkDone, then eventually call Start()
35// again to repeat the task. When the instance isn't needed anymore,
36// call Release. DoWork, OnWorkStart and OnWorkStop are called again,
37// on a new thread.
38// The subclass should override DoWork() to perform the background task. By
39// periodically calling ContinueWork(), it can check for cancellation.
40// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work
41// tasks in the context of the main thread.
42///////////////////////////////////////////////////////////////////////////////
43
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080044class SignalThread : public sigslot::has_slots<>, protected MessageHandler {
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080045 public:
46 SignalThread();
47
48 // Context: Main Thread. Call before Start to change the worker's name.
49 bool SetName(const std::string& name, const void* obj);
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.
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080067 sigslot::signal1<SignalThread*> SignalWorkDone;
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080068
69 enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE };
70
71 protected:
72 ~SignalThread() override;
73
74 Thread* worker() { return &worker_; }
75
76 // Context: Main Thread. Subclass should override to do pre-work setup.
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080077 virtual void OnWorkStart() {}
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080078
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.
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080088 virtual void OnWorkStop() {}
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080089
90 // Context: Main Thread. Subclass should override to do post-work cleanup.
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080091 virtual void OnWorkDone() {}
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +080092
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 void OnMessage(Message* msg) override;
96
97 private:
98 enum State {
Hsin-Yu Chaoedc34c82018-08-09 17:53:05 +080099 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
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +0800104 };
105
106 class Worker : public Thread {
107 public:
108 explicit Worker(SignalThread* parent);
109 ~Worker() override;
110 void Run() override;
Hsin-Yu Chao1bda95a2018-10-17 15:30:12 +0800111 bool IsProcessingMessagesForTesting() override;
Hsin-Yu Chao47ed2092018-03-17 16:50:45 +0800112
113 private:
114 SignalThread* parent_;
115
116 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Worker);
117 };
118
119 class RTC_SCOPED_LOCKABLE EnterExit {
120 public:
121 explicit EnterExit(SignalThread* t) RTC_EXCLUSIVE_LOCK_FUNCTION(t->cs_)
122 : t_(t) {
123 t_->cs_.Enter();
124 // If refcount_ is zero then the object has already been deleted and we
125 // will be double-deleting it in ~EnterExit()! (shouldn't happen)
126 RTC_DCHECK_NE(0, t_->refcount_);
127 ++t_->refcount_;
128 }
129 ~EnterExit() RTC_UNLOCK_FUNCTION() {
130 bool d = (0 == --t_->refcount_);
131 t_->cs_.Leave();
132 if (d)
133 delete t_;
134 }
135
136 private:
137 SignalThread* t_;
138
139 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EnterExit);
140 };
141
142 void Run();
143 void OnMainThreadDestroyed();
144
145 Thread* main_;
146 Worker worker_;
147 CriticalSection cs_;
148 State state_;
149 int refcount_;
150
151 RTC_DISALLOW_COPY_AND_ASSIGN(SignalThread);
152};
153
154///////////////////////////////////////////////////////////////////////////////
155
156} // namespace rtc
157
Hsin-Yu Chaof76cafb2019-04-01 13:54:10 +0800158#endif // RTC_BASE_SIGNAL_THREAD_H_