diff options
author | Konstantin Pereiaslov <perk11@perk11.info> | 2023-10-01 22:53:47 -0500 |
---|---|---|
committer | Konstantin Pereiaslov <perk11@perk11.info> | 2023-10-01 23:14:10 -0500 |
commit | a983cb2490eb2d794ed5f9b997620dda27527b1e (patch) | |
tree | e46ceb633a2c8d4aa40926039e760fb1e4ade685 | |
parent | 77b26a4cdf54f71ffa26220df2f8671af100ed9f (diff) |
First version of pausing/resuming recursively
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | process_handling.c | 78 | ||||
-rw-r--r-- | process_handling.h | 18 |
3 files changed, 97 insertions, 5 deletions
@@ -58,7 +58,7 @@ int handle_interruption() { "Since command was previously paused, we will try to resume it now to be able to handle the interruption before exiting\n" ); } - resume_command(pid); + resume_command_recursively(pid); } //Wait for the child process to complete return wait_for_pid_to_exit_synchronously(pid); @@ -93,7 +93,7 @@ long long pause_or_resume_command_depending_on_user_activity( printf("Lack of user activity detected. "); //intentionally no new line here, resume_command will print the rest of the message. } - resume_command(pid); + resume_command_recursively(pid); command_paused = 0; } } else { @@ -105,7 +105,7 @@ long long pause_or_resume_command_depending_on_user_activity( if (verbose) { fprintf(stderr, "Idle time: %lums.\n", user_idle_time_ms); } - pause_command(pid); + pause_command_recursively(pid); if (debug) fprintf(stderr,"Command paused\n"); command_paused = 1; command_was_paused_this_iteration = 1; diff --git a/process_handling.c b/process_handling.c index 9f1d414..a3ab85d 100644 --- a/process_handling.c +++ b/process_handling.c @@ -5,6 +5,7 @@ #include <string.h> #include <unistd.h> #include <sys/wait.h> +#include <dirent.h> #include "process_handling.h" #include "output_settings.h" @@ -41,6 +42,52 @@ pid_t run_shell_command(const char *shell_command_to_run) { void handle_kill_error(char *signal_name, pid_t pid, int kill_errno) { fprintf(stderr, "Failed to send %s signal to PID %i: %s\n", signal_name, pid, strerror(kill_errno)); } +typedef struct ProcessNode { + int process_id; + struct ProcessNode* next_node; +} ProcessNode; + + +ProcessNode* get_child_processes_linked_list(int parent_process_id) { + DIR *proc_directory = opendir("/proc/"); + if (proc_directory == NULL) { + fprintf_error("Could not open /proc directory"); + exit(1); + } + + ProcessNode *head_node = NULL, **tail_node = &head_node; + struct dirent *directory_entry; + char stat_file_path[64]; + int process_id, found_parent_process_id; + FILE *stat_file; + + while ((directory_entry = readdir(proc_directory)) != NULL) { + if (sscanf(directory_entry->d_name, "%d", &process_id) != 1) continue; + + snprintf(stat_file_path, sizeof(stat_file_path), "/proc/%d/stat", process_id); + stat_file = fopen(stat_file_path, "r"); + if (stat_file == NULL) continue; + + fscanf(stat_file, "%*d %*s %*c %d", &found_parent_process_id); + fclose(stat_file); + + if (found_parent_process_id != parent_process_id) continue; + + ProcessNode *new_node = (ProcessNode *)malloc(sizeof(ProcessNode)); + if (new_node == NULL) { + perror("Memory allocation failed"); + exit(1); + } + + new_node->process_id = process_id; + new_node->next_node = NULL; + *tail_node = new_node; + tail_node = &(new_node->next_node); + } + + closedir(proc_directory); + return head_node; +} void send_signal_to_pid(pid_t pid, int signal, char *signal_name) { if (debug) { @@ -57,7 +104,7 @@ void send_signal_to_pid(pid_t pid, int signal, char *signal_name) { void pause_command(pid_t pid) { if (!quiet) { - printf("User activity is detected, pausing PID %i\n", pid); + printf("Pausing PID %i\n", pid); } switch (pause_method) { case PAUSE_METHOD_SIGTSTP: @@ -72,6 +119,21 @@ void pause_command(pid_t pid) { } } +void pause_command_recursively(pid_t pid) +{ + pause_command(pid); + ProcessNode* child_process_ids = get_child_processes_linked_list(pid); + ProcessNode* current_node = child_process_ids; + ProcessNode* previous_node; + + while (current_node) { + pause_command(current_node->process_id); + previous_node = current_node; + current_node = current_node->next_node; + free(previous_node); + } +} + void resume_command(pid_t pid) { if (!quiet) { printf("Resuming PID %i\n", pid); @@ -79,6 +141,20 @@ void resume_command(pid_t pid) { send_signal_to_pid(pid, SIGCONT, "SIGCONT"); } +void resume_command_recursively(pid_t pid) +{ + resume_command(pid); + ProcessNode* child_process_ids = get_child_processes_linked_list(pid); + ProcessNode* current_node = child_process_ids; + ProcessNode* previous_node; + + while (current_node) { + resume_command(current_node->process_id); + previous_node = current_node; + current_node = current_node->next_node; + free(previous_node); + } +} int wait_for_pid_to_exit_synchronously(int pid) { int status; diff --git a/process_handling.h b/process_handling.h index 2153797..c3cdb13 100644 --- a/process_handling.h +++ b/process_handling.h @@ -9,13 +9,21 @@ */ void send_signal_to_pid(pid_t pid, int signal, char *signal_name); /** - * Pauses a specified process by sending the SIGTSTP signal. + * Pauses a specified process using pause method specified in pause_method variable * * @param pid The process ID of the target process. */ void pause_command(pid_t pid); /** + * Pauses a specified process and all child processes + * + * @param pid The process ID of the target process. + */ +void pause_command_recursively(pid_t pid); + + +/** * Resumes a specified process by sending the SIGCONT signal. * * @param pid The process ID of the target process. @@ -23,6 +31,14 @@ void pause_command(pid_t pid); void resume_command(pid_t pid); /** + * Resumes a specified process and all child processes by sending SIGCONT signal to each process. + * + * @param pid The process ID of the target process. + */ +void resume_command_recursively(pid_t pid); + + +/** * Executes a shell command in a new process and returns the process ID of the child process. * On failure will exit. * |