1.1 --- a/fsaccess/op_run.c Thu Jan 25 00:05:40 2024 +0100
1.2 +++ b/fsaccess/op_run.c Fri Jan 26 00:32:35 2024 +0100
1.3 @@ -52,6 +52,45 @@
1.4
1.5
1.6
1.7 +/* Find the given program in the job list. */
1.8 +
1.9 +static int _find_program(process_t *process)
1.10 +{
1.11 + int job_number;
1.12 +
1.13 + for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++)
1.14 + {
1.15 + if (processes[job_number] == process)
1.16 + return job_number;
1.17 + }
1.18 +
1.19 + return -1;
1.20 +}
1.21 +
1.22 +/* Remove the details of a program from the job list. */
1.23 +
1.24 +static void _remove_program(int job_number)
1.25 +{
1.26 + readers[job_number] = NULL;
1.27 + processes[job_number] = NULL;
1.28 +
1.29 + free(programs[job_number]);
1.30 + programs[job_number] = NULL;
1.31 +}
1.32 +
1.33 +/* Show the details of a running program. */
1.34 +
1.35 +static void _show_program(int job_number)
1.36 +{
1.37 + /* Employ the Unix convention of a "+" for the default job to be restored upon
1.38 + the appropriate command. */
1.39 +
1.40 + printf("[%d]%s %s%s\n", job_number, job_number == next_job ? "+" : " ",
1.41 + programs[job_number], readers[job_number] != NULL ? " [!]" : "");
1.42 +}
1.43 +
1.44 +
1.45 +
1.46 /* Show output from a program. */
1.47
1.48 static void _show_output(file_t *reader)
1.49 @@ -63,11 +102,26 @@
1.50 fwrite(buffer, sizeof(char), nread, stdout);
1.51 }
1.52
1.53 +/* Show the exit status of a program. */
1.54 +
1.55 +static void _show_status(notifiable_t *notifiable)
1.56 +{
1.57 + printf("Completed with");
1.58 +
1.59 + if (notifiable->notifications & NOTIFY_TASK_ERROR)
1.60 + printf(" error");
1.61 +
1.62 + if (notifiable->notifications & NOTIFY_TASK_SIGNAL)
1.63 + printf(" signal %ld", notifiable->values.sig);
1.64 +
1.65 + printf(" value %ld\n", notifiable->values.val);
1.66 +}
1.67 +
1.68 /* Wait for a program to finish, showing its output. */
1.69
1.70 static int _wait_program(file_t *reader, process_t *process)
1.71 {
1.72 - notifier_t *notifier = client_notifier_local();
1.73 + notifier_t *notifier = client_notifier_task();
1.74 notifiable_t *notifiable;
1.75 int exitcode;
1.76 long err;
1.77 @@ -81,7 +135,6 @@
1.78 if (err)
1.79 {
1.80 printf("Could not subscribe to pipe notifications: %s\n", l4sys_errtostr(err));
1.81 - client_notifier_close(notifier);
1.82 return -1;
1.83 }
1.84 }
1.85 @@ -92,7 +145,6 @@
1.86 {
1.87 printf("Could not subscribe to process notifications: %s\n", l4sys_errtostr(err));
1.88 client_unsubscribe(reader, notifier);
1.89 - client_notifier_close(notifier);
1.90 return -1;
1.91 }
1.92
1.93 @@ -110,7 +162,6 @@
1.94 client_unsubscribe(reader, notifier);
1.95
1.96 notify_unsubscribe(process_notifiable(process), notifier);
1.97 - client_notifier_close(notifier);
1.98 return -1;
1.99 }
1.100
1.101 @@ -123,19 +174,22 @@
1.102
1.103 if (process_terminated(notifiable))
1.104 {
1.105 - if (reader != NULL)
1.106 + if ((reader != NULL) && ((process_t *) notifiable->base == process))
1.107 _show_output(reader);
1.108
1.109 - printf("Completed with");
1.110 + _show_status(notifiable);
1.111
1.112 - if (notifiable->notifications & NOTIFY_TASK_ERROR)
1.113 - printf(" error");
1.114 + /* If explicitly waiting for this process, remove it from the job list and
1.115 + return. Otherwise, just remove it from the job list and keep waiting
1.116 + for the indicated process. */
1.117
1.118 - if (notifiable->notifications & NOTIFY_TASK_SIGNAL)
1.119 - printf(" signal %ld", notifiable->values.sig);
1.120 -
1.121 - printf(" value %ld\n", notifiable->values.val);
1.122 - break;
1.123 + if ((process_t *) notifiable->base == process)
1.124 + {
1.125 + _remove_program(next_job);
1.126 + break;
1.127 + }
1.128 + else
1.129 + _remove_program(_find_program((process_t *) notifiable->base));
1.130 }
1.131 }
1.132
1.133 @@ -148,7 +202,6 @@
1.134
1.135 /* Close the process and pipe. */
1.136
1.137 - client_notifier_close(notifier);
1.138 process_free(process);
1.139
1.140 if (reader != NULL)
1.141 @@ -203,10 +256,13 @@
1.142 if (next_job >= NUMBER_OF_JOBS)
1.143 next_job = 0;
1.144
1.145 - /* Wait for the process to complete if no more job slots are available. */
1.146 + /* Return an error if no more job slots are available. */
1.147
1.148 if (next_job == last_job)
1.149 - return _wait_program(output_reader, process);
1.150 + {
1.151 + printf("No job slots available.\n");
1.152 + return -1;
1.153 + }
1.154 }
1.155
1.156 readers[next_job] = output_reader;
1.157 @@ -253,7 +309,10 @@
1.158 if (argc < 1)
1.159 return -1;
1.160
1.161 - job_number = atoi(argv[0]);
1.162 + if (!strcmp(argv[0], "+"))
1.163 + job_number = next_job;
1.164 + else
1.165 + job_number = atoi(argv[0]);
1.166
1.167 if (readers[job_number] == NULL)
1.168 {
1.169 @@ -269,14 +328,23 @@
1.170 client_close(readers[job_number]);
1.171 readers[job_number] = NULL;
1.172
1.173 + /* Subscribe to signals from the process. */
1.174 +
1.175 + notify_subscribe(process_notifiable(processes[job_number]), NOTIFY_TASK_ALL, client_notifier_task());
1.176 +
1.177 return exitcode;
1.178 }
1.179
1.180 -/* Run the given program. */
1.181 +/* Run the given program and wait for it to finish. */
1.182
1.183 int run_program(int argc, char *argv[])
1.184 {
1.185 - return _run_program(argc, argv, NULL);
1.186 + int exitcode = _run_program(argc, argv, NULL);
1.187 +
1.188 + if (exitcode)
1.189 + return exitcode;
1.190 +
1.191 + return _wait_program(readers[next_job], processes[next_job]);
1.192 }
1.193
1.194 /* Show initiated programs. */
1.195 @@ -290,24 +358,37 @@
1.196 for (job_number = 0; job_number < NUMBER_OF_JOBS; job_number++)
1.197 {
1.198 if (processes[job_number] != NULL)
1.199 - printf("[%d] %s%s\n", job_number, programs[job_number],
1.200 - readers[job_number] != NULL ? " [!]" : "");
1.201 + _show_program(job_number);
1.202 }
1.203
1.204 return 0;
1.205 }
1.206
1.207 -/* Wait for the indicated program to finish, showing its output. */
1.208 +/* Run the given program but do not wait for it to finish, instead allowing the
1.209 + program to produce output and potentially block until an operation to wait
1.210 + for its completion is performed. */
1.211 +
1.212 +int spawn_program(int argc, char *argv[])
1.213 +{
1.214 + int exitcode = _run_program(argc, argv, NULL);
1.215 +
1.216 + if (!exitcode)
1.217 + _show_program(next_job);
1.218 +
1.219 + return exitcode;
1.220 +}
1.221 +
1.222 +/* Wait for the indicated program (or the last program to be spawned) to finish,
1.223 + showing its output. */
1.224
1.225 int wait_program(int argc, char *argv[])
1.226 {
1.227 int job_number;
1.228 - int exitcode;
1.229
1.230 if (argc < 1)
1.231 - return -1;
1.232 -
1.233 - job_number = atoi(argv[0]);
1.234 + job_number = next_job;
1.235 + else
1.236 + job_number = atoi(argv[0]);
1.237
1.238 if (processes[job_number] == NULL)
1.239 {
1.240 @@ -315,15 +396,7 @@
1.241 return -1;
1.242 }
1.243
1.244 - exitcode = _wait_program(readers[job_number], processes[job_number]);
1.245 -
1.246 - readers[job_number] = NULL;
1.247 - processes[job_number] = NULL;
1.248 -
1.249 - free(programs[job_number]);
1.250 - programs[job_number] = NULL;
1.251 -
1.252 - return exitcode;
1.253 + return _wait_program(readers[job_number], processes[job_number]);
1.254 }
1.255
1.256 /* vim: tabstop=2 expandtab shiftwidth=2