blob: c5f3bc3951bcc3f2e8546da19fe948b1e8b7b0b7 [file] [log] [blame]
Tommibebc6902015-05-18 09:51:42 +02001/*
2 * Copyright (c) 2015 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/platform_thread.h"
Tommibebc6902015-05-18 09:51:42 +020012
Markus Handell97c44582021-04-20 17:41:54 +020013#include <memory>
14
Yves Gerey988cc082018-10-23 12:03:01 +020015#if !defined(WEBRTC_WIN)
16#include <sched.h>
17#endif
Guido Urdaneta793bac52021-05-06 13:12:47 +000018#include <stdint.h>
19#include <time.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020020
Guido Urdaneta793bac52021-05-06 13:12:47 +000021#include <algorithm>
22
23#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/checks.h"
Tommibebc6902015-05-18 09:51:42 +020025
Tommibebc6902015-05-18 09:51:42 +020026namespace rtc {
Markus Handellc89fdd72021-05-05 10:42:04 +020027
Guido Urdaneta793bac52021-05-06 13:12:47 +000028namespace {
29struct ThreadStartData {
30 ThreadRunFunction run_function;
31 void* obj;
32 std::string thread_name;
33 ThreadPriority priority;
34};
pbos12411ef2015-11-23 14:47:56 -080035
Markus Handell97c44582021-04-20 17:41:54 +020036bool SetPriority(ThreadPriority priority) {
pbos12411ef2015-11-23 14:47:56 -080037#if defined(WEBRTC_WIN)
Guido Urdaneta793bac52021-05-06 13:12:47 +000038 return SetThreadPriority(GetCurrentThread(), priority) != FALSE;
Wez0614ed92018-02-06 13:38:21 -080039#elif defined(__native_client__) || defined(WEBRTC_FUCHSIA)
40 // Setting thread priorities is not supported in NaCl or Fuchsia.
Peter Boströmc6612132015-11-24 18:10:24 +010041 return true;
42#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
43 // TODO(tommi): Switch to the same mechanism as Chromium uses for changing
44 // thread priorities.
pbos12411ef2015-11-23 14:47:56 -080045 return true;
46#else
pbos12411ef2015-11-23 14:47:56 -080047 const int policy = SCHED_FIFO;
pbos12411ef2015-11-23 14:47:56 -080048 const int min_prio = sched_get_priority_min(policy);
49 const int max_prio = sched_get_priority_max(policy);
50 if (min_prio == -1 || max_prio == -1) {
51 return false;
52 }
53
54 if (max_prio - min_prio <= 2)
55 return false;
56
Peter Boström97c821d2015-11-24 13:48:13 +010057 // Convert webrtc priority to system priorities:
pbos12411ef2015-11-23 14:47:56 -080058 sched_param param;
Peter Boström97c821d2015-11-24 13:48:13 +010059 const int top_prio = max_prio - 1;
60 const int low_prio = min_prio + 1;
61 switch (priority) {
Guido Urdaneta793bac52021-05-06 13:12:47 +000062 case kLowPriority:
Peter Boström97c821d2015-11-24 13:48:13 +010063 param.sched_priority = low_prio;
64 break;
Guido Urdaneta793bac52021-05-06 13:12:47 +000065 case kNormalPriority:
Peter Boström97c821d2015-11-24 13:48:13 +010066 // The -1 ensures that the kHighPriority is always greater or equal to
67 // kNormalPriority.
68 param.sched_priority = (low_prio + top_prio - 1) / 2;
69 break;
Guido Urdaneta793bac52021-05-06 13:12:47 +000070 case kHighPriority:
Peter Boström97c821d2015-11-24 13:48:13 +010071 param.sched_priority = std::max(top_prio - 2, low_prio);
72 break;
Guido Urdaneta793bac52021-05-06 13:12:47 +000073 case kHighestPriority:
74 param.sched_priority = std::max(top_prio - 1, low_prio);
75 break;
76 case kRealtimePriority:
Peter Boström97c821d2015-11-24 13:48:13 +010077 param.sched_priority = top_prio;
78 break;
pbos12411ef2015-11-23 14:47:56 -080079 }
Markus Handell97c44582021-04-20 17:41:54 +020080 return pthread_setschedparam(pthread_self(), policy, &param) == 0;
81#endif // defined(WEBRTC_WIN)
82}
83
Guido Urdaneta793bac52021-05-06 13:12:47 +000084void RunPlatformThread(std::unique_ptr<ThreadStartData> data) {
85 rtc::SetCurrentThreadName(data->thread_name.c_str());
86 data->thread_name.clear();
87 SetPriority(data->priority);
88 data->run_function(data->obj);
89}
90
Markus Handell97c44582021-04-20 17:41:54 +020091#if defined(WEBRTC_WIN)
Guido Urdaneta793bac52021-05-06 13:12:47 +000092DWORD WINAPI StartThread(void* param) {
Markus Handell97c44582021-04-20 17:41:54 +020093 // The GetLastError() function only returns valid results when it is called
94 // after a Win32 API function that returns a "failed" result. A crash dump
95 // contains the result from GetLastError() and to make sure it does not
96 // falsely report a Windows error we call SetLastError here.
97 ::SetLastError(ERROR_SUCCESS);
Guido Urdaneta793bac52021-05-06 13:12:47 +000098 RunPlatformThread(absl::WrapUnique(static_cast<ThreadStartData*>(param)));
Markus Handell97c44582021-04-20 17:41:54 +020099 return 0;
100}
101#else
Guido Urdaneta793bac52021-05-06 13:12:47 +0000102void* StartThread(void* param) {
103 RunPlatformThread(absl::WrapUnique(static_cast<ThreadStartData*>(param)));
Markus Handell97c44582021-04-20 17:41:54 +0200104 return 0;
105}
106#endif // defined(WEBRTC_WIN)
107
108} // namespace
109
Guido Urdaneta793bac52021-05-06 13:12:47 +0000110PlatformThread::PlatformThread(ThreadRunFunction func,
111 void* obj,
112 absl::string_view thread_name,
113 ThreadAttributes attributes)
114 : run_function_(func),
115 attributes_(attributes),
116 obj_(obj),
117 name_(thread_name) {
118 RTC_DCHECK(func);
119 RTC_DCHECK(!name_.empty());
120 // TODO(tommi): Consider lowering the limit to 15 (limit on Linux).
121 RTC_DCHECK(name_.length() < 64);
Markus Handell97c44582021-04-20 17:41:54 +0200122}
123
124PlatformThread::~PlatformThread() {
Guido Urdaneta793bac52021-05-06 13:12:47 +0000125 RTC_DCHECK_RUN_ON(&thread_checker_);
126 RTC_DCHECK(!thread_);
Markus Handellc89fdd72021-05-05 10:42:04 +0200127#if defined(WEBRTC_WIN)
Guido Urdaneta793bac52021-05-06 13:12:47 +0000128 RTC_DCHECK(!thread_id_);
129#endif // defined(WEBRTC_WIN)
Markus Handellc89fdd72021-05-05 10:42:04 +0200130}
131
Guido Urdaneta793bac52021-05-06 13:12:47 +0000132void PlatformThread::Start() {
133 RTC_DCHECK_RUN_ON(&thread_checker_);
134 RTC_DCHECK(!thread_) << "Thread already started?";
135 ThreadStartData* data =
136 new ThreadStartData{run_function_, obj_, name_, attributes_.priority};
Markus Handell97c44582021-04-20 17:41:54 +0200137#if defined(WEBRTC_WIN)
138 // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
139 // Set the reserved stack stack size to 1M, which is the default on Windows
140 // and Linux.
Guido Urdaneta793bac52021-05-06 13:12:47 +0000141 thread_ = ::CreateThread(nullptr, 1024 * 1024, &StartThread, data,
142 STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_);
143 RTC_CHECK(thread_) << "CreateThread failed";
144 RTC_DCHECK(thread_id_);
Markus Handell97c44582021-04-20 17:41:54 +0200145#else
146 pthread_attr_t attr;
147 pthread_attr_init(&attr);
148 // Set the stack stack size to 1M.
149 pthread_attr_setstacksize(&attr, 1024 * 1024);
Guido Urdaneta793bac52021-05-06 13:12:47 +0000150 pthread_attr_setdetachstate(&attr, attributes_.joinable
151 ? PTHREAD_CREATE_JOINABLE
152 : PTHREAD_CREATE_DETACHED);
153 RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, data));
Markus Handell97c44582021-04-20 17:41:54 +0200154 pthread_attr_destroy(&attr);
155#endif // defined(WEBRTC_WIN)
156}
157
Guido Urdaneta793bac52021-05-06 13:12:47 +0000158bool PlatformThread::IsRunning() const {
159 RTC_DCHECK_RUN_ON(&thread_checker_);
160#if defined(WEBRTC_WIN)
161 return thread_ != nullptr;
162#else
163 return thread_ != 0;
164#endif // defined(WEBRTC_WIN)
165}
166
167PlatformThreadRef PlatformThread::GetThreadRef() const {
168#if defined(WEBRTC_WIN)
169 return thread_id_;
170#else
171 return thread_;
172#endif // defined(WEBRTC_WIN)
173}
174
175void PlatformThread::Stop() {
176 RTC_DCHECK_RUN_ON(&thread_checker_);
177 if (!IsRunning())
178 return;
179
180#if defined(WEBRTC_WIN)
181 if (attributes_.joinable) {
182 WaitForSingleObject(thread_, INFINITE);
183 }
184 CloseHandle(thread_);
185 thread_ = nullptr;
186 thread_id_ = 0;
187#else
188 if (attributes_.joinable) {
189 RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
190 }
191 thread_ = 0;
192#endif // defined(WEBRTC_WIN)
193}
194
195#if defined(WEBRTC_WIN)
196bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
197 RTC_DCHECK_RUN_ON(&thread_checker_);
198 RTC_DCHECK(IsRunning());
199
200 return QueueUserAPC(function, thread_, data) != FALSE;
201}
202#endif
203
Peter Boström8c38e8b2015-11-26 17:45:47 +0100204} // namespace rtc