blob: 9a20ad252bce8b173595d5ec3ad16be96c207e6c [file] [log] [blame]
deadbeef8290ddf2017-07-11 16:56:05 -07001/*
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
Steve Anton10542f22019-01-11 09:11:00 -080011#ifndef RTC_BASE_SIGNAL_THREAD_H_
12#define RTC_BASE_SIGNAL_THREAD_H_
deadbeef8290ddf2017-07-11 16:56:05 -070013
14#include <string>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -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"
Yves Gerey988cc082018-10-23 12:03:01 +020021#include "rtc_base/third_party/sigslot/sigslot.h"
22#include "rtc_base/thread.h"
23#include "rtc_base/thread_annotations.h"
deadbeef8290ddf2017-07-11 16:56:05 -070024
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
Yves Gerey665174f2018-06-19 15:03:05 +020044class SignalThread : public sigslot::has_slots<>, protected MessageHandler {
deadbeef8290ddf2017-07-11 16:56:05 -070045 public:
Niels Möller77d37112018-01-15 12:59:43 +010046 SignalThread();
deadbeef8290ddf2017-07-11 16:56:05 -070047
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.
Yves Gerey665174f2018-06-19 15:03:05 +020067 sigslot::signal1<SignalThread*> SignalWorkDone;
deadbeef8290ddf2017-07-11 16:56:05 -070068
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.
Yves Gerey665174f2018-06-19 15:03:05 +020077 virtual void OnWorkStart() {}
deadbeef8290ddf2017-07-11 16:56:05 -070078
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.
Yves Gerey665174f2018-06-19 15:03:05 +020088 virtual void OnWorkStop() {}
deadbeef8290ddf2017-07-11 16:56:05 -070089
90 // Context: Main Thread. Subclass should override to do post-work cleanup.
Yves Gerey665174f2018-06-19 15:03:05 +020091 virtual void OnWorkDone() {}
deadbeef8290ddf2017-07-11 16:56:05 -070092
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 {
Yves Gerey665174f2018-06-19 15:03:05 +020099 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
deadbeef8290ddf2017-07-11 16:56:05 -0700104 };
105
106 class Worker : public Thread {
107 public:
Taylor Brandstetter08672602018-03-02 15:20:33 -0800108 explicit Worker(SignalThread* parent);
deadbeef8290ddf2017-07-11 16:56:05 -0700109 ~Worker() override;
110 void Run() override;
Niels Möller8909a632018-09-06 08:42:44 +0200111 bool IsProcessingMessagesForTesting() override;
deadbeef8290ddf2017-07-11 16:56:05 -0700112
113 private:
114 SignalThread* parent_;
115
116 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Worker);
117 };
118
danilchap3c6abd22017-09-06 05:46:29 -0700119 class RTC_SCOPED_LOCKABLE EnterExit {
deadbeef8290ddf2017-07-11 16:56:05 -0700120 public:
danilchap3c6abd22017-09-06 05:46:29 -0700121 explicit EnterExit(SignalThread* t) RTC_EXCLUSIVE_LOCK_FUNCTION(t->cs_)
deadbeef8290ddf2017-07-11 16:56:05 -0700122 : 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 }
danilchap3c6abd22017-09-06 05:46:29 -0700129 ~EnterExit() RTC_UNLOCK_FUNCTION() {
deadbeef8290ddf2017-07-11 16:56:05 -0700130 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
Steve Anton10542f22019-01-11 09:11:00 -0800158#endif // RTC_BASE_SIGNAL_THREAD_H_