Fixes for flaws found by gemini 3.8 on 21/10/26.

This commit is contained in:
unrealdragon 2026-10-21 21:59:19 +05:30
commit bc5760eee9
4 changed files with 105 additions and 84 deletions

View file

@ -126,9 +126,10 @@ std::string AppInfo::getAfterString() const
for(auto &[key,value]: after) { for(auto &[key,value]: after) {
ss << key << "[" << value << "], "; ss << key << "[" << value << "], ";
} }
std::string after = ss.str(); std::string after_str = ss.str();
after = after.substr(0,after.size() - 2); if(after_str.size() >= 2)
return after; after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
} }
std::string AppInfo::getAfterKeys() const std::string AppInfo::getAfterKeys() const
@ -137,9 +138,10 @@ std::string AppInfo::getAfterKeys() const
for(auto &[key,value]: after) { for(auto &[key,value]: after) {
ss << key << ", "; ss << key << ", ";
} }
std::string after = ss.str(); std::string after_str = ss.str();
after = after.substr(0,after.size() - 2); if(after_str.size() >= 2)
return after; after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
} }
std::string AppInfo::getStringRunMode() const std::string AppInfo::getStringRunMode() const
@ -343,6 +345,7 @@ bool AppInfo::checkValidity()
void AppInfo::updateNextTimeToRun() void AppInfo::updateNextTimeToRun()
{ {
next_time_to_run_parse_failed = false;
bool got_run_every = false; bool got_run_every = false;
bool got_run_at = false; bool got_run_at = false;
std::chrono::system_clock::time_point every_time_point, at_time_point; std::chrono::system_clock::time_point every_time_point, at_time_point;
@ -513,9 +516,10 @@ std::optional<std::chrono::system_clock::time_point> AppInfo::parseAtTimeFormat(
} }
auto local_next = std::chrono::local_days{ymd} + time_of_day; auto local_next = std::chrono::local_days{ymd} + time_of_day;
if (local_next <= local_now) { if (local_next <= local_now) {
std::chrono::year_month_day ymd_next = (current_ymd.year() / current_ymd.month() / target_day) + std::chrono::months(1); auto next_ym = current_ymd.year() / current_ymd.month() + std::chrono::months(1);
std::chrono::year_month_day ymd_next = next_ym / target_day;
if (!ymd_next.ok()) { if (!ymd_next.ok()) {
ymd_next = ymd_next.year() / ymd_next.month() / std::chrono::last; ymd_next = next_ym / std::chrono::last;
} }
local_next = std::chrono::local_days{ymd_next} + time_of_day; local_next = std::chrono::local_days{ymd_next} + time_of_day;
} }
@ -781,9 +785,10 @@ std::string AppInfo::AppData::getAfterString() const
for(auto &[key,value]: after) { for(auto &[key,value]: after) {
ss << key << "[" << value << "], "; ss << key << "[" << value << "], ";
} }
std::string after = ss.str(); std::string after_str = ss.str();
after = after.substr(0,after.size() - 2); if(after_str.size() >= 2)
return after; after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
} }
std::string AppInfo::AppData::getAfterKeys() const std::string AppInfo::AppData::getAfterKeys() const
@ -792,7 +797,8 @@ std::string AppInfo::AppData::getAfterKeys() const
for(auto &[key,value]: after) { for(auto &[key,value]: after) {
ss << key << ", "; ss << key << ", ";
} }
std::string after = ss.str(); std::string after_str = ss.str();
after = after.substr(0,after.size() - 2); if(after_str.size() >= 2)
return after; after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
} }

View file

