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) {
ss << key << "[" << value << "], ";
}
std::string after = ss.str();
after = after.substr(0,after.size() - 2);
return after;
std::string after_str = ss.str();
if(after_str.size() >= 2)
after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
}
std::string AppInfo::getAfterKeys() const
@ -137,9 +138,10 @@ std::string AppInfo::getAfterKeys() const
for(auto &[key,value]: after) {
ss << key << ", ";
}
std::string after = ss.str();
after = after.substr(0,after.size() - 2);
return after;
std::string after_str = ss.str();
if(after_str.size() >= 2)
after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
}
std::string AppInfo::getStringRunMode() const
@ -343,6 +345,7 @@ bool AppInfo::checkValidity()
void AppInfo::updateNextTimeToRun()
{
next_time_to_run_parse_failed = false;
bool got_run_every = false;
bool got_run_at = false;
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;
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()) {
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;
}
@ -781,9 +785,10 @@ std::string AppInfo::AppData::getAfterString() const
for(auto &[key,value]: after) {
ss << key << "[" << value << "], ";
}
std::string after = ss.str();
after = after.substr(0,after.size() - 2);
return after;
std::string after_str = ss.str();
if(after_str.size() >= 2)
after_str = after_str.substr(0, after_str.size() - 2);
return after_str;
}
std::string AppInfo::AppData::getAfterKeys() const
@ -792,7 +797,8 @@ std::string AppInfo::AppData::getAfterKeys() const
for(auto &[key,value]: after) {
ss << key << ", ";
}
std::string after = ss.str();
after = after.substr(0,after.size() - 2);
return after;
std::string after_str = ss.str();
if(after_str.size() >= 2)
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()
{
finished = false;
initial_list_size = job_list.size();
seperateScheduledTasks();
log_file << "Main Thread: Job list: " << job_list.size() <<
" Scheduled list: " << scheduled_list.size() << std::endl;
last_poll_time = std::chrono::system_clock::now();
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();
for(int i=active_thread_count.load(); i < threads ;i++) {
// Dispatch jobs from job_list to worker threads
while(active_thread_count.load() < threads) {
std::shared_ptr<AppInfo> ptr;
int val = 0;
size_t remaining_size = 0;
{
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;
}
ptr = job_list.front();
job_list.erase(job_list.begin());
remaining_size = job_list.size();
val = index_count++;
}
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::osyncstream os(log_file.rdbuf());
size_t list_size = 0;
{
std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
if(job_list.size() == 0) {
os << std::vformat("Thread[{}] called while the job list was empty: ", std::make_format_args(val))
<< std::endl;
return;
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);
}
ptr = this->job_list[0];
job_list.erase(job_list.begin());
list_size = job_list.size();
}
} guard{active_thread_count, worker->done};
std::osyncstream os(log_file.rdbuf());
std::string module_name = ptr->getModuleName();
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();
while(!ptr->isParentDependencyCleared(os))
{
@ -220,25 +231,26 @@ void ExecutionManager::run()
state_change.notify_all();
os << std::vformat("Thread[{}] finished: ", std::make_format_args(val))
<< 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);
if(job_list.empty()) {
log_file << "Main Thread: Job list is empty, waiting for finish." << std::endl;
if(job_list.empty() && scheduled_list.empty() && active_thread_count.load() == 0) {
log_file << "Main Thread: All jobs finished." << std::endl;
break;
}
}
if (active_thread_count.load() >= threads) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
for(auto i: thread_list) {
if(i->joinable())
i->join();
for(auto &worker: thread_list) {
if(worker->thread.joinable())
worker->thread.join();
}
thread_list.clear();
finished = true;
}
@ -249,16 +261,16 @@ bool ExecutionManager::checkScheduledTaskIsReady(std::chrono::system_clock::time
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)->getRunOnStart()) && ((*task)->getScheduled())) {
log_file << "Main Thread: Job[" + (*task)->getModuleName() +
"] is scheduled for execution." << std::endl;
scheduled_list.push_back(std::move(*task));
scheduled_list.push_back(*task);
task = job_list.erase(task);
if(task == job_list.end())
break;
task--;
} else {
++task;
}
}
}
@ -266,23 +278,20 @@ void ExecutionManager::seperateScheduledTasks()
void ExecutionManager::pollScheduledTasks()
{
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;
last_poll_time = current_poll_time;
{
std::lock_guard<std::mutex> lock_get(this->job_list_mutex);
log_file << "Main Thread: Polling before: Job list: " << job_list.size() <<
" Scheduled list: " << scheduled_list.size() << std::endl;
for(auto task = scheduled_list.begin(); task != scheduled_list.end(); task++) {
for(auto task = scheduled_list.begin(); task != scheduled_list.end(); ) {
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);
if(task == scheduled_list.end())
break;
task--;
} else {
++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
{
struct WorkerThread {
std::thread thread;
std::atomic<bool> done{false};
};
bool finished = false;
int threads;
int index_count = 0;
int initial_list_size = 0;
long long int log_file_max_size = 0;
std::string log_dir;
std::mutex job_list_mutex;
std::atomic<int> state_change = 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>> scheduled_list;
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 << "Json file : " << options.json_file_path << 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;
}
@ -189,7 +189,7 @@ Example startup_apps.json:
{
"name": "LS 2",
"app_name": "/bin/ls",
"app_arpgs": ["-lh"],
"app_args": ["-lh"],
"run_mode": "script",
"create_log": true,
"after": [{"module": "LS 0", "state": "exited"}],
@ -246,7 +246,7 @@ void parseArgs(int c, char *v[]) {
int i = contains(arg_list, "--json", "-j");
if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
if(j >= arg_list.size()) {
printHelp();
exit(-1);
}
@ -257,7 +257,7 @@ void parseArgs(int c, char *v[]) {
i = contains(arg_list, "--log_dir", "-ld");
if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
if(j >= arg_list.size()) {
printHelp();
exit(-1);
}
@ -268,7 +268,7 @@ void parseArgs(int c, char *v[]) {
i = contains(arg_list, "--threads", "-t");
if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
if(j >= arg_list.size()) {
printHelp();
exit(-1);
}
@ -278,29 +278,24 @@ void parseArgs(int c, char *v[]) {
}
i = contains(arg_list, "--test", "-T");
if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
printHelp();
exit(-1);
}
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;
contains_any_known_arg = true;
}
i = contains(arg_list, "--help", "-h");
if(i >= 0) {
int j = i + 1;
if(j > arg_list.size()) {
printHelp();
exit(-1);
}
if(arg_list[j] == "json") {
if(j < arg_list.size() && arg_list[j] == "json") {
printJsonHelp();
exit(0);
}
else {
printHelp();
exit(-1);
exit(0);
}
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;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
tokens.push_back(token);
token = string_strip(s.substr(0, pos));
if(!token.empty())
tokens.push_back(token);
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;
}
@ -436,7 +434,7 @@ std::optional<int> checkAppList(std::deque<AppInfo::AppData> &copy_list, std::ve
}
}
if(!found) {
out << "Depenedency not found" << std::endl;
out << "Dependency not found" << std::endl;
}
}
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) {
bool run_validity = i->checkValidity();
i->printInfo(out);
for(auto &[j, state]: i->getParents()) {
if(state == AppInfo::State::exited && j->getRunMode() == AppInfo::RunMode::daemon) {
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;
}
}
if(!run_validity) {
out << "[ERR]: " << i->getModuleName() <<
" incorrect format for scheduled run. Please see help page." << std::endl;
all_valid = false;
} else if((i->getScheduled()) && (!i->getRunOnStart())) {
const auto* zone = std::chrono::current_zone();
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 {
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;
}