// Copyright (C) 2023 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include namespace dittosuite { bool SchedAttr::IsSet() const { return initialized_; } void SchedAttr::Set() const { if (!initialized_) { LOGF("Setting uninitialized scheduling attributes"); } LOGD("Setting scheduling policy [" + std::to_string(sched_attr_.sched_policy) + "] to thread: " + std::to_string(syscall_.GetTid())); int ret = syscall_.SchedSetattr(0 /* self */, sched_attr_, 0 /* still not implemented */); if (ret) { PLOGF("Failed setting scheduling attributes \n" + to_string(sched_attr_) + "\n"); } } SchedAttr& SchedAttr::operator=(const dittosuiteproto::SchedAttr& pb) { typedef dittosuiteproto::SchedAttr::AttributesCase SchedType; sched_attr_.size = sizeof(sched_attr_); sched_attr_.sched_flags = pb.flags(); switch (pb.attributes_case()) { case SchedType::kOther: switch (pb.other().policy()) { case dittosuiteproto::SchedAttr::SchedOther::OTHER: sched_attr_.sched_policy = SchedPolicy::SchedNormal; break; case dittosuiteproto::SchedAttr::SchedOther::BATCH: sched_attr_.sched_policy = SchedPolicy::SchedBatch; break; } sched_attr_.sched_nice = pb.other().nice(); break; case SchedType::kRt: switch (pb.rt().policy()) { case dittosuiteproto::SchedAttr::SchedRt::FIFO: sched_attr_.sched_policy = SchedPolicy::SchedFifo; break; case dittosuiteproto::SchedAttr::SchedRt::RR: sched_attr_.sched_policy = SchedPolicy::SchedRr; break; } if (pb.rt().priority() < 1 || pb.rt().priority() > 99) { LOGF("Scheduling priority should be in the range [1, 99]"); } sched_attr_.sched_priority = pb.rt().priority(); break; case SchedType::kDeadline: sched_attr_.sched_policy = SchedPolicy::SchedDeadline; sched_attr_.sched_runtime = pb.deadline().runtime(); sched_attr_.sched_deadline = pb.deadline().deadline(); sched_attr_.sched_period = pb.deadline().period(); break; case SchedType::ATTRIBUTES_NOT_SET: LOGF("Missing scheduling attribute"); break; } initialized_ = true; return *this; } void SchedAffinity::Set() const { if (!initialized_) { LOGF("Setting uninitialized affinity attributes"); } LOGD("Setting affinity mask [" + std::to_string(mask_) + "] to thread: " + std::to_string(syscall_.GetTid())); cpu_set_t mask; CPU_ZERO(&mask); uint64_t tmp_bitset = mask_; for (unsigned int i=0; i>= 1; } int ret = sched_setaffinity(0 /* self */, sizeof(mask), &mask); if (ret) { PLOGF("Failed setting scheduling affinity"); } } bool SchedAffinity::IsSet() const { return initialized_; } SchedAffinity& SchedAffinity::operator=(const uint64_t mask) { if (mask == 0) { LOGF("Empty CPU affinity mask"); } mask_ = mask; initialized_ = true; return *this; } /* * Create a copy of environ and return the new argv[0] size * * The stack looks pretty much as follows: * * | [...] * | * | argc * | argv[0] (pointer) * | argv[1] (pointer) * | ... * | NULL * | environ[0] (pointer) * | environ[1] (pointer) * | ... * | NULL * | * | [...] * | * | *argv[0] (string) * | *argv[1] (string) * | ... * | *environ[0] (string) * | *environ[1] (string) * | ... * * After this function is call, all the *environ[*] strings will be moved in * dynamic memory, and the old environ strings space in the stack can be used * to extend *argv[*]. */ int move_environ(int argc, char**argv) { // Count the number of items in environ int env_last_id = -1; if (environ) { while (environ[++env_last_id]) ; } unsigned int argv_strings_size; if (env_last_id > 0) { // If there is something in environ (it exists and there is something more // than the terminating NULL), size is the total size that will be usable // for argv after environ is moved. In fact, this would be the size of all // the argv strings, plus the size of all the current environ strings. // More specifically, this is: // - the address of the last element of environ, // - plus its content size, so now we have the very last byte of environ, // - subtracted the address of the first string of argv. argv_strings_size = environ[env_last_id - 1] + strlen(environ[env_last_id - 1]) - argv[0]; } else { // Otherwise, this is just the size of all the argv strings. argv_strings_size = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; } if (environ) { // Create a copy of environ in dynamic memory char** new_environ = static_cast(malloc(env_last_id * sizeof(char*))); // Create a copy in dynamic memory for all the environ strings unsigned int i = -1; while (environ[++i]) { new_environ[i] = strdup(environ[i]); } // Also, update the environ pointer environ = new_environ; } return argv_strings_size; } /* * Update the title of the calling process by updating argv[0] (may be * destructive for the following argv[1..]) * * If the length of the new title is larger than the previously allocated * argv[0] in the stack, then this function will overwrite the next argv * strings. * If the length of the new title is larger than all the argv strings, this * function will move environ and use its reclaimed space. */ void setproctitle(int argc, char** argv, const char* title) { size_t available_size = strlen(argv[0]); size_t argv_size = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; if (available_size < argv_size) { available_size = move_environ(argc, argv); } memset(argv[0], 0, available_size); snprintf(argv[0], available_size - 1, "%s", title); } } // namespace dittosuite