@ -58,45 +58,56 @@ void ExecutionManager::printActiveJobs()
void ExecutionManager::run() void ExecutionManager::run()
{ {
finished = false; finished = false;
initial_list_size = job_list.size();
seperateScheduledTasks(); seperateScheduledTasks();
log_file << "Main Thread: Job list: " << job_list.size() << log_file << "Main Thread: Job list: " << job_list.size() <<
" Scheduled list: " << scheduled_list.size() << std::endl; " Scheduled list: " << scheduled_list.size() << std::endl;
last_poll_time = std::chrono::system_clock::now(); last_poll_time = std::chrono::system_clock::now();
while(true) { while(true) {
// Clean up completed worker threads
for(auto it = thread_list.begin(); it != thread_list.end(); ) {
if((*it)->done.load()) {
if((*it)->thread.joinable())
(*it)->thread.join();
it = thread_list.erase(it);
} else {
++it;
}
}
pollScheduledTasks(); pollScheduledTasks();
for(int i=active_thread_count.load(); i < threads ;i++) {
int val = 0; // Dispatch jobs from job_list to worker threads
{ while(active_thread_count.load() < threads) {
std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
val = index_count++;
if(job_list.empty()) {
log_file << "Main Thread: Job list is empty, waiting for finish." << std::endl;
break;
}
if(val > (initial_list_size - 1)) {
break;
}
}
active_thread_count.fetch_add(1);
std::shared_ptr<std::thread> thread = std::make_shared<std::thread>([this, val](){
std::shared_ptr<AppInfo> ptr; std::shared_ptr<AppInfo> ptr;
std::osyncstream os(log_file.rdbuf()); int val = 0;
size_t list_size = 0; size_t remaining_size = 0;
{ {
std::lock_guard<std::mutex> lock_get(this->job_list_mutex); std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
if(job_list.size() == 0) { if(job_list.empty()) {
os << std::vformat("Thread[{}] called while the job list was empty: ", std::make_format_args(val)) break;
<< std::endl;
return;
} }
ptr = this->job_list[0]; ptr = job_list.front();
job_list.erase(job_list.begin()); job_list.erase(job_list.begin());
list_size = job_list.size(); remaining_size = job_list.size();
val = index_count++;
} }
active_thread_count.fetch_add(1);
auto worker = std::make_shared<WorkerThread>();
worker->thread = std::thread([this, val, ptr, remaining_size, worker](){
struct ThreadGuard {
std::atomic<int>& count;
std::atomic<bool>& done;
~ThreadGuard() {
count.fetch_sub(1);
done.store(true);
}
} guard{active_thread_count, worker->done};
std::osyncstream os(log_file.rdbuf());
std::string module_name = ptr->getModuleName(); std::string module_name = ptr->getModuleName();
os << std::vformat("Thread[{}] running: ", std::make_format_args(val)) os << std::vformat("Thread[{}] running: ", std::make_format_args(val))
<< module_name << " current list size: " << list_size << std::endl; << module_name << " current list size: " << remaining_size << std::endl;
int old = state_change.load(); int old = state_change.load();
while(!ptr->isParentDependencyCleared(os)) while(!ptr->isParentDependencyCleared(os))
{ {
@ -220,25 +231,26 @@ void ExecutionManager::run()
state_change.notify_all(); state_change.notify_all();
os << std::vformat("Thread[{}] finished: ", std::make_format_args(val)) os << std::vformat("Thread[{}] finished: ", std::make_format_args(val))
<< module_name << std::endl; << module_name << std::endl;
active_thread_count.fetch_sub(1);
}); });
thread_list.push_back(thread); thread_list.push_back(worker);
} }
// Check if all work is done (no active jobs, no pending jobs, no scheduled tasks)
{ {
std::lock_guard<std::mutex> lock_get(this->job_list_mutex); std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
if(job_list.empty()) { if(job_list.empty() && scheduled_list.empty() && active_thread_count.load() == 0) {
log_file << "Main Thread: Job list is empty, waiting for finish." << std::endl; log_file << "Main Thread: All jobs finished." << std::endl;
break; break;
} }
} }
if (active_thread_count.load() >= threads) { std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
for(auto &worker: thread_list) {
if(worker->thread.joinable())
worker->thread.join();
} }
for(auto i: thread_list) { thread_list.clear();
if(i->joinable())
i->join();
}
finished = true; finished = true;
} }
@ -249,16 +261,16 @@ bool ExecutionManager::checkScheduledTaskIsReady(std::chrono::system_clock::time
void ExecutionManager::seperateScheduledTasks() void ExecutionManager::seperateScheduledTasks()
{ {
for(auto task = job_list.begin(); task != job_list.end(); task++) { std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
for(auto task = job_list.begin(); task != job_list.end(); ) {
// If task is not running on start and task is scheduled. // If task is not running on start and task is scheduled.
if(!((*task)->getRunOnStart()) && ((*task)->getScheduled())) { if(!((*task)->getRunOnStart()) && ((*task)->getScheduled())) {
log_file << "Main Thread: Job[" + (*task)->getModuleName() + log_file << "Main Thread: Job[" + (*task)->getModuleName() +
"] is scheduled for execution." << std::endl; "] is scheduled for execution." << std::endl;
scheduled_list.push_back(std::move(*task)); scheduled_list.push_back(*task);
task = job_list.erase(task); task = job_list.erase(task);
if(task == job_list.end()) } else {
break; ++task;
task--;
} }
} }
} }
@ -266,23 +278,20 @@ void ExecutionManager::seperateScheduledTasks()
void ExecutionManager::pollScheduledTasks() void ExecutionManager::pollScheduledTasks()
{ {
auto current_poll_time = std::chrono::system_clock::now(); auto current_poll_time = std::chrono::system_clock::now();
if(std::chrono::duration_cast<std::chrono::seconds>(current_poll_time - last_poll_time).count() <= 1) if(std::chrono::duration_cast<std::chrono::seconds>(current_poll_time - last_poll_time).count() < polling_interval)
return; return;
last_poll_time = current_poll_time; last_poll_time = current_poll_time;
{ {
std::lock_guard<std::mutex> lock_get(this->job_list_mutex); std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
log_file << "Main Thread: Polling before: Job list: " << job_list.size() << for(auto task = scheduled_list.begin(); task != scheduled_list.end(); ) {
" Scheduled list: " << scheduled_list.size() << std::endl;
for(auto task = scheduled_list.begin(); task != scheduled_list.end(); task++) {
if(checkScheduledTaskIsReady((*task)->getNextTimeToRun())) { if(checkScheduledTaskIsReady((*task)->getNextTimeToRun())) {
job_list.push_back(std::move(*task)); log_file << "Main Thread: Job[" + (*task)->getModuleName() +
"] scheduled time arrived, adding to execution queue." << std::endl;
job_list.push_back(*task);
task = scheduled_list.erase(task); task = scheduled_list.erase(task);
if(task == scheduled_list.end()) } else {
break; ++task;
task--;
} }
} }
log_file << "Main Thread: Polling after: Job list: " << job_list.size() <<
" Scheduled list: " << scheduled_list.size() << std::endl;
} }
} }

View file

@ -10,16 +10,19 @@
class ExecutionManager class ExecutionManager
{ {
struct WorkerThread {
std::thread thread;
std::atomic<bool> done{false};
};
bool finished = false; bool finished = false;
int threads; int threads;
int index_count = 0; int index_count = 0;
int initial_list_size = 0;
long long int log_file_max_size = 0; long long int log_file_max_size = 0;
std::string log_dir; std::string log_dir;
std::mutex job_list_mutex; std::mutex job_list_mutex;
std::atomic<int> state_change = 0; std::atomic<int> state_change = 0;
std::atomic<int> active_thread_count = 0; std::atomic<int> active_thread_count = 0;
std::vector<std::shared_ptr<std::thread>> thread_list; std::vector<std::shared_ptr<WorkerThread>> thread_list;
std::vector<std::shared_ptr<AppInfo>> job_list; std::vector<std::shared_ptr<AppInfo>> job_list;
std::vector<std::shared_ptr<AppInfo>> scheduled_list; std::vector<std::shared_ptr<AppInfo>> scheduled_list;
std::chrono::system_clock::time_point last_poll_time; std::chrono::system_clock::time_point last_poll_time;

View file

@ -109,7 +109,7 @@ void printDefaults() {
std::cout << "StartUpRunner Default Values: " << std::endl; std::cout << "StartUpRunner Default Values: " << std::endl;
std::cout << "Json file : " << options.json_file_path << std::endl; std::cout << "Json file : " << options.json_file_path << std::endl;
std::cout << "Logs directory : " << options.log_directory << std::endl; std::cout << "Logs directory : " << options.log_directory << std::endl;
std::cout << "Log file max size: " << options.threads << std::endl; std::cout << "Log file max size: " << options.log_file_max_size << std::endl;
std::cout << "Threads : " << options.threads << std::endl; std::cout << "Threads : " << options.threads << std::endl;
} }
@ -189,7 +189,7 @@ Example startup_apps.json:
{ {
"name": "LS 2", "name": "LS 2",
"app_name": "/bin/ls", "app_name": "/bin/ls",
"app_arpgs": ["-lh"], "app_args": ["-lh"],
"run_mode": "script", "run_mode": "script",
"create_log": true, "create_log": true,
"after": [{"module": "LS 0", "state": "exited"}], "after": [{"module": "LS 0", "state": "exited"}],
@ -246,7 +246,7 @@ void parseArgs(int c, char *v[]) {
int i = contains(arg_list, "--json", "-j"); int i = contains(arg_list, "--json", "-j");
if(i >= 0) { if(i >= 0) {
int j = i + 1; int j = i + 1;
if(j > arg_list.size()) { if(j >= arg_list.size()) {
printHelp(); printHelp();
exit(-1); exit(-1);
} }
@ -257,7 +257,7 @@ void parseArgs(int c, char *v[]) {
i = contains(arg_list, "--log_dir", "-ld"); i = contains(arg_list, "--log_dir", "-ld");
if(i >= 0) { if(i >= 0) {
int j = i + 1; int j = i + 1;
if(j > arg_list.size()) { if(j >= arg_list.size()) {
printHelp(); printHelp();
exit(-1); exit(-1);
} }
@ -268,7 +268,7 @@ void parseArgs(int c, char *v[]) {
i = contains(arg_list, "--threads", "-t"); i = contains(arg_list, "--threads", "-t");
if(i >= 0) { if(i >= 0) {
int j = i + 1; int j = i + 1;
if(j > arg_list.size()) { if(j >= arg_list.size()) {
printHelp(); printHelp();
exit(-1); exit(-1);
} }
@ -278,29 +278,24 @@ void parseArgs(int c, char *v[]) {
} }
i = contains(arg_list, "--test", "-T"); i = contains(arg_list, "--test", "-T");
if(i >= 0) { if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
printHelp();
exit(-1);
}
options.check_for_errors = true; options.check_for_errors = true;
int j = i + 1;
if(j < arg_list.size() && arg_list[j].rfind("-", 0) != 0) {
options.json_file_path = arg_list[j];
}
std::cout << "Testing json file." << std::endl; std::cout << "Testing json file." << std::endl;
contains_any_known_arg = true; contains_any_known_arg = true;
} }
i = contains(arg_list, "--help", "-h"); i = contains(arg_list, "--help", "-h");
if(i >= 0) { if(i >= 0) {
int j = i + 1; int j = i + 1;
if(j > arg_list.size()) { if(j < arg_list.size() && arg_list[j] == "json") {
printHelp();
exit(-1);
}
if(arg_list[j] == "json") {
printJsonHelp(); printJsonHelp();
exit(0); exit(0);
} }
else { else {
printHelp(); printHelp();
exit(-1); exit(0);
} }
contains_any_known_arg = true; contains_any_known_arg = true;
} }
@ -339,11 +334,14 @@ std::vector<std::string> string_split(std::string s, const std::string& delimite
size_t pos = 0; size_t pos = 0;
std::string token; std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) { while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos); token = string_strip(s.substr(0, pos));
if(!token.empty())
tokens.push_back(token); tokens.push_back(token);
s.erase(0, pos + delimiter.length()); s.erase(0, pos + delimiter.length());
} }
tokens.push_back(string_strip(s)); std::string last = string_strip(s);
if(!last.empty())
tokens.push_back(last);
return tokens; return tokens;
} }
@ -436,7 +434,7 @@ std::optional<int> checkAppList(std::deque<AppInfo::AppData> &copy_list, std::ve
} }
} }
if(!found) { if(!found) {
out << "Depenedency not found" << std::endl; out << "Dependency not found" << std::endl;
} }
} }
after_list.push_back(std::move(app_info)); after_list.push_back(std::move(app_info));
@ -463,19 +461,21 @@ std::optional<int> checkAppList(std::deque<AppInfo::AppData> &copy_list, std::ve
} }
} }
} }
bool all_valid = true;
for(auto &i: after_list) { for(auto &i: after_list) {
bool run_validity = i->checkValidity(); bool run_validity = i->checkValidity();
i->printInfo(out); i->printInfo(out);
for(auto &[j, state]: i->getParents()) { for(auto &[j, state]: i->getParents()) {
if(state == AppInfo::State::exited && j->getRunMode() == AppInfo::RunMode::daemon) { if(state == AppInfo::State::exited && j->getRunMode() == AppInfo::RunMode::daemon) {
out << "[WARN]: " << i->getModuleName() << out << "[WARN]: " << i->getModuleName() <<
" is waiting for a daemon: " << j->getModuleName() << " to start exeuction." << " is waiting for a daemon: " << j->getModuleName() << " to start execution." <<
std::endl; std::endl;
} }
} }
if(!run_validity) { if(!run_validity) {
out << "[ERR]: " << i->getModuleName() << out << "[ERR]: " << i->getModuleName() <<
" incorrect format for scheduled run. Please see help page." << std::endl; " incorrect format for scheduled run. Please see help page." << std::endl;
all_valid = false;
} else if((i->getScheduled()) && (!i->getRunOnStart())) { } else if((i->getScheduled()) && (!i->getRunOnStart())) {
const auto* zone = std::chrono::current_zone(); const auto* zone = std::chrono::current_zone();
auto local_now = zone->to_local(i->getNextTimeToRun()); auto local_now = zone->to_local(i->getNextTimeToRun());
@ -491,9 +491,12 @@ std::optional<int> checkAppList(std::deque<AppInfo::AppData> &copy_list, std::ve
} }
else { else {
out << "Module: " << i->getModuleName() << out << "Module: " << i->getModuleName() <<
" is to be launched on init." << i->getScheduled() << i->getRunOnStart() << run_validity << std::endl; " is to be launched on init." << std::endl;
} }
} }
if(!all_valid) {
return std::nullopt;
}
return 0; return 0;
} }