xref: /aosp_15_r20/test/dittosuite/src/multithreading_utils.cpp (revision 6fa2df46f119dce7527f5beb2814eca0e6f886ac)
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