1*6fa2df46SAndroid Build Coastguard Worker // Copyright (C) 2023 The Android Open Source Project
2*6fa2df46SAndroid Build Coastguard Worker //
3*6fa2df46SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*6fa2df46SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*6fa2df46SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*6fa2df46SAndroid Build Coastguard Worker //
7*6fa2df46SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*6fa2df46SAndroid Build Coastguard Worker //
9*6fa2df46SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*6fa2df46SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*6fa2df46SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6fa2df46SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*6fa2df46SAndroid Build Coastguard Worker // limitations under the License.
14*6fa2df46SAndroid Build Coastguard Worker
15*6fa2df46SAndroid Build Coastguard Worker #include <ditto/multithreading_utils.h>
16*6fa2df46SAndroid Build Coastguard Worker
17*6fa2df46SAndroid Build Coastguard Worker #include <sched.h>
18*6fa2df46SAndroid Build Coastguard Worker #include <unistd.h>
19*6fa2df46SAndroid Build Coastguard Worker
20*6fa2df46SAndroid Build Coastguard Worker namespace dittosuite {
21*6fa2df46SAndroid Build Coastguard Worker
IsSet() const22*6fa2df46SAndroid Build Coastguard Worker bool SchedAttr::IsSet() const { return initialized_; }
23*6fa2df46SAndroid Build Coastguard Worker
Set() const24*6fa2df46SAndroid Build Coastguard Worker void SchedAttr::Set() const {
25*6fa2df46SAndroid Build Coastguard Worker if (!initialized_) {
26*6fa2df46SAndroid Build Coastguard Worker LOGF("Setting uninitialized scheduling attributes");
27*6fa2df46SAndroid Build Coastguard Worker }
28*6fa2df46SAndroid Build Coastguard Worker
29*6fa2df46SAndroid Build Coastguard Worker LOGD("Setting scheduling policy [" + std::to_string(sched_attr_.sched_policy) +
30*6fa2df46SAndroid Build Coastguard Worker "] to thread: " + std::to_string(syscall_.GetTid()));
31*6fa2df46SAndroid Build Coastguard Worker
32*6fa2df46SAndroid Build Coastguard Worker int ret = syscall_.SchedSetattr(0 /* self */, sched_attr_, 0 /* still not implemented */);
33*6fa2df46SAndroid Build Coastguard Worker if (ret) {
34*6fa2df46SAndroid Build Coastguard Worker PLOGF("Failed setting scheduling attributes \n" + to_string(sched_attr_) + "\n");
35*6fa2df46SAndroid Build Coastguard Worker }
36*6fa2df46SAndroid Build Coastguard Worker }
37*6fa2df46SAndroid Build Coastguard Worker
operator =(const dittosuiteproto::SchedAttr & pb)38*6fa2df46SAndroid Build Coastguard Worker SchedAttr& SchedAttr::operator=(const dittosuiteproto::SchedAttr& pb) {
39*6fa2df46SAndroid Build Coastguard Worker typedef dittosuiteproto::SchedAttr::AttributesCase SchedType;
40*6fa2df46SAndroid Build Coastguard Worker
41*6fa2df46SAndroid Build Coastguard Worker sched_attr_.size = sizeof(sched_attr_);
42*6fa2df46SAndroid Build Coastguard Worker
43*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_flags = pb.flags();
44*6fa2df46SAndroid Build Coastguard Worker
45*6fa2df46SAndroid Build Coastguard Worker switch (pb.attributes_case()) {
46*6fa2df46SAndroid Build Coastguard Worker case SchedType::kOther:
47*6fa2df46SAndroid Build Coastguard Worker switch (pb.other().policy()) {
48*6fa2df46SAndroid Build Coastguard Worker case dittosuiteproto::SchedAttr::SchedOther::OTHER:
49*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_policy = SchedPolicy::SchedNormal;
50*6fa2df46SAndroid Build Coastguard Worker break;
51*6fa2df46SAndroid Build Coastguard Worker case dittosuiteproto::SchedAttr::SchedOther::BATCH:
52*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_policy = SchedPolicy::SchedBatch;
53*6fa2df46SAndroid Build Coastguard Worker break;
54*6fa2df46SAndroid Build Coastguard Worker }
55*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_nice = pb.other().nice();
56*6fa2df46SAndroid Build Coastguard Worker break;
57*6fa2df46SAndroid Build Coastguard Worker case SchedType::kRt:
58*6fa2df46SAndroid Build Coastguard Worker switch (pb.rt().policy()) {
59*6fa2df46SAndroid Build Coastguard Worker case dittosuiteproto::SchedAttr::SchedRt::FIFO:
60*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_policy = SchedPolicy::SchedFifo;
61*6fa2df46SAndroid Build Coastguard Worker break;
62*6fa2df46SAndroid Build Coastguard Worker case dittosuiteproto::SchedAttr::SchedRt::RR:
63*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_policy = SchedPolicy::SchedRr;
64*6fa2df46SAndroid Build Coastguard Worker break;
65*6fa2df46SAndroid Build Coastguard Worker }
66*6fa2df46SAndroid Build Coastguard Worker if (pb.rt().priority() < 1 || pb.rt().priority() > 99) {
67*6fa2df46SAndroid Build Coastguard Worker LOGF("Scheduling priority should be in the range [1, 99]");
68*6fa2df46SAndroid Build Coastguard Worker }
69*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_priority = pb.rt().priority();
70*6fa2df46SAndroid Build Coastguard Worker break;
71*6fa2df46SAndroid Build Coastguard Worker case SchedType::kDeadline:
72*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_policy = SchedPolicy::SchedDeadline;
73*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_runtime = pb.deadline().runtime();
74*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_deadline = pb.deadline().deadline();
75*6fa2df46SAndroid Build Coastguard Worker sched_attr_.sched_period = pb.deadline().period();
76*6fa2df46SAndroid Build Coastguard Worker break;
77*6fa2df46SAndroid Build Coastguard Worker case SchedType::ATTRIBUTES_NOT_SET:
78*6fa2df46SAndroid Build Coastguard Worker LOGF("Missing scheduling attribute");
79*6fa2df46SAndroid Build Coastguard Worker break;
80*6fa2df46SAndroid Build Coastguard Worker }
81*6fa2df46SAndroid Build Coastguard Worker
82*6fa2df46SAndroid Build Coastguard Worker initialized_ = true;
83*6fa2df46SAndroid Build Coastguard Worker
84*6fa2df46SAndroid Build Coastguard Worker return *this;
85*6fa2df46SAndroid Build Coastguard Worker }
86*6fa2df46SAndroid Build Coastguard Worker
Set() const87*6fa2df46SAndroid Build Coastguard Worker void SchedAffinity::Set() const {
88*6fa2df46SAndroid Build Coastguard Worker if (!initialized_) {
89*6fa2df46SAndroid Build Coastguard Worker LOGF("Setting uninitialized affinity attributes");
90*6fa2df46SAndroid Build Coastguard Worker }
91*6fa2df46SAndroid Build Coastguard Worker
92*6fa2df46SAndroid Build Coastguard Worker LOGD("Setting affinity mask [" + std::to_string(mask_) +
93*6fa2df46SAndroid Build Coastguard Worker "] to thread: " + std::to_string(syscall_.GetTid()));
94*6fa2df46SAndroid Build Coastguard Worker
95*6fa2df46SAndroid Build Coastguard Worker cpu_set_t mask;
96*6fa2df46SAndroid Build Coastguard Worker CPU_ZERO(&mask);
97*6fa2df46SAndroid Build Coastguard Worker uint64_t tmp_bitset = mask_;
98*6fa2df46SAndroid Build Coastguard Worker for (unsigned int i=0; i<sizeof(mask_) * 8; ++i) {
99*6fa2df46SAndroid Build Coastguard Worker if (tmp_bitset & 1) {
100*6fa2df46SAndroid Build Coastguard Worker LOGD("Enabling on CPU: " + std::to_string(i));
101*6fa2df46SAndroid Build Coastguard Worker CPU_SET(i, &mask);
102*6fa2df46SAndroid Build Coastguard Worker }
103*6fa2df46SAndroid Build Coastguard Worker tmp_bitset >>= 1;
104*6fa2df46SAndroid Build Coastguard Worker }
105*6fa2df46SAndroid Build Coastguard Worker
106*6fa2df46SAndroid Build Coastguard Worker int ret = sched_setaffinity(0 /* self */, sizeof(mask), &mask);
107*6fa2df46SAndroid Build Coastguard Worker if (ret) {
108*6fa2df46SAndroid Build Coastguard Worker PLOGF("Failed setting scheduling affinity");
109*6fa2df46SAndroid Build Coastguard Worker }
110*6fa2df46SAndroid Build Coastguard Worker }
111*6fa2df46SAndroid Build Coastguard Worker
IsSet() const112*6fa2df46SAndroid Build Coastguard Worker bool SchedAffinity::IsSet() const {
113*6fa2df46SAndroid Build Coastguard Worker return initialized_;
114*6fa2df46SAndroid Build Coastguard Worker }
115*6fa2df46SAndroid Build Coastguard Worker
operator =(const uint64_t mask)116*6fa2df46SAndroid Build Coastguard Worker SchedAffinity& SchedAffinity::operator=(const uint64_t mask) {
117*6fa2df46SAndroid Build Coastguard Worker if (mask == 0) {
118*6fa2df46SAndroid Build Coastguard Worker LOGF("Empty CPU affinity mask");
119*6fa2df46SAndroid Build Coastguard Worker }
120*6fa2df46SAndroid Build Coastguard Worker
121*6fa2df46SAndroid Build Coastguard Worker mask_ = mask;
122*6fa2df46SAndroid Build Coastguard Worker initialized_ = true;
123*6fa2df46SAndroid Build Coastguard Worker
124*6fa2df46SAndroid Build Coastguard Worker return *this;
125*6fa2df46SAndroid Build Coastguard Worker }
126*6fa2df46SAndroid Build Coastguard Worker
127*6fa2df46SAndroid Build Coastguard Worker /*
128*6fa2df46SAndroid Build Coastguard Worker * Create a copy of environ and return the new argv[0] size
129*6fa2df46SAndroid Build Coastguard Worker *
130*6fa2df46SAndroid Build Coastguard Worker * The stack looks pretty much as follows:
131*6fa2df46SAndroid Build Coastguard Worker *
132*6fa2df46SAndroid Build Coastguard Worker * | [...]
133*6fa2df46SAndroid Build Coastguard Worker * |
134*6fa2df46SAndroid Build Coastguard Worker * | argc
135*6fa2df46SAndroid Build Coastguard Worker * | argv[0] (pointer)
136*6fa2df46SAndroid Build Coastguard Worker * | argv[1] (pointer)
137*6fa2df46SAndroid Build Coastguard Worker * | ...
138*6fa2df46SAndroid Build Coastguard Worker * | NULL
139*6fa2df46SAndroid Build Coastguard Worker * | environ[0] (pointer)
140*6fa2df46SAndroid Build Coastguard Worker * | environ[1] (pointer)
141*6fa2df46SAndroid Build Coastguard Worker * | ...
142*6fa2df46SAndroid Build Coastguard Worker * | NULL
143*6fa2df46SAndroid Build Coastguard Worker * |
144*6fa2df46SAndroid Build Coastguard Worker * | [...]
145*6fa2df46SAndroid Build Coastguard Worker * |
146*6fa2df46SAndroid Build Coastguard Worker * | *argv[0] (string)
147*6fa2df46SAndroid Build Coastguard Worker * | *argv[1] (string)
148*6fa2df46SAndroid Build Coastguard Worker * | ...
149*6fa2df46SAndroid Build Coastguard Worker * | *environ[0] (string)
150*6fa2df46SAndroid Build Coastguard Worker * | *environ[1] (string)
151*6fa2df46SAndroid Build Coastguard Worker * | ...
152*6fa2df46SAndroid Build Coastguard Worker *
153*6fa2df46SAndroid Build Coastguard Worker * After this function is call, all the *environ[*] strings will be moved in
154*6fa2df46SAndroid Build Coastguard Worker * dynamic memory, and the old environ strings space in the stack can be used
155*6fa2df46SAndroid Build Coastguard Worker * to extend *argv[*].
156*6fa2df46SAndroid Build Coastguard Worker */
move_environ(int argc,char ** argv)157*6fa2df46SAndroid Build Coastguard Worker int move_environ(int argc, char**argv) {
158*6fa2df46SAndroid Build Coastguard Worker // Count the number of items in environ
159*6fa2df46SAndroid Build Coastguard Worker int env_last_id = -1;
160*6fa2df46SAndroid Build Coastguard Worker if (environ) {
161*6fa2df46SAndroid Build Coastguard Worker while (environ[++env_last_id])
162*6fa2df46SAndroid Build Coastguard Worker ;
163*6fa2df46SAndroid Build Coastguard Worker }
164*6fa2df46SAndroid Build Coastguard Worker
165*6fa2df46SAndroid Build Coastguard Worker unsigned int argv_strings_size;
166*6fa2df46SAndroid Build Coastguard Worker if (env_last_id > 0) {
167*6fa2df46SAndroid Build Coastguard Worker // If there is something in environ (it exists and there is something more
168*6fa2df46SAndroid Build Coastguard Worker // than the terminating NULL), size is the total size that will be usable
169*6fa2df46SAndroid Build Coastguard Worker // for argv after environ is moved. In fact, this would be the size of all
170*6fa2df46SAndroid Build Coastguard Worker // the argv strings, plus the size of all the current environ strings.
171*6fa2df46SAndroid Build Coastguard Worker // More specifically, this is:
172*6fa2df46SAndroid Build Coastguard Worker // - the address of the last element of environ,
173*6fa2df46SAndroid Build Coastguard Worker // - plus its content size, so now we have the very last byte of environ,
174*6fa2df46SAndroid Build Coastguard Worker // - subtracted the address of the first string of argv.
175*6fa2df46SAndroid Build Coastguard Worker argv_strings_size = environ[env_last_id - 1] + strlen(environ[env_last_id - 1]) - argv[0];
176*6fa2df46SAndroid Build Coastguard Worker } else {
177*6fa2df46SAndroid Build Coastguard Worker // Otherwise, this is just the size of all the argv strings.
178*6fa2df46SAndroid Build Coastguard Worker argv_strings_size = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
179*6fa2df46SAndroid Build Coastguard Worker }
180*6fa2df46SAndroid Build Coastguard Worker
181*6fa2df46SAndroid Build Coastguard Worker if (environ) {
182*6fa2df46SAndroid Build Coastguard Worker // Create a copy of environ in dynamic memory
183*6fa2df46SAndroid Build Coastguard Worker char** new_environ = static_cast<char**>(malloc(env_last_id * sizeof(char*)));
184*6fa2df46SAndroid Build Coastguard Worker
185*6fa2df46SAndroid Build Coastguard Worker // Create a copy in dynamic memory for all the environ strings
186*6fa2df46SAndroid Build Coastguard Worker unsigned int i = -1;
187*6fa2df46SAndroid Build Coastguard Worker while (environ[++i]) {
188*6fa2df46SAndroid Build Coastguard Worker new_environ[i] = strdup(environ[i]);
189*6fa2df46SAndroid Build Coastguard Worker }
190*6fa2df46SAndroid Build Coastguard Worker
191*6fa2df46SAndroid Build Coastguard Worker // Also, update the environ pointer
192*6fa2df46SAndroid Build Coastguard Worker environ = new_environ;
193*6fa2df46SAndroid Build Coastguard Worker }
194*6fa2df46SAndroid Build Coastguard Worker
195*6fa2df46SAndroid Build Coastguard Worker return argv_strings_size;
196*6fa2df46SAndroid Build Coastguard Worker }
197*6fa2df46SAndroid Build Coastguard Worker
198*6fa2df46SAndroid Build Coastguard Worker /*
199*6fa2df46SAndroid Build Coastguard Worker * Update the title of the calling process by updating argv[0] (may be
200*6fa2df46SAndroid Build Coastguard Worker * destructive for the following argv[1..])
201*6fa2df46SAndroid Build Coastguard Worker *
202*6fa2df46SAndroid Build Coastguard Worker * If the length of the new title is larger than the previously allocated
203*6fa2df46SAndroid Build Coastguard Worker * argv[0] in the stack, then this function will overwrite the next argv
204*6fa2df46SAndroid Build Coastguard Worker * strings.
205*6fa2df46SAndroid Build Coastguard Worker * If the length of the new title is larger than all the argv strings, this
206*6fa2df46SAndroid Build Coastguard Worker * function will move environ and use its reclaimed space.
207*6fa2df46SAndroid Build Coastguard Worker */
setproctitle(int argc,char ** argv,const char * title)208*6fa2df46SAndroid Build Coastguard Worker void setproctitle(int argc, char** argv, const char* title) {
209*6fa2df46SAndroid Build Coastguard Worker size_t available_size = strlen(argv[0]);
210*6fa2df46SAndroid Build Coastguard Worker size_t argv_size = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
211*6fa2df46SAndroid Build Coastguard Worker
212*6fa2df46SAndroid Build Coastguard Worker if (available_size < argv_size) {
213*6fa2df46SAndroid Build Coastguard Worker available_size = move_environ(argc, argv);
214*6fa2df46SAndroid Build Coastguard Worker }
215*6fa2df46SAndroid Build Coastguard Worker
216*6fa2df46SAndroid Build Coastguard Worker memset(argv[0], 0, available_size);
217*6fa2df46SAndroid Build Coastguard Worker snprintf(argv[0], available_size - 1, "%s", title);
218*6fa2df46SAndroid Build Coastguard Worker }
219*6fa2df46SAndroid Build Coastguard Worker
220*6fa2df46SAndroid Build Coastguard Worker } // namespace dittosuite
221