1.1 --- a/conf/dstest_exec.cfg Mon Dec 11 19:17:25 2023 +0100 1.2 +++ b/conf/dstest_exec.cfg Mon Dec 11 19:23:39 2023 +0100 1.3 @@ -59,6 +59,7 @@ 1.4 l:startv({ 1.5 caps = { 1.6 fsserver = ext2server_paulb, 1.7 + pipeserver = pipe_server, 1.8 prserver = process_server, 1.9 }, 1.10 log = { "client", "g" },
2.1 --- a/libexec/include/exec/process_creating.h Mon Dec 11 19:17:25 2023 +0100 2.2 +++ b/libexec/include/exec/process_creating.h Mon Dec 11 19:23:39 2023 +0100 2.3 @@ -86,16 +86,19 @@ 2.4 2.5 long start_region_mapper(l4_cap_idx_t pager); 2.6 2.7 - long start_program(l4_cap_idx_t monitor, int argc, const char *argv[]); 2.8 + long start_program(l4_cap_idx_t monitor, int argc, const char *argv[], 2.9 + l4_cap_idx_t writer); 2.10 2.11 - long _start(int argc, const char *argv[], l4_cap_idx_t process); 2.12 + long _start(int argc, const char *argv[], l4_cap_idx_t writer, 2.13 + l4_cap_idx_t process); 2.14 2.15 public: 2.16 explicit ProcessCreating(const char *rm_filename, file_t *rm_file); 2.17 2.18 virtual long init_process_monitor(l4_cap_idx_t *monitor); 2.19 2.20 - virtual long start(int argc, const char *argv[], l4_cap_idx_t process); 2.21 + virtual long start(int argc, const char *argv[], l4_cap_idx_t writer, 2.22 + l4_cap_idx_t process); 2.23 }; 2.24 2.25 /* vim: tabstop=2 expandtab shiftwidth=2
3.1 --- a/libexec/include/exec/process_creator_context_resource.h Mon Dec 11 19:17:25 2023 +0100 3.2 +++ b/libexec/include/exec/process_creator_context_resource.h Mon Dec 11 19:23:39 2023 +0100 3.3 @@ -56,7 +56,7 @@ 3.4 3.5 /* Process creator context interface methods. */ 3.6 3.7 - virtual long start(int argc, l4_cap_idx_t *process); 3.8 + virtual long start(int argc, l4_cap_idx_t writer, l4_cap_idx_t *process); 3.9 3.10 /* Pager/dataspace methods. */ 3.11
4.1 --- a/libexec/include/exec/process_creator_resource.h Mon Dec 11 19:17:25 2023 +0100 4.2 +++ b/libexec/include/exec/process_creator_resource.h Mon Dec 11 19:23:39 2023 +0100 4.3 @@ -51,7 +51,8 @@ 4.4 4.5 virtual long init_process(l4_cap_idx_t *process); 4.6 4.7 - virtual long start(int argc, const char *argv[], l4_cap_idx_t process); 4.8 + virtual long start(int argc, const char *argv[], l4_cap_idx_t writer, 4.9 + l4_cap_idx_t process); 4.10 4.11 /* Opener interface methods. */ 4.12
5.1 --- a/libexec/lib/src/process_creating.cc Mon Dec 11 19:17:25 2023 +0100 5.2 +++ b/libexec/lib/src/process_creating.cc Mon Dec 11 19:23:39 2023 +0100 5.3 @@ -283,7 +283,8 @@ 5.4 /* Configure a thread for a program, populate its stack, and start the 5.5 thread. */ 5.6 5.7 -long ProcessCreating::start_program(l4_cap_idx_t monitor, int argc, const char *argv[]) 5.8 +long ProcessCreating::start_program(l4_cap_idx_t monitor, int argc, 5.9 + const char *argv[], l4_cap_idx_t writer) 5.10 { 5.11 /* NOTE: Environment vector is currently not defined. */ 5.12 5.13 @@ -316,10 +317,15 @@ 5.14 l4_cap_idx_t fsserver_cap = _process.allocate_cap(); 5.15 l4_cap_idx_t fsserver = l4re_env_get_cap(ENV_FILESYSTEM_SERVER_NAME); 5.16 5.17 + /* Also reserve a capability for the writer. */ 5.18 + 5.19 + l4_cap_idx_t writer_cap = _process.allocate_cap(); 5.20 + 5.21 /* Define the capabilities to be mapped for the filesystem. */ 5.22 5.23 struct ipc_mapped_cap program_mapped_caps[] = { 5.24 {fsserver_cap, fsserver, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}, 5.25 + {writer_cap, writer, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}, 5.26 {0, L4_INVALID_CAP, 0, 0}, 5.27 }; 5.28 5.29 @@ -336,6 +342,7 @@ 5.30 5.31 l4re_env_cap_entry_t program_init_caps[] = { 5.32 l4re_env_cap_entry_t(ENV_FILESYSTEM_SERVER_NAME, fsserver_cap, L4_CAP_FPAGE_RWS), 5.33 + l4re_env_cap_entry_t(ENV_OUTPUT_STREAM_NAME, writer_cap, L4_CAP_FPAGE_W), 5.34 l4re_env_cap_entry_t() 5.35 }; 5.36 5.37 @@ -361,10 +368,12 @@ 5.38 } 5.39 5.40 /* Start a new process for the payload indicated by the first of the given 5.41 - program arguments, returning a reference to the process monitor as an object 5.42 - for interacting with the process. */ 5.43 + program arguments, employing the given writer pipe, and returning a 5.44 + reference to the process monitor as an object for interacting with the 5.45 + process. */ 5.46 5.47 -long ProcessCreating::_start(int argc, const char *argv[], l4_cap_idx_t process) 5.48 +long ProcessCreating::_start(int argc, const char *argv[], l4_cap_idx_t writer, 5.49 + l4_cap_idx_t process) 5.50 { 5.51 /* Open the program file, handling any error conditions. If successfully 5.52 opened, it will be closed when the process terminates. */ 5.53 @@ -410,7 +419,7 @@ 5.54 if (err) 5.55 return err; 5.56 5.57 - err = start_program(process, argc, argv); 5.58 + err = start_program(process, argc, argv, writer); 5.59 if (err) 5.60 return err; 5.61 5.62 @@ -435,11 +444,12 @@ 5.63 5.64 /* Start the given program, notifying the process monitor upon any error. */ 5.65 5.66 -long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t process) 5.67 +long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t writer, 5.68 + l4_cap_idx_t process) 5.69 { 5.70 std::lock_guard<std::mutex> guard(_lock); 5.71 5.72 - long err = _start(argc, argv, process); 5.73 + long err = _start(argc, argv, writer, process); 5.74 5.75 /* Communicate the error using the signal value. */ 5.76
6.1 --- a/libexec/lib/src/process_creator_context_resource.cc Mon Dec 11 19:17:25 2023 +0100 6.2 +++ b/libexec/lib/src/process_creator_context_resource.cc Mon Dec 11 19:23:39 2023 +0100 6.3 @@ -50,7 +50,8 @@ 6.4 6.5 /* ProcessCreatorContext interface methods. */ 6.6 6.7 -long ProcessCreatorContextResource::start(int argc, l4_cap_idx_t *process) 6.8 +long ProcessCreatorContextResource::start(int argc, l4_cap_idx_t writer, 6.9 + l4_cap_idx_t *process) 6.10 { 6.11 /* Obtain the arguments by reading from the shared memory. */ 6.12 6.13 @@ -85,7 +86,7 @@ 6.14 reply, so a notification is sent via the process monitor instead by the 6.15 process creator. */ 6.16 6.17 - _creator->start(argc, argv, *process); 6.18 + _creator->start(argc, argv, writer, *process); 6.19 6.20 return IPC_MESSAGE_SENT; 6.21 }
7.1 --- a/libexec/lib/src/process_creator_resource.cc Mon Dec 11 19:17:25 2023 +0100 7.2 +++ b/libexec/lib/src/process_creator_resource.cc Mon Dec 11 19:23:39 2023 +0100 7.3 @@ -55,9 +55,10 @@ 7.4 7.5 /* Start the new process, obtaining a reference to it. */ 7.6 7.7 -long ProcessCreatorResource::start(int argc, const char *argv[], l4_cap_idx_t process) 7.8 +long ProcessCreatorResource::start(int argc, const char *argv[], 7.9 + l4_cap_idx_t writer, l4_cap_idx_t process) 7.10 { 7.11 - return _creating.start(argc, argv, process); 7.12 + return _creating.start(argc, argv, writer, process); 7.13 } 7.14 7.15
8.1 --- a/libfsclient/include/fsclient/client.h Mon Dec 11 19:17:25 2023 +0100 8.2 +++ b/libfsclient/include/fsclient/client.h Mon Dec 11 19:23:39 2023 +0100 8.3 @@ -34,6 +34,10 @@ 8.4 l4_cap_idx_t client_open_for_user(user_t user); 8.5 l4_cap_idx_t client_open_for_user_using(user_t user, l4_cap_idx_t server); 8.6 8.7 +/* Stream access operations. */ 8.8 + 8.9 +file_t *client_get_stream(const char *name, flags_t flags); 8.10 + 8.11 /* Opening and closing operations. */ 8.12 8.13 void client_close(file_t *file);
9.1 --- a/libfsclient/include/fsclient/process.h Mon Dec 11 19:17:25 2023 +0100 9.2 +++ b/libfsclient/include/fsclient/process.h Mon Dec 11 19:23:39 2023 +0100 9.3 @@ -53,8 +53,8 @@ 9.4 long process_error(process_t *process); 9.5 void process_free(process_t *process); 9.6 void process_init(process_t *process); 9.7 -long process_spawn(int argc, const char *argv[], process_t **process); 9.8 -long process_start(process_t *process, int argc, const char *argv[]); 9.9 +long process_spawn(int argc, const char *argv[], file_t *writer, process_t **process); 9.10 +long process_start(process_t *process, int argc, const char *argv[], file_t *writer); 9.11 long process_wait(process_t *process, notify_flags_t *flags, notify_values_t *values); 9.12 9.13 /* Notification support. */
10.1 --- a/libfsclient/lib/src/client.cc Mon Dec 11 19:17:25 2023 +0100 10.2 +++ b/libfsclient/lib/src/client.cc Mon Dec 11 19:23:39 2023 +0100 10.3 @@ -261,6 +261,37 @@ 10.4 10.5 10.6 10.7 +/* Obtain a stream from the environment. */ 10.8 + 10.9 +file_t *client_get_stream(const char *name, flags_t flags) 10.10 +{ 10.11 + file_t *stream = (file_t *) malloc(sizeof(file_t)); 10.12 + 10.13 + file_init(stream); 10.14 + stream->flags = flags; 10.15 + stream->ref = l4re_env_get_cap(name); 10.16 + 10.17 + /* Enforce blocking if necessary. 10.18 + NOTE: Ignoring any event subscription error. */ 10.19 + 10.20 + if (!(flags & O_NONBLOCK)) 10.21 + { 10.22 + notify_flags_t nflags = 0; 10.23 + 10.24 + if ((flags & O_WRONLY) || (flags & O_RDWR)) 10.25 + nflags |= NOTIFY_SPACE_AVAILABLE; 10.26 + 10.27 + if ((flags & O_RDONLY) || (flags & O_RDWR)) 10.28 + nflags |= NOTIFY_CONTENT_AVAILABLE; 10.29 + 10.30 + client_set_blocking(stream, nflags | NOTIFY_PEER_CLOSED); 10.31 + } 10.32 + 10.33 + return stream; 10.34 +} 10.35 + 10.36 + 10.37 + 10.38 /* Open a filesystem object. */ 10.39 10.40 file_t *client_open(const char *name, flags_t flags)
11.1 --- a/libfsclient/lib/src/process.cc Mon Dec 11 19:17:25 2023 +0100 11.2 +++ b/libfsclient/lib/src/process.cc Mon Dec 11 19:23:39 2023 +0100 11.3 @@ -111,22 +111,24 @@ 11.4 11.5 /* A convenience function for creating and starting a process. */ 11.6 11.7 -long process_spawn(int argc, const char *argv[], process_t **process) 11.8 +long process_spawn(int argc, const char *argv[], file_t *writer, 11.9 + process_t **process) 11.10 { 11.11 *process = process_new(); 11.12 11.13 /* Start the process with the given arguments. */ 11.14 11.15 if (*process != NULL) 11.16 - return process_start(*process, argc, argv); 11.17 + return process_start(*process, argc, argv, writer); 11.18 else 11.19 return -L4_ENOMEM; 11.20 } 11.21 11.22 /* Start a process using the given arguments. 11.23 - NOTE: This does not yet obtain input/output pipes. */ 11.24 + NOTE: This does not yet employ a pipe for the process's input stream. */ 11.25 11.26 -long process_start(process_t *process, int argc, const char *argv[]) 11.27 +long process_start(process_t *process, int argc, const char *argv[], 11.28 + file_t *writer) 11.29 { 11.30 l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME); 11.31 11.32 @@ -157,7 +159,8 @@ 11.33 11.34 /* Start the process, obtaining a reference to it. */ 11.35 11.36 - err = creator.start(argc, &process->ref); 11.37 + err = creator.start(argc, writer != NULL ? writer->ref : (l4_cap_idx_t) L4_INVALID_CAP, 11.38 + &process->ref); 11.39 11.40 /* Initialise the notifiable section of the structure. */ 11.41
12.1 --- a/libsystypes/idl/process_creator_context.idl Mon Dec 11 19:17:25 2023 +0100 12.2 +++ b/libsystypes/idl/process_creator_context.idl Mon Dec 11 19:23:39 2023 +0100 12.3 @@ -4,7 +4,10 @@ 12.4 interface ProcessCreatorContext 12.5 { 12.6 /* Start a process, using the given argument count to refer to the process 12.7 - arguments supplied via the dataspace, including the program itself. */ 12.8 + arguments supplied via the dataspace, including the program itself. 12.9 12.10 - [opcode(30)] void start(in int argc, out cap process); 12.11 + A writer pipe capability is to be provided for the process's output, and 12.12 + the process capability is returned. */ 12.13 + 12.14 + [opcode(30)] void start(in int argc, in cap writer, out cap process); 12.15 };
13.1 --- a/libsystypes/include/systypes/env.h Mon Dec 11 19:17:25 2023 +0100 13.2 +++ b/libsystypes/include/systypes/env.h Mon Dec 11 19:23:39 2023 +0100 13.3 @@ -26,6 +26,7 @@ 13.4 #define ENV_FILESYSTEM_SERVER_NAME "fsserver" 13.5 #define ENV_PIPE_SERVER_NAME "pipeserver" 13.6 #define ENV_PROCESS_SERVER_NAME "prserver" 13.7 +#define ENV_OUTPUT_STREAM_NAME "stdout" 13.8 13.9 EXTERN_C_END 13.10
14.1 --- a/test_files/programs/dstest_exec_payload.c Mon Dec 11 19:17:25 2023 +0100 14.2 +++ b/test_files/programs/dstest_exec_payload.c Mon Dec 11 19:23:39 2023 +0100 14.3 @@ -20,6 +20,13 @@ 14.4 */ 14.5 14.6 #include <stdio.h> 14.7 +#include <string.h> 14.8 + 14.9 +/* NOTE: For inclusion in the C library. */ 14.10 + 14.11 +#include <fsclient/client.h> 14.12 +#include <systypes/env.h> 14.13 +#include <systypes/fcntl.h> 14.14 14.15 14.16 14.17 @@ -27,10 +34,24 @@ 14.18 { 14.19 int i; 14.20 14.21 + /* NOTE: For inclusion in the C library. */ 14.22 + 14.23 + file_t *output = client_get_stream(ENV_OUTPUT_STREAM_NAME, O_WRONLY); 14.24 + 14.25 + /* Write the arguments to the output stream. */ 14.26 + 14.27 + char buffer[32]; 14.28 + 14.29 for (i = 0; i < argc; i++) 14.30 - printf("Arg #%d: %s\n", i, argv[i]); 14.31 + { 14.32 + sprintf(buffer, "Arg #%d: ", i); 14.33 + client_write(output, buffer, strlen(buffer)); 14.34 + client_write(output, argv[i], strlen(argv[i])); 14.35 + client_write(output, "\n", 1); 14.36 + } 14.37 14.38 - printf("Terminating.\n"); 14.39 + client_write(output, "Terminating.\n", 13); 14.40 + client_flush(output); 14.41 return 0; 14.42 } 14.43
15.1 --- a/tests/dstest_exec.cc Mon Dec 11 19:17:25 2023 +0100 15.2 +++ b/tests/dstest_exec.cc Mon Dec 11 19:23:39 2023 +0100 15.3 @@ -21,20 +21,54 @@ 15.4 15.5 #include <l4/sys/err.h> 15.6 15.7 +#include <fsclient/client.h> 15.8 #include <fsclient/process.h> 15.9 +#include <systypes/fcntl.h> 15.10 #include <systypes/format.h> 15.11 15.12 #include <stdio.h> 15.13 15.14 15.15 15.16 +/* Transfer size for communication. */ 15.17 + 15.18 +const offset_t TO_TRANSFER = 1024; 15.19 + 15.20 + 15.21 + 15.22 +/* Test process initiation and interaction. */ 15.23 + 15.24 static long test_process(int argc, const char *argv[]) 15.25 { 15.26 process_t *process; 15.27 + file_t *reader, *writer; 15.28 + long err; 15.29 + 15.30 + /* Obtain the common notifier. */ 15.31 + 15.32 + notifier_t *notifier = client_notifier_task(); 15.33 + 15.34 + /* Create a pipe for process output. */ 15.35 + 15.36 + err = client_pipe(&reader, &writer, O_NONBLOCK); 15.37 + 15.38 + if (err) 15.39 + { 15.40 + printf("Could not obtain pipe: %s\n", l4sys_errtostr(err)); 15.41 + return err; 15.42 + } 15.43 + 15.44 + err = client_subscribe(reader, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier); 15.45 + 15.46 + if (err) 15.47 + { 15.48 + printf("Could not subscribe to pipe notifications: %s\n", l4sys_errtostr(err)); 15.49 + return err; 15.50 + } 15.51 15.52 /* Start the process. */ 15.53 15.54 - long err = process_spawn(argc, argv, &process); 15.55 + err = process_spawn(argc, argv, writer, &process); 15.56 15.57 if (err) 15.58 { 15.59 @@ -44,21 +78,60 @@ 15.60 15.61 printf("Finished program initiation.\n"); 15.62 15.63 - /* Wait for a signal from the process. */ 15.64 + /* Wait for a signal from the process or input from the process. */ 15.65 15.66 - notify_flags_t flags; 15.67 - notify_values_t values; 15.68 - 15.69 - err = process_wait(process, &flags, &values); 15.70 + err = notify_subscribe(process_notifiable(process), NOTIFY_TASK_ALL, notifier); 15.71 15.72 if (err) 15.73 { 15.74 - printf("Could not wait for process: %s\n", l4sys_errtostr(err)); 15.75 + printf("Could not subscribe to task notifications: %s\n", l4sys_errtostr(err)); 15.76 return err; 15.77 } 15.78 15.79 + notifiable_t *notifiable; 15.80 + 15.81 + while (1) 15.82 + { 15.83 + err = notify_wait_many(¬ifiable, notifier); 15.84 + 15.85 + if (err) 15.86 + { 15.87 + printf("Could not wait for process: %s\n", l4sys_errtostr(err)); 15.88 + return err; 15.89 + } 15.90 + 15.91 + /* Handle any signal. */ 15.92 + 15.93 + if (notifiable == process_notifiable(process)) 15.94 + break; 15.95 + 15.96 + /* Handle any input. */ 15.97 + 15.98 + else if (notifiable == file_notifiable(reader)) 15.99 + { 15.100 + char buffer[TO_TRANSFER]; 15.101 + offset_t nread = client_read(reader, buffer, TO_TRANSFER); 15.102 + 15.103 + while (nread) 15.104 + { 15.105 + fwrite(buffer, sizeof(char), nread, stdout); 15.106 + nread = client_read(reader, buffer, TO_TRANSFER); 15.107 + } 15.108 + } 15.109 + } 15.110 + 15.111 + notify_flags_t flags = process_notifications(process); 15.112 + notify_values_t values = process_notification_values(process); 15.113 + 15.114 printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val); 15.115 - return L4_EOK; 15.116 + 15.117 + err = process_error(process); 15.118 + 15.119 + client_close(reader); 15.120 + process_free(process); 15.121 + client_notifier_close(notifier); 15.122 + 15.123 + return err; 15.124 } 15.125 15.126 15.127 @@ -73,10 +146,6 @@ 15.128 return 1; 15.129 } 15.130 15.131 - /* Obtain the common notifier. */ 15.132 - 15.133 - notifier_t *notifier = notify_get_task(); 15.134 - 15.135 /* Start a process for a non-existent program. */ 15.136 15.137 printf("Start non-existent program...\n"); 15.138 @@ -102,8 +171,6 @@ 15.139 if (err) 15.140 return 1; 15.141 15.142 - notify_close(notifier); 15.143 - 15.144 printf("End of test.\n"); 15.145 return 0; 15.146 }
16.1 --- a/tests/dstest_exec_many.cc Mon Dec 11 19:17:25 2023 +0100 16.2 +++ b/tests/dstest_exec_many.cc Mon Dec 11 19:23:39 2023 +0100 16.3 @@ -49,7 +49,7 @@ 16.4 16.5 process_t *process; 16.6 16.7 - err = process_spawn(argc - 2, (const char **) argv + 2, &process); 16.8 + err = process_spawn(argc - 2, (const char **) argv + 2, NULL, &process); 16.9 16.10 if (err) 16.11 {