# HG changeset patch # User Paul Boddie # Date 1706225555 -3600 # Node ID 2733e5770ee97dedd059eed94e90ea3dd4dd2360 # Parent c18fa9fe009e19eacce98073ae00ba49e7f61a06 Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available. diff -r c18fa9fe009e -r 2733e5770ee9 fsaccess/fsaccess.c --- a/fsaccess/fsaccess.c Thu Jan 25 00:05:40 2024 +0100 +++ b/fsaccess/fsaccess.c Fri Jan 26 00:32:35 2024 +0100 @@ -56,8 +56,9 @@ file Send a file to a program\n\ jobs Show initiated programs\n\ pipe Connect a running program to a new program\n\ - run Run a program from the filesystem\n\ - wait Wait for a program to finish\n\ + run Run a program from the filesystem and wait for it to finish\n\ + spawn Run a program in the background\n\ + wait Wait for a spawned program to finish\n\ "; /* Operations exposed by the program. */ @@ -72,6 +73,7 @@ {"rm", remove_non_dirs}, {"rmdir", remove_dirs}, {"run", run_program}, + {"spawn", spawn_program}, {"script", run_script}, {"stat", stat_objects}, {"wait", wait_program}, diff -r c18fa9fe009e -r 2733e5770ee9 fsaccess/op_run.c --- a/fsaccess/op_run.c Thu Jan 25 00:05:40 2024 +0100 +++ b/fsaccess/op_run.c Fri Jan 26 00:32:35 2024 +0100 @@ -52,6 +52,45 @@ +/* Find the given program in the job list. */ + +static int _find_program(process_t *process) +{ + int job_number; + + for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++) + { + if (processes[job_number] == process) + return job_number; + } + + return -1; +} + +/* Remove the details of a program from the job list. */ + +static void _remove_program(int job_number) +{ + readers[job_number] = NULL; + processes[job_number] = NULL; + + free(programs[job_number]); + programs[job_number] = NULL; +} + +/* Show the details of a running program. */ + +static void _show_program(int job_number) +{ + /* Employ the Unix convention of a "+" for the default job to be restored upon + the appropriate command. */ + + printf("[%d]%s %s%s\n", job_number, job_number == next_job ? "+" : " ", + programs[job_number], readers[job_number] != NULL ? " [!]" : ""); +} + + + /* Show output from a program. */ static void _show_output(file_t *reader) @@ -63,11 +102,26 @@ fwrite(buffer, sizeof(char), nread, stdout); } +/* Show the exit status of a program. */ + +static void _show_status(notifiable_t *notifiable) +{ + printf("Completed with"); + + if (notifiable->notifications & NOTIFY_TASK_ERROR) + printf(" error"); + + if (notifiable->notifications & NOTIFY_TASK_SIGNAL) + printf(" signal %ld", notifiable->values.sig); + + printf(" value %ld\n", notifiable->values.val); +} + /* Wait for a program to finish, showing its output. */ static int _wait_program(file_t *reader, process_t *process) { - notifier_t *notifier = client_notifier_local(); + notifier_t *notifier = client_notifier_task(); notifiable_t *notifiable; int exitcode; long err; @@ -81,7 +135,6 @@ if (err) { printf("Could not subscribe to pipe notifications: %s\n", l4sys_errtostr(err)); - client_notifier_close(notifier); return -1; } } @@ -92,7 +145,6 @@ { printf("Could not subscribe to process notifications: %s\n", l4sys_errtostr(err)); client_unsubscribe(reader, notifier); - client_notifier_close(notifier); return -1; } @@ -110,7 +162,6 @@ client_unsubscribe(reader, notifier); notify_unsubscribe(process_notifiable(process), notifier); - client_notifier_close(notifier); return -1; } @@ -123,19 +174,22 @@ if (process_terminated(notifiable)) { - if (reader != NULL) + if ((reader != NULL) && ((process_t *) notifiable->base == process)) _show_output(reader); - printf("Completed with"); + _show_status(notifiable); - if (notifiable->notifications & NOTIFY_TASK_ERROR) - printf(" error"); + /* If explicitly waiting for this process, remove it from the job list and + return. Otherwise, just remove it from the job list and keep waiting + for the indicated process. */ - if (notifiable->notifications & NOTIFY_TASK_SIGNAL) - printf(" signal %ld", notifiable->values.sig); - - printf(" value %ld\n", notifiable->values.val); - break; + if ((process_t *) notifiable->base == process) + { + _remove_program(next_job); + break; + } + else + _remove_program(_find_program((process_t *) notifiable->base)); } } @@ -148,7 +202,6 @@ /* Close the process and pipe. */ - client_notifier_close(notifier); process_free(process); if (reader != NULL) @@ -203,10 +256,13 @@ if (next_job >= NUMBER_OF_JOBS) next_job = 0; - /* Wait for the process to complete if no more job slots are available. */ + /* Return an error if no more job slots are available. */ if (next_job == last_job) - return _wait_program(output_reader, process); + { + printf("No job slots available.\n"); + return -1; + } } readers[next_job] = output_reader; @@ -253,7 +309,10 @@ if (argc < 1) return -1; - job_number = atoi(argv[0]); + if (!strcmp(argv[0], "+")) + job_number = next_job; + else + job_number = atoi(argv[0]); if (readers[job_number] == NULL) { @@ -269,14 +328,23 @@ client_close(readers[job_number]); readers[job_number] = NULL; + /* Subscribe to signals from the process. */ + + notify_subscribe(process_notifiable(processes[job_number]), NOTIFY_TASK_ALL, client_notifier_task()); + return exitcode; } -/* Run the given program. */ +/* Run the given program and wait for it to finish. */ int run_program(int argc, char *argv[]) { - return _run_program(argc, argv, NULL); + int exitcode = _run_program(argc, argv, NULL); + + if (exitcode) + return exitcode; + + return _wait_program(readers[next_job], processes[next_job]); } /* Show initiated programs. */ @@ -290,24 +358,37 @@ for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++) { if (processes[job_number] != NULL) - printf("[%d] %s%s\n", job_number, programs[job_number], - readers[job_number] != NULL ? " [!]" : ""); + _show_program(job_number); } return 0; } -/* Wait for the indicated program to finish, showing its output. */ +/* Run the given program but do not wait for it to finish, instead allowing the + program to produce output and potentially block until an operation to wait + for its completion is performed. */ + +int spawn_program(int argc, char *argv[]) +{ + int exitcode = _run_program(argc, argv, NULL); + + if (!exitcode) + _show_program(next_job); + + return exitcode; +} + +/* Wait for the indicated program (or the last program to be spawned) to finish, + showing its output. */ int wait_program(int argc, char *argv[]) { int job_number; - int exitcode; if (argc < 1) - return -1; - - job_number = atoi(argv[0]); + job_number = next_job; + else + job_number = atoi(argv[0]); if (processes[job_number] == NULL) { @@ -315,15 +396,7 @@ return -1; } - exitcode = _wait_program(readers[job_number], processes[job_number]); - - readers[job_number] = NULL; - processes[job_number] = NULL; - - free(programs[job_number]); - programs[job_number] = NULL; - - return exitcode; + return _wait_program(readers[job_number], processes[job_number]); } /* vim: tabstop=2 expandtab shiftwidth=2 diff -r c18fa9fe009e -r 2733e5770ee9 fsaccess/ops.h --- a/fsaccess/ops.h Thu Jan 25 00:05:40 2024 +0100 +++ b/fsaccess/ops.h Fri Jan 26 00:32:35 2024 +0100 @@ -53,6 +53,7 @@ int remove_dirs(int argc, char *argv[]); int remove_non_dirs(int argc, char *argv[]); int run_program(int argc, char *argv[]); +int spawn_program(int argc, char *argv[]); int run_script(int argc, char *argv[]); int show_programs(int argc, char *argv[]); int stat_objects(int argc, char *argv[]);