# HG changeset patch # User Paul Boddie # Date 1702319019 -3600 # Node ID 7c8ba245fbba6014b6edf85b051ff85c862cdaf1 # Parent 5283243773745a6c3556b0bd3a413b30f119322d Added tentative support for standard output via a pipe to a creating process. diff -r 528324377374 -r 7c8ba245fbba conf/dstest_exec.cfg --- a/conf/dstest_exec.cfg Mon Dec 11 19:17:25 2023 +0100 +++ b/conf/dstest_exec.cfg Mon Dec 11 19:23:39 2023 +0100 @@ -59,6 +59,7 @@ l:startv({ caps = { fsserver = ext2server_paulb, + pipeserver = pipe_server, prserver = process_server, }, log = { "client", "g" }, diff -r 528324377374 -r 7c8ba245fbba libexec/include/exec/process_creating.h --- a/libexec/include/exec/process_creating.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/include/exec/process_creating.h Mon Dec 11 19:23:39 2023 +0100 @@ -86,16 +86,19 @@ long start_region_mapper(l4_cap_idx_t pager); - long start_program(l4_cap_idx_t monitor, int argc, const char *argv[]); + long start_program(l4_cap_idx_t monitor, int argc, const char *argv[], + l4_cap_idx_t writer); - long _start(int argc, const char *argv[], l4_cap_idx_t process); + long _start(int argc, const char *argv[], l4_cap_idx_t writer, + l4_cap_idx_t process); public: explicit ProcessCreating(const char *rm_filename, file_t *rm_file); virtual long init_process_monitor(l4_cap_idx_t *monitor); - virtual long start(int argc, const char *argv[], l4_cap_idx_t process); + virtual long start(int argc, const char *argv[], l4_cap_idx_t writer, + l4_cap_idx_t process); }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r 528324377374 -r 7c8ba245fbba libexec/include/exec/process_creator_context_resource.h --- a/libexec/include/exec/process_creator_context_resource.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/include/exec/process_creator_context_resource.h Mon Dec 11 19:23:39 2023 +0100 @@ -56,7 +56,7 @@ /* Process creator context interface methods. */ - virtual long start(int argc, l4_cap_idx_t *process); + virtual long start(int argc, l4_cap_idx_t writer, l4_cap_idx_t *process); /* Pager/dataspace methods. */ diff -r 528324377374 -r 7c8ba245fbba libexec/include/exec/process_creator_resource.h --- a/libexec/include/exec/process_creator_resource.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/include/exec/process_creator_resource.h Mon Dec 11 19:23:39 2023 +0100 @@ -51,7 +51,8 @@ virtual long init_process(l4_cap_idx_t *process); - virtual long start(int argc, const char *argv[], l4_cap_idx_t process); + virtual long start(int argc, const char *argv[], l4_cap_idx_t writer, + l4_cap_idx_t process); /* Opener interface methods. */ diff -r 528324377374 -r 7c8ba245fbba libexec/lib/src/process_creating.cc --- a/libexec/lib/src/process_creating.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/lib/src/process_creating.cc Mon Dec 11 19:23:39 2023 +0100 @@ -283,7 +283,8 @@ /* Configure a thread for a program, populate its stack, and start the thread. */ -long ProcessCreating::start_program(l4_cap_idx_t monitor, int argc, const char *argv[]) +long ProcessCreating::start_program(l4_cap_idx_t monitor, int argc, + const char *argv[], l4_cap_idx_t writer) { /* NOTE: Environment vector is currently not defined. */ @@ -316,10 +317,15 @@ l4_cap_idx_t fsserver_cap = _process.allocate_cap(); l4_cap_idx_t fsserver = l4re_env_get_cap(ENV_FILESYSTEM_SERVER_NAME); + /* Also reserve a capability for the writer. */ + + l4_cap_idx_t writer_cap = _process.allocate_cap(); + /* Define the capabilities to be mapped for the filesystem. */ struct ipc_mapped_cap program_mapped_caps[] = { {fsserver_cap, fsserver, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}, + {writer_cap, writer, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}, {0, L4_INVALID_CAP, 0, 0}, }; @@ -336,6 +342,7 @@ l4re_env_cap_entry_t program_init_caps[] = { l4re_env_cap_entry_t(ENV_FILESYSTEM_SERVER_NAME, fsserver_cap, L4_CAP_FPAGE_RWS), + l4re_env_cap_entry_t(ENV_OUTPUT_STREAM_NAME, writer_cap, L4_CAP_FPAGE_W), l4re_env_cap_entry_t() }; @@ -361,10 +368,12 @@ } /* Start a new process for the payload indicated by the first of the given - program arguments, returning a reference to the process monitor as an object - for interacting with the process. */ + program arguments, employing the given writer pipe, and returning a + reference to the process monitor as an object for interacting with the + process. */ -long ProcessCreating::_start(int argc, const char *argv[], l4_cap_idx_t process) +long ProcessCreating::_start(int argc, const char *argv[], l4_cap_idx_t writer, + l4_cap_idx_t process) { /* Open the program file, handling any error conditions. If successfully opened, it will be closed when the process terminates. */ @@ -410,7 +419,7 @@ if (err) return err; - err = start_program(process, argc, argv); + err = start_program(process, argc, argv, writer); if (err) return err; @@ -435,11 +444,12 @@ /* Start the given program, notifying the process monitor upon any error. */ -long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t process) +long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t writer, + l4_cap_idx_t process) { std::lock_guard guard(_lock); - long err = _start(argc, argv, process); + long err = _start(argc, argv, writer, process); /* Communicate the error using the signal value. */ diff -r 528324377374 -r 7c8ba245fbba libexec/lib/src/process_creator_context_resource.cc --- a/libexec/lib/src/process_creator_context_resource.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/lib/src/process_creator_context_resource.cc Mon Dec 11 19:23:39 2023 +0100 @@ -50,7 +50,8 @@ /* ProcessCreatorContext interface methods. */ -long ProcessCreatorContextResource::start(int argc, l4_cap_idx_t *process) +long ProcessCreatorContextResource::start(int argc, l4_cap_idx_t writer, + l4_cap_idx_t *process) { /* Obtain the arguments by reading from the shared memory. */ @@ -85,7 +86,7 @@ reply, so a notification is sent via the process monitor instead by the process creator. */ - _creator->start(argc, argv, *process); + _creator->start(argc, argv, writer, *process); return IPC_MESSAGE_SENT; } diff -r 528324377374 -r 7c8ba245fbba libexec/lib/src/process_creator_resource.cc --- a/libexec/lib/src/process_creator_resource.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/libexec/lib/src/process_creator_resource.cc Mon Dec 11 19:23:39 2023 +0100 @@ -55,9 +55,10 @@ /* Start the new process, obtaining a reference to it. */ -long ProcessCreatorResource::start(int argc, const char *argv[], l4_cap_idx_t process) +long ProcessCreatorResource::start(int argc, const char *argv[], + l4_cap_idx_t writer, l4_cap_idx_t process) { - return _creating.start(argc, argv, process); + return _creating.start(argc, argv, writer, process); } diff -r 528324377374 -r 7c8ba245fbba libfsclient/include/fsclient/client.h --- a/libfsclient/include/fsclient/client.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libfsclient/include/fsclient/client.h Mon Dec 11 19:23:39 2023 +0100 @@ -34,6 +34,10 @@ l4_cap_idx_t client_open_for_user(user_t user); l4_cap_idx_t client_open_for_user_using(user_t user, l4_cap_idx_t server); +/* Stream access operations. */ + +file_t *client_get_stream(const char *name, flags_t flags); + /* Opening and closing operations. */ void client_close(file_t *file); diff -r 528324377374 -r 7c8ba245fbba libfsclient/include/fsclient/process.h --- a/libfsclient/include/fsclient/process.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libfsclient/include/fsclient/process.h Mon Dec 11 19:23:39 2023 +0100 @@ -53,8 +53,8 @@ long process_error(process_t *process); void process_free(process_t *process); void process_init(process_t *process); -long process_spawn(int argc, const char *argv[], process_t **process); -long process_start(process_t *process, int argc, const char *argv[]); +long process_spawn(int argc, const char *argv[], file_t *writer, process_t **process); +long process_start(process_t *process, int argc, const char *argv[], file_t *writer); long process_wait(process_t *process, notify_flags_t *flags, notify_values_t *values); /* Notification support. */ diff -r 528324377374 -r 7c8ba245fbba libfsclient/lib/src/client.cc --- a/libfsclient/lib/src/client.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/libfsclient/lib/src/client.cc Mon Dec 11 19:23:39 2023 +0100 @@ -261,6 +261,37 @@ +/* Obtain a stream from the environment. */ + +file_t *client_get_stream(const char *name, flags_t flags) +{ + file_t *stream = (file_t *) malloc(sizeof(file_t)); + + file_init(stream); + stream->flags = flags; + stream->ref = l4re_env_get_cap(name); + + /* Enforce blocking if necessary. + NOTE: Ignoring any event subscription error. */ + + if (!(flags & O_NONBLOCK)) + { + notify_flags_t nflags = 0; + + if ((flags & O_WRONLY) || (flags & O_RDWR)) + nflags |= NOTIFY_SPACE_AVAILABLE; + + if ((flags & O_RDONLY) || (flags & O_RDWR)) + nflags |= NOTIFY_CONTENT_AVAILABLE; + + client_set_blocking(stream, nflags | NOTIFY_PEER_CLOSED); + } + + return stream; +} + + + /* Open a filesystem object. */ file_t *client_open(const char *name, flags_t flags) diff -r 528324377374 -r 7c8ba245fbba libfsclient/lib/src/process.cc --- a/libfsclient/lib/src/process.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/libfsclient/lib/src/process.cc Mon Dec 11 19:23:39 2023 +0100 @@ -111,22 +111,24 @@ /* A convenience function for creating and starting a process. */ -long process_spawn(int argc, const char *argv[], process_t **process) +long process_spawn(int argc, const char *argv[], file_t *writer, + process_t **process) { *process = process_new(); /* Start the process with the given arguments. */ if (*process != NULL) - return process_start(*process, argc, argv); + return process_start(*process, argc, argv, writer); else return -L4_ENOMEM; } /* Start a process using the given arguments. - NOTE: This does not yet obtain input/output pipes. */ + NOTE: This does not yet employ a pipe for the process's input stream. */ -long process_start(process_t *process, int argc, const char *argv[]) +long process_start(process_t *process, int argc, const char *argv[], + file_t *writer) { l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME); @@ -157,7 +159,8 @@ /* Start the process, obtaining a reference to it. */ - err = creator.start(argc, &process->ref); + err = creator.start(argc, writer != NULL ? writer->ref : (l4_cap_idx_t) L4_INVALID_CAP, + &process->ref); /* Initialise the notifiable section of the structure. */ diff -r 528324377374 -r 7c8ba245fbba libsystypes/idl/process_creator_context.idl --- a/libsystypes/idl/process_creator_context.idl Mon Dec 11 19:17:25 2023 +0100 +++ b/libsystypes/idl/process_creator_context.idl Mon Dec 11 19:23:39 2023 +0100 @@ -4,7 +4,10 @@ interface ProcessCreatorContext { /* Start a process, using the given argument count to refer to the process - arguments supplied via the dataspace, including the program itself. */ + arguments supplied via the dataspace, including the program itself. - [opcode(30)] void start(in int argc, out cap process); + A writer pipe capability is to be provided for the process's output, and + the process capability is returned. */ + + [opcode(30)] void start(in int argc, in cap writer, out cap process); }; diff -r 528324377374 -r 7c8ba245fbba libsystypes/include/systypes/env.h --- a/libsystypes/include/systypes/env.h Mon Dec 11 19:17:25 2023 +0100 +++ b/libsystypes/include/systypes/env.h Mon Dec 11 19:23:39 2023 +0100 @@ -26,6 +26,7 @@ #define ENV_FILESYSTEM_SERVER_NAME "fsserver" #define ENV_PIPE_SERVER_NAME "pipeserver" #define ENV_PROCESS_SERVER_NAME "prserver" +#define ENV_OUTPUT_STREAM_NAME "stdout" EXTERN_C_END diff -r 528324377374 -r 7c8ba245fbba test_files/programs/dstest_exec_payload.c --- a/test_files/programs/dstest_exec_payload.c Mon Dec 11 19:17:25 2023 +0100 +++ b/test_files/programs/dstest_exec_payload.c Mon Dec 11 19:23:39 2023 +0100 @@ -20,6 +20,13 @@ */ #include +#include + +/* NOTE: For inclusion in the C library. */ + +#include +#include +#include @@ -27,10 +34,24 @@ { int i; + /* NOTE: For inclusion in the C library. */ + + file_t *output = client_get_stream(ENV_OUTPUT_STREAM_NAME, O_WRONLY); + + /* Write the arguments to the output stream. */ + + char buffer[32]; + for (i = 0; i < argc; i++) - printf("Arg #%d: %s\n", i, argv[i]); + { + sprintf(buffer, "Arg #%d: ", i); + client_write(output, buffer, strlen(buffer)); + client_write(output, argv[i], strlen(argv[i])); + client_write(output, "\n", 1); + } - printf("Terminating.\n"); + client_write(output, "Terminating.\n", 13); + client_flush(output); return 0; } diff -r 528324377374 -r 7c8ba245fbba tests/dstest_exec.cc --- a/tests/dstest_exec.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/tests/dstest_exec.cc Mon Dec 11 19:23:39 2023 +0100 @@ -21,20 +21,54 @@ #include +#include #include +#include #include #include +/* Transfer size for communication. */ + +const offset_t TO_TRANSFER = 1024; + + + +/* Test process initiation and interaction. */ + static long test_process(int argc, const char *argv[]) { process_t *process; + file_t *reader, *writer; + long err; + + /* Obtain the common notifier. */ + + notifier_t *notifier = client_notifier_task(); + + /* Create a pipe for process output. */ + + err = client_pipe(&reader, &writer, O_NONBLOCK); + + if (err) + { + printf("Could not obtain pipe: %s\n", l4sys_errtostr(err)); + return err; + } + + err = client_subscribe(reader, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier); + + if (err) + { + printf("Could not subscribe to pipe notifications: %s\n", l4sys_errtostr(err)); + return err; + } /* Start the process. */ - long err = process_spawn(argc, argv, &process); + err = process_spawn(argc, argv, writer, &process); if (err) { @@ -44,21 +78,60 @@ printf("Finished program initiation.\n"); - /* Wait for a signal from the process. */ + /* Wait for a signal from the process or input from the process. */ - notify_flags_t flags; - notify_values_t values; - - err = process_wait(process, &flags, &values); + err = notify_subscribe(process_notifiable(process), NOTIFY_TASK_ALL, notifier); if (err) { - printf("Could not wait for process: %s\n", l4sys_errtostr(err)); + printf("Could not subscribe to task notifications: %s\n", l4sys_errtostr(err)); return err; } + notifiable_t *notifiable; + + while (1) + { + err = notify_wait_many(¬ifiable, notifier); + + if (err) + { + printf("Could not wait for process: %s\n", l4sys_errtostr(err)); + return err; + } + + /* Handle any signal. */ + + if (notifiable == process_notifiable(process)) + break; + + /* Handle any input. */ + + else if (notifiable == file_notifiable(reader)) + { + char buffer[TO_TRANSFER]; + offset_t nread = client_read(reader, buffer, TO_TRANSFER); + + while (nread) + { + fwrite(buffer, sizeof(char), nread, stdout); + nread = client_read(reader, buffer, TO_TRANSFER); + } + } + } + + notify_flags_t flags = process_notifications(process); + notify_values_t values = process_notification_values(process); + printf("End process (flags %" pFMTnotify_flags "x values: %ld, %ld)\n", flags, values.sig, values.val); - return L4_EOK; + + err = process_error(process); + + client_close(reader); + process_free(process); + client_notifier_close(notifier); + + return err; } @@ -73,10 +146,6 @@ return 1; } - /* Obtain the common notifier. */ - - notifier_t *notifier = notify_get_task(); - /* Start a process for a non-existent program. */ printf("Start non-existent program...\n"); @@ -102,8 +171,6 @@ if (err) return 1; - notify_close(notifier); - printf("End of test.\n"); return 0; } diff -r 528324377374 -r 7c8ba245fbba tests/dstest_exec_many.cc --- a/tests/dstest_exec_many.cc Mon Dec 11 19:17:25 2023 +0100 +++ b/tests/dstest_exec_many.cc Mon Dec 11 19:23:39 2023 +0100 @@ -49,7 +49,7 @@ process_t *process; - err = process_spawn(argc - 2, (const char **) argv + 2, &process); + err = process_spawn(argc - 2, (const char **) argv + 2, NULL, &process); if (err) {