blob: 9df7aca09019e14f9b40e3552c0eb59475e94bfb [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/realtime.h"
2
Austin Schuhcc6070c2020-10-10 20:25:56 -07003#include <errno.h>
4#include <malloc.h>
5#include <sched.h>
6#include <stdint.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include <stdio.h>
Austin Schuhcc6070c2020-10-10 20:25:56 -07008#include <stdlib.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include <string.h>
10#include <sys/mman.h>
Austin Schuhcc6070c2020-10-10 20:25:56 -070011#include <sys/prctl.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include <sys/resource.h>
13#include <sys/types.h>
14#include <unistd.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -070015
Austin Schuhcc6070c2020-10-10 20:25:56 -070016#include "aos/thread_local.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "glog/logging.h"
18
19namespace FLAG__namespace_do_not_use_directly_use_DECLARE_double_instead {
20extern double FLAGS_tcmalloc_release_rate __attribute__((weak));
21}
22using FLAG__namespace_do_not_use_directly_use_DECLARE_double_instead::
23 FLAGS_tcmalloc_release_rate;
24
25namespace aos {
26namespace logging {
27namespace internal {
28
29// Implemented in aos/logging/context.cc.
30void ReloadThreadName() __attribute__((weak));
31
32} // namespace internal
33} // namespace logging
34
35namespace {
36
James Kuszmaulb4874eb2020-01-18 17:50:35 -080037enum class SetLimitForRoot {
38 kYes,
39 kNo
40};
41
42enum class AllowSoftLimitDecrease {
43 kYes,
44 kNo
45};
46
47void SetSoftRLimit(
48 int resource, rlim64_t soft, SetLimitForRoot set_for_root,
49 AllowSoftLimitDecrease allow_decrease = AllowSoftLimitDecrease::kYes) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070050 bool am_root = getuid() == 0;
James Kuszmaulb4874eb2020-01-18 17:50:35 -080051 if (set_for_root == SetLimitForRoot::kYes || !am_root) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 struct rlimit64 rlim;
53 PCHECK(getrlimit64(resource, &rlim) == 0)
Brian Silverman6a54ff32020-04-28 16:41:39 -070054 << ": getting limit for " << resource;
Alex Perrycb7da4b2019-08-28 19:35:56 -070055
James Kuszmaulb4874eb2020-01-18 17:50:35 -080056 if (allow_decrease == AllowSoftLimitDecrease::kYes) {
57 rlim.rlim_cur = soft;
58 } else {
59 rlim.rlim_cur = std::max(rlim.rlim_cur, soft);
60 }
Alex Perrycb7da4b2019-08-28 19:35:56 -070061 rlim.rlim_max = ::std::max(rlim.rlim_max, soft);
62
63 PCHECK(setrlimit64(resource, &rlim) == 0)
Brian Silverman6a54ff32020-04-28 16:41:39 -070064 << ": changing limit for " << resource << " to " << rlim.rlim_cur
65 << " with max of " << rlim.rlim_max;
Alex Perrycb7da4b2019-08-28 19:35:56 -070066 }
67}
68
69} // namespace
70
71void LockAllMemory() {
Austin Schuhcc6070c2020-10-10 20:25:56 -070072 CheckNotRealtime();
Alex Perrycb7da4b2019-08-28 19:35:56 -070073 // Allow locking as much as we want into RAM.
James Kuszmaulb4874eb2020-01-18 17:50:35 -080074 SetSoftRLimit(RLIMIT_MEMLOCK, RLIM_INFINITY, SetLimitForRoot::kNo);
Alex Perrycb7da4b2019-08-28 19:35:56 -070075
76 WriteCoreDumps();
Brian Silverman6a54ff32020-04-28 16:41:39 -070077 PCHECK(mlockall(MCL_CURRENT | MCL_FUTURE) == 0);
Alex Perrycb7da4b2019-08-28 19:35:56 -070078
Brian Silverman4dbbcce2020-09-18 15:27:38 -070079#if !__has_feature(address_sanitizer) && !__has_feature(memory_sanitizer)
Alex Perrycb7da4b2019-08-28 19:35:56 -070080 // Don't give freed memory back to the OS.
81 CHECK_EQ(1, mallopt(M_TRIM_THRESHOLD, -1));
82 // Don't use mmap for large malloc chunks.
83 CHECK_EQ(1, mallopt(M_MMAP_MAX, 0));
Austin Schuh85faf672020-09-10 22:58:46 -070084#endif
Alex Perrycb7da4b2019-08-28 19:35:56 -070085
86 if (&FLAGS_tcmalloc_release_rate) {
87 // Tell tcmalloc not to return memory.
88 FLAGS_tcmalloc_release_rate = 0.0;
89 }
90
91 // Forces the memory pages for all the stack space that we're ever going to
92 // use to be loaded into memory (so it can be locked there).
93 uint8_t data[4096 * 8];
94 // Not 0 because linux might optimize that to a 0-filled page.
95 memset(data, 1, sizeof(data));
Lee Mracek6afc0ac2020-03-06 12:42:33 -050096 __asm__ __volatile__("" :: "m" (data));
Alex Perrycb7da4b2019-08-28 19:35:56 -070097
98 static const size_t kHeapPreallocSize = 512 * 1024;
99 char *const heap_data = static_cast<char *>(malloc(kHeapPreallocSize));
100 memset(heap_data, 1, kHeapPreallocSize);
Lee Mracek6afc0ac2020-03-06 12:42:33 -0500101 __asm__ __volatile__("" :: "m" (heap_data));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 free(heap_data);
103}
104
105void InitRT() {
Austin Schuhcc6070c2020-10-10 20:25:56 -0700106 CheckNotRealtime();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700107 LockAllMemory();
108
109 // Only let rt processes run for 3 seconds straight.
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800110 SetSoftRLimit(RLIMIT_RTTIME, 3000000, SetLimitForRoot::kYes);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700111
112 // Allow rt processes up to priority 40.
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800113 SetSoftRLimit(RLIMIT_RTPRIO, 40, SetLimitForRoot::kNo);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700114}
115
116void UnsetCurrentThreadRealtimePriority() {
117 struct sched_param param;
118 param.sched_priority = 0;
Brian Silverman6a54ff32020-04-28 16:41:39 -0700119 PCHECK(sched_setscheduler(0, SCHED_OTHER, &param) == 0);
Austin Schuhcc6070c2020-10-10 20:25:56 -0700120 MarkRealtime(false);
Brian Silverman6a54ff32020-04-28 16:41:39 -0700121}
122
123void SetCurrentThreadAffinity(const cpu_set_t &cpuset) {
124 PCHECK(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700125}
126
James Kuszmaul57c2baa2020-01-19 14:52:52 -0800127void SetCurrentThreadName(const std::string_view name) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700128 CHECK_LE(name.size(), 16u) << ": thread name '" << name << "' too long";
129 VLOG(1) << "This thread is changing to '" << name << "'";
James Kuszmaul57c2baa2020-01-19 14:52:52 -0800130 std::string string_name(name);
Brian Silverman6a54ff32020-04-28 16:41:39 -0700131 PCHECK(prctl(PR_SET_NAME, string_name.c_str()) == 0)
132 << ": changing name to " << string_name;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700133 if (&logging::internal::ReloadThreadName != nullptr) {
134 logging::internal::ReloadThreadName();
135 }
136}
137
138void SetCurrentThreadRealtimePriority(int priority) {
139 // Make sure we will only be allowed to run for 3 seconds straight.
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800140 SetSoftRLimit(RLIMIT_RTTIME, 3000000, SetLimitForRoot::kYes);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700141
Brian Silvermanb3826f52020-07-02 19:41:18 -0700142 // Raise our soft rlimit if necessary.
143 SetSoftRLimit(RLIMIT_RTPRIO, priority, SetLimitForRoot::kNo,
144 AllowSoftLimitDecrease::kNo);
145
Alex Perrycb7da4b2019-08-28 19:35:56 -0700146 struct sched_param param;
147 param.sched_priority = priority;
Austin Schuhcc6070c2020-10-10 20:25:56 -0700148 MarkRealtime(true);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149 PCHECK(sched_setscheduler(0, SCHED_FIFO, &param) == 0)
Brian Silverman6a54ff32020-04-28 16:41:39 -0700150 << ": changing to SCHED_FIFO with " << priority;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151}
152
153void WriteCoreDumps() {
154 // Do create core files of unlimited size.
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800155 SetSoftRLimit(RLIMIT_CORE, RLIM_INFINITY, SetLimitForRoot::kYes);
156}
157
158void ExpandStackSize() {
159 SetSoftRLimit(RLIMIT_STACK, 1000000, SetLimitForRoot::kYes,
160 AllowSoftLimitDecrease::kNo);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161}
162
Austin Schuhcc6070c2020-10-10 20:25:56 -0700163namespace {
164AOS_THREAD_LOCAL bool is_realtime = false;
165}
166
167bool MarkRealtime(bool realtime) {
168 const bool prior = is_realtime;
169 is_realtime = realtime;
170 return prior;
171}
172
173void CheckRealtime() { CHECK(is_realtime); }
174
175void CheckNotRealtime() { CHECK(!is_realtime); }
176
177ScopedRealtimeRestorer::ScopedRealtimeRestorer() : prior_(is_realtime) {}
178
Alex Perrycb7da4b2019-08-28 19:35:56 -0700179} // namespace aos