# HG changeset patch # User Paul Boddie # Date 1677192566 -3600 # Node ID 9c5e1a1b92aaa157352ced6452c0494a642a90e9 # Parent 97d131d6a09b1f351db7e1697065e89a64b737d8 Introduced a process server and a prototype mechanism for starting new processes and receiving notifications from them. diff -r 97d131d6a09b -r 9c5e1a1b92aa conf/dstest_exec.cfg --- a/conf/dstest_exec.cfg Sat Feb 18 22:48:39 2023 +0100 +++ b/conf/dstest_exec.cfg Thu Feb 23 23:49:26 2023 +0100 @@ -20,7 +20,7 @@ caps = { server = block_server:svr(), }, - log = { "blocksvr", "r" }, + log = { "blocks", "r" }, }, "rom/block_server", "10"); @@ -32,7 +32,7 @@ pipes = pipe_server, ext2svr = ext2svr:svr(), }, - log = { "ext2svr", "y" }, + log = { "ext2", "y" }, }, "rom/ext2_server", "blocksvr", "rom/e2test.fs", "20", "ext2svr"); @@ -41,10 +41,22 @@ local open_for_user = 6; local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18); +local process_server = l:new_channel(); + l:startv({ caps = { server = ext2svr_paulb, + pserver = process_server:svr(), + }, + log = { "process", "y" }, + }, + "rom/process_server", "home/paulb/exec_region_mapper"); + +l:startv({ + caps = { + server = ext2svr_paulb, + pserver = process_server, }, log = { "client", "g" }, }, - "rom/dstest_exec", "home/paulb/exec_region_mapper", "home/paulb/dstest_exec_payload", "hello", "world"); + "rom/dstest_exec", "home/paulb/dstest_exec_payload", "hello", "world"); diff -r 97d131d6a09b -r 9c5e1a1b92aa conf/dstest_exec.list --- a/conf/dstest_exec.list Sat Feb 18 22:48:39 2023 +0100 +++ b/conf/dstest_exec.list Thu Feb 23 23:49:26 2023 +0100 @@ -8,6 +8,7 @@ module ext2_server module block_server module pipe_server +module process_server module lib4re-c.so module lib4re-c-util.so module lib4re.so diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/Control --- a/libexec/Control Sat Feb 18 22:48:39 2023 +0100 +++ b/libexec/Control Thu Feb 23 23:49:26 2023 +0100 @@ -1,3 +1,3 @@ -requires: libstdc++ libc libmem libipc libsystypes libfsclient +requires: libstdc++ libc libmem libipc libsystypes libfsclient libfsserver provides: libexec maintainer: paul@boddie.org.uk diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/include/exec/process_creating.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/process_creating.h Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,91 @@ +/* + * Support for executing code in new tasks and threads. + * + * Copyright (C) 2022, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + + + +/* Process creator functionality. */ + +class ProcessCreating +{ +protected: + const char *_rm_filename; + + /* External pager configuration. */ + + ExternalPager _exec_pager; + ipc_server_config_type _config; + + Process _process; + + /* Stack and payload descriptions. */ + + ExplicitSegment _rm_stack; + Payload *_rm_payload; + + ExplicitSegment _program_stack; + Payload *_program_payload; + + /* IPC gate for communication within the created task, plus allocated + capability. */ + + l4_cap_idx_t _ipc_gate, _ipc_gate_cap; + + /* Utility methods. */ + + long start_pager(); + + long init_region_mapper(); + + long init_program(file_t *file); + + long init_external_pager(); + + long configure_task(); + + long create_ipc_gate(); + + void init_region(struct exec_region *regions, + struct ipc_mapped_cap *mapped_caps, + struct exec_region &r, unsigned int &index); + + long start_region_mapper(); + + long start_program(int argc, const char *argv[]); + +public: + explicit ProcessCreating(const char *rm_filename); + + virtual long start(file_t *file, int argc, const char *argv[]); + + virtual void set_notifier(Notifier *notifier); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/include/exec/process_creator.h --- a/libexec/include/exec/process_creator.h Sat Feb 18 22:48:39 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Support for executing code in new tasks and threads. - * - * Copyright (C) 2022, 2023 Paul Boddie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - - - -/* Process creator. */ - -class ProcessCreator -{ -protected: - const char *_rm_filename; - - /* External pager configuration. */ - - ExternalPager _exec_pager; - ipc_server_config_type _config; - - Process _process; - - /* Stack and payload descriptions. */ - - ExplicitSegment _rm_stack; - Payload *_rm_payload; - - ExplicitSegment _program_stack; - Payload *_program_payload; - - /* IPC gate for communication within the created task, plus allocated - capability. */ - - l4_cap_idx_t _ipc_gate, _ipc_gate_cap; - - /* Utility methods. */ - - long start_pager(); - - long init_region_mapper(); - - long init_program(file_t *file); - - long init_external_pager(); - - long configure_task(); - - long create_ipc_gate(); - - void init_region(struct exec_region *regions, - struct ipc_mapped_cap *mapped_caps, - struct exec_region &r, unsigned int &index); - - long start_region_mapper(); - - long start_program(int argc, const char *argv[]); - -public: - explicit ProcessCreator(const char *rm_filename); - - long start(file_t *file, int argc, const char *argv[]); - - void set_notifier(Notifier *notifier); -}; - -/* vim: tabstop=2 expandtab shiftwidth=2 -*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/include/exec/process_creator_resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/process_creator_resource.h Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,54 @@ +/* + * Support for executing code in new tasks and threads. + * + * Copyright (C) 2022, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include "process_creator_interface.h" + + + +/* Process creator. */ + +class ProcessCreatorResource : public Resource, public ProcessCreating, + public ProcessCreator +{ +public: + explicit ProcessCreatorResource(const char *rm_filename); + + virtual ~ProcessCreatorResource(); + + /* Server details. */ + + ipc_server_default_config_type config(); + + void *interface() + { return static_cast(this); } + + /* Process creator interface methods. */ + + virtual long start(l4_cap_idx_t program, l4_cap_idx_t notifier); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/lib/src/Makefile --- a/libexec/lib/src/Makefile Sat Feb 18 22:48:39 2023 +0100 +++ b/libexec/lib/src/Makefile Thu Feb 23 23:49:26 2023 +0100 @@ -9,7 +9,7 @@ IDL_DIR = $(PKGDIR)/../libsystypes/idl IDL_MK_DIR = $(L4DIR)/idl4re/mk IDL_BUILD_DIR = . -IDL_EXPORT_DIR = . +IDL_EXPORT_DIR = $(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)/exec include $(IDL_MK_DIR)/idl.mk @@ -17,7 +17,7 @@ CLIENT_INTERFACES_CC = dataspace mapped_file notifier -SERVER_INTERFACES_CC = pager_object parent_pager_object +SERVER_INTERFACES_CC = pager_object parent_pager_object process_creator # Generated and plain source files. @@ -30,8 +30,9 @@ PLAIN_SRC_CC = \ common.cc elf.cc external_pager.cc \ internal_pager.cc memory.cc pager.cc \ - process.cc process_creator.cc segment.cc \ - stack.cc + process.cc process_creating.cc \ + process_creator_resource.cc \ + segment.cc stack.cc # Normal definitions. @@ -40,7 +41,7 @@ $(SERVER_INTERFACES_SRC_CC) \ $(PLAIN_SRC_CC) -REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient +REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient libfsserver PRIVATE_INCDIR = $(PKGDIR)/include/exec $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/lib/src/process_creating.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/process_creating.cc Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,324 @@ +/* + * Support for executing code in new tasks and threads. + * + * Copyright (C) 2022, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include + +#include +#include + +#include "parent_pager_object_server.h" +#include "process_creating.h" + + + +/* Process stack configuration. */ + +static const offset_t initial_stack_size = 16 * L4_PAGESIZE; + + + +/* Initialise the process creator with the details of a region mapper. */ + +ProcessCreating::ProcessCreating(const char *rm_filename) +: _rm_filename(rm_filename), + _exec_pager(0, 10 * L4_PAGESIZE), + _rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW), + _program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW) +{ +} + +/* Start the system pager in a separate thread. */ + +long ProcessCreating::start_pager() +{ + pthread_t pager_thread; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + ipc_server_init_for(&_config, ParentPagerObject, &_exec_pager); + + long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &_config); + + if (err) + return err; + + return ipc_server_start_config_thread(&_config, pthread_l4_cap(pager_thread)); +} + +/* Initialise the memory segments of the region mapper. These are mapped into + this task so that we may access them, allowing the external pager in this + task to use them. */ + +long ProcessCreating::init_region_mapper() +{ + long err = exec_get_payload(_rm_filename, &_rm_payload, true); + + if (err) + return err; + + return _rm_stack.allocate(true); +} + +/* Initialise the memory segments of the actual program. These are not mapped + into this task, instead being accessed by the region mapper in the new + task. */ + +long ProcessCreating::init_program(file_t *file) +{ + long err = exec_get_payload_file(file, &_program_payload, false); + + if (err) + return err; + + return _program_stack.allocate(true); +} + +/* Initialise an external system-level pager serving the region mapper in a + created task. The allocated regions requested by the region mapper are + constrained to an area of memory that must not overlap with the area reserved + for the program being run. */ + +long ProcessCreating::init_external_pager() +{ + /* Initialise pager regions for the region mapper. */ + + for (unsigned int i = 0; i < _rm_payload->segments(); i++) + { + if (_rm_payload->segment(i)->loadable()) + _exec_pager.add(_rm_payload->segment(i)->region()); + } + + /* Include the region mapper's stack region. */ + + _exec_pager.add(_rm_stack.region()); + + /* Start the pager in a separate thread. */ + + return start_pager(); +} + +/* Configure the environment for the task. */ + +long ProcessCreating::configure_task() +{ + long err = _process.configure_task(); + + if (err) + return err; + + return _process.set_parent(_config.server); +} + +/* Create an unbound IPC gate for the region mapper and allocate it in the + created process. */ + +long ProcessCreating::create_ipc_gate() +{ + _ipc_gate_cap = _process.allocate_cap(); + _ipc_gate = ipc_cap_alloc(); + + if (l4_is_invalid_cap(_ipc_gate)) + return -L4_ENOMEM; + + return l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0)); +} + +/* Initialise and assign a region in a list to the created process. */ + +void ProcessCreating::init_region(struct exec_region *regions, + struct ipc_mapped_cap *mapped_caps, + struct exec_region &r, unsigned int &index) +{ + l4_cap_idx_t mapped_cap = _process.allocate_cap(); + + mapped_caps[index] = (struct ipc_mapped_cap) {mapped_cap, r.ds, L4_CAP_FPAGE_RWS, 0}; + + /* Change the region definition to use the allocated capability in the created + process. */ + + regions[index] = r; + regions[index].ds = mapped_cap; + index++; +} + +/* Initialise the region mapper with details of the payload program regions + and of the associated capabilities, configure the region mapper thread, + populate its stack, and start the thread. */ + +long ProcessCreating::start_region_mapper() +{ + /* Define regions employing dataspaces to provide program segments. */ + + struct exec_region rm_regions[_rm_payload->segments() + 2]; + + /* Define capabilities for mapping, including region dataspace capabilities, + the stack dataspace capability, and the server capability. */ + + struct ipc_mapped_cap rm_mapped_caps[_rm_payload->segments() + 3]; + + /* Here, the arrays are sized for the maximum number of regions and + capabilities, but in practice only the loadable segments are used, leaving + fewer elements utilised. A terminating entry is employed to indicate the + limit of utilised elements. */ + + unsigned int rm_index = 0; + + for (unsigned int i = 0; i < _program_payload->segments(); i++) + { + Segment *s = _program_payload->segment(i); + + if (s->loadable()) + init_region(rm_regions, rm_mapped_caps, s->exec_region(), rm_index); + } + + /* Introduce the stack region and capability. */ + + init_region(rm_regions, rm_mapped_caps, _program_stack.exec_region(), rm_index); + + /* Terminate the region array. */ + + rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP}; + + /* Introduce the server capability and terminate the capability array. */ + + rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}; + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0}; + + /* Map these additional capabilities. */ + + _process.map_capabilities(rm_mapped_caps, false); + + /* Define the IPC gate as an initial capability to be acquired by the region + mapper via the l4re_env API. The capability index is assigned above when + mapping the capability and encoded in the entry below. */ + + l4re_env_cap_entry_t rm_init_caps[] = { + l4re_env_cap_entry_t("server", _ipc_gate_cap, L4_CAP_FPAGE_RWS), + l4re_env_cap_entry_t() + }; + + /* NOTE: Environment vector is currently not defined. */ + + const char *envp[] = {NULL}; + + /* Configure the environment for the thread, specifying the pager (and + exception handler plus region mapper). */ + + long err = _process.configure_thread(_config.server); + + if (err) + return err; + + /* Populate a thread stack with argument and environment details for the + region mapper, plus the initial server capability and region details. */ + + const char *argv[] = {_rm_filename}; + Stack rm_st(_rm_stack); + + rm_st.set_init_caps(rm_init_caps); + rm_st.set_regions(rm_regions); + rm_st.populate(1, argv, envp); + + /* Start the region mapper thread in the appropriate stack. */ + + return _process.thread_start(_rm_payload->entry_point(), rm_st); +} + +/* Configure a thread for a program, populate its stack, and start the + thread. */ + +long ProcessCreating::start_program(int argc, const char *argv[]) +{ + /* NOTE: Environment vector is currently not defined. */ + + const char *envp[] = {NULL}; + + /* Configure the environment for the thread, specifying the pager (and + exception handler plus region mapper). */ + + long err = _process.configure_thread(_ipc_gate, _ipc_gate_cap); + + if (err) + return err; + + /* Populate a thread stack with argument and environment details for the + actual program. The server capability should be assigned to the region + mapper capability slot already. */ + + Stack program_st(_program_stack); + + program_st.populate(argc, argv, envp); + + /* Start the program thread in the appropriate stack. */ + + return _process.thread_start(_program_payload->entry_point(), program_st); +} + +/* Start a new process for the given payload, providing the indicated program + arguments. */ + +long ProcessCreating::start(file_t *file, int argc, const char *argv[]) +{ + long err; + + err = init_region_mapper(); + if (err) + return err; + + err = init_program(file); + if (err) + return err; + + err = init_external_pager(); + if (err) + return err; + + err = configure_task(); + if (err) + return err; + + err = create_ipc_gate(); + if (err) + return err; + + err = start_region_mapper(); + if (err) + return err; + + return start_program(argc, argv); +} + +/* Set the given notifier on the system-level pager for a process. */ + +void ProcessCreating::set_notifier(Notifier *notifier) +{ + _exec_pager.set_notifier(notifier); +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/lib/src/process_creator.cc --- a/libexec/lib/src/process_creator.cc Sat Feb 18 22:48:39 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -/* - * Support for executing code in new tasks and threads. - * - * Copyright (C) 2022, 2023 Paul Boddie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA - */ - -#include - -#include -#include - -#include - -#include -#include - -#include "parent_pager_object_server.h" -#include "process_creator.h" - - - -/* Process stack configuration. */ - -static const offset_t initial_stack_size = 16 * L4_PAGESIZE; - - - -/* Initialise the process creator with the details of a region mapper. */ - -ProcessCreator::ProcessCreator(const char *rm_filename) -: _rm_filename(rm_filename), - _exec_pager(0, 10 * L4_PAGESIZE), - _rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW), - _program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW) -{ -} - -/* Start the system pager in a separate thread. */ - -long ProcessCreator::start_pager() -{ - pthread_t pager_thread; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - ipc_server_init_for(&_config, ParentPagerObject, &_exec_pager); - - long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &_config); - - if (err) - return err; - - return ipc_server_start_config_thread(&_config, pthread_l4_cap(pager_thread)); -} - -/* Initialise the memory segments of the region mapper. These are mapped into - this task so that we may access them, allowing the external pager in this - task to use them. */ - -long ProcessCreator::init_region_mapper() -{ - long err = exec_get_payload(_rm_filename, &_rm_payload, true); - - if (err) - return err; - - return _rm_stack.allocate(true); -} - -/* Initialise the memory segments of the actual program. These are not mapped - into this task, instead being accessed by the region mapper in the new - task. */ - -long ProcessCreator::init_program(file_t *file) -{ - long err = exec_get_payload_file(file, &_program_payload, false); - - if (err) - return err; - - return _program_stack.allocate(true); -} - -/* Initialise an external system-level pager serving the region mapper in a - created task. The allocated regions requested by the region mapper are - constrained to an area of memory that must not overlap with the area reserved - for the program being run. */ - -long ProcessCreator::init_external_pager() -{ - /* Initialise pager regions for the region mapper. */ - - for (unsigned int i = 0; i < _rm_payload->segments(); i++) - { - if (_rm_payload->segment(i)->loadable()) - _exec_pager.add(_rm_payload->segment(i)->region()); - } - - /* Include the region mapper's stack region. */ - - _exec_pager.add(_rm_stack.region()); - - /* Start the pager in a separate thread. */ - - return start_pager(); -} - -/* Configure the environment for the task. */ - -long ProcessCreator::configure_task() -{ - long err = _process.configure_task(); - - if (err) - return err; - - return _process.set_parent(_config.server); -} - -/* Create an unbound IPC gate for the region mapper and allocate it in the - created process. */ - -long ProcessCreator::create_ipc_gate() -{ - _ipc_gate_cap = _process.allocate_cap(); - _ipc_gate = ipc_cap_alloc(); - - if (l4_is_invalid_cap(_ipc_gate)) - return -L4_ENOMEM; - - return l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0)); -} - -/* Initialise and assign a region in a list to the created process. */ - -void ProcessCreator::init_region(struct exec_region *regions, - struct ipc_mapped_cap *mapped_caps, - struct exec_region &r, unsigned int &index) -{ - l4_cap_idx_t mapped_cap = _process.allocate_cap(); - - mapped_caps[index] = (struct ipc_mapped_cap) {mapped_cap, r.ds, L4_CAP_FPAGE_RWS, 0}; - - /* Change the region definition to use the allocated capability in the created - process. */ - - regions[index] = r; - regions[index].ds = mapped_cap; - index++; -} - -/* Initialise the region mapper with details of the payload program regions - and of the associated capabilities, configure the region mapper thread, - populate its stack, and start the thread. */ - -long ProcessCreator::start_region_mapper() -{ - /* Define regions employing dataspaces to provide program segments. */ - - struct exec_region rm_regions[_rm_payload->segments() + 2]; - - /* Define capabilities for mapping, including region dataspace capabilities, - the stack dataspace capability, and the server capability. */ - - struct ipc_mapped_cap rm_mapped_caps[_rm_payload->segments() + 3]; - - /* Here, the arrays are sized for the maximum number of regions and - capabilities, but in practice only the loadable segments are used, leaving - fewer elements utilised. A terminating entry is employed to indicate the - limit of utilised elements. */ - - unsigned int rm_index = 0; - - for (unsigned int i = 0; i < _program_payload->segments(); i++) - { - Segment *s = _program_payload->segment(i); - - if (s->loadable()) - init_region(rm_regions, rm_mapped_caps, s->exec_region(), rm_index); - } - - /* Introduce the stack region and capability. */ - - init_region(rm_regions, rm_mapped_caps, _program_stack.exec_region(), rm_index); - - /* Terminate the region array. */ - - rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP}; - - /* Introduce the server capability and terminate the capability array. */ - - rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS}; - rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0}; - - /* Map these additional capabilities. */ - - _process.map_capabilities(rm_mapped_caps, false); - - /* Define the IPC gate as an initial capability to be acquired by the region - mapper via the l4re_env API. The capability index is assigned above when - mapping the capability and encoded in the entry below. */ - - l4re_env_cap_entry_t rm_init_caps[] = { - l4re_env_cap_entry_t("server", _ipc_gate_cap, L4_CAP_FPAGE_RWS), - l4re_env_cap_entry_t() - }; - - /* NOTE: Environment vector is currently not defined. */ - - const char *envp[] = {NULL}; - - /* Configure the environment for the thread, specifying the pager (and - exception handler plus region mapper). */ - - long err = _process.configure_thread(_config.server); - - if (err) - return err; - - /* Populate a thread stack with argument and environment details for the - region mapper, plus the initial server capability and region details. */ - - const char *argv[] = {_rm_filename}; - Stack rm_st(_rm_stack); - - rm_st.set_init_caps(rm_init_caps); - rm_st.set_regions(rm_regions); - rm_st.populate(1, argv, envp); - - /* Start the region mapper thread in the appropriate stack. */ - - return _process.thread_start(_rm_payload->entry_point(), rm_st); -} - -/* Configure a thread for a program, populate its stack, and start the - thread. */ - -long ProcessCreator::start_program(int argc, const char *argv[]) -{ - /* NOTE: Environment vector is currently not defined. */ - - const char *envp[] = {NULL}; - - /* Configure the environment for the thread, specifying the pager (and - exception handler plus region mapper). */ - - long err = _process.configure_thread(_ipc_gate, _ipc_gate_cap); - - if (err) - return err; - - /* Populate a thread stack with argument and environment details for the - actual program. The server capability should be assigned to the region - mapper capability slot already. */ - - Stack program_st(_program_stack); - - program_st.populate(argc, argv, envp); - - /* Start the program thread in the appropriate stack. */ - - return _process.thread_start(_program_payload->entry_point(), program_st); -} - -/* Start a new process for the given payload, providing the indicated program - arguments. */ - -long ProcessCreator::start(file_t *file, int argc, const char *argv[]) -{ - long err; - - err = init_region_mapper(); - if (err) - return err; - - err = init_program(file); - if (err) - return err; - - err = init_external_pager(); - if (err) - return err; - - err = configure_task(); - if (err) - return err; - - err = create_ipc_gate(); - if (err) - return err; - - err = start_region_mapper(); - if (err) - return err; - - return start_program(argc, argv); -} - -/* Set the given notifier on the system-level pager for a process. */ - -void ProcessCreator::set_notifier(Notifier *notifier) -{ - _exec_pager.set_notifier(notifier); -} - -/* vim: tabstop=2 expandtab shiftwidth=2 -*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa libexec/lib/src/process_creator_resource.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/process_creator_resource.cc Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,82 @@ +/* + * A resource offering support for creating processes. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include "process_creating.h" +#include "process_creator_resource.h" + +#include "notifier_client.h" +#include "process_creator_server.h" + + + +/* Support for creating processes. */ + +ProcessCreatorResource::ProcessCreatorResource(const char *rm_filename) +: ProcessCreating(rm_filename) +{ +} + +ProcessCreatorResource::~ProcessCreatorResource() +{ +} + +ipc_server_default_config_type ProcessCreatorResource::config() +{ + return config_ProcessCreator; +} + + + +/* ProcessCreator interface methods. */ + +long ProcessCreatorResource::start(l4_cap_idx_t program, l4_cap_idx_t notifier) +{ + file_t file; + + file_init(&file); + file.ref = program; + + /* Obtain a distinct and usable file object. */ + + file_t *program_file = client_reopen(&file, O_RDONLY); + + /* NOTE: To be replaced with the actual arguments, perhaps involving a + context object. */ + + const char *argv[] = {""}; + + long err = ProcessCreating::start(program_file, 1, argv); + + if (err) + return err; + + /* NOTE: To be managed properly. */ + + client_Notifier *n = new client_Notifier(notifier); + + set_notifier(n); + + return L4_EOK; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 97d131d6a09b -r 9c5e1a1b92aa libfsclient/include/fsclient/notifier.h --- a/libfsclient/include/fsclient/notifier.h Sat Feb 18 22:48:39 2023 +0100 +++ b/libfsclient/include/fsclient/notifier.h Thu Feb 23 23:49:26 2023 +0100 @@ -106,6 +106,10 @@ virtual long unsubscribe(notifiable_t *object); + virtual long get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create); + + virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint); + /* Event handling support. */ virtual void mainloop(); diff -r 97d131d6a09b -r 9c5e1a1b92aa libfsclient/include/fsclient/process.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsclient/include/fsclient/process.h Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,78 @@ +/* + * Process-related convenience functions and types. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#include +#include + + + +/* C compatibility types (defined in the implementation). */ + +struct process_notifier; + +typedef struct process_notifier process_notifier_t; + + + +EXTERN_C_BEGIN + +/* File access abstraction compatible with notifiable_base_t. */ + +typedef struct +{ + /* File object reference. */ + + l4_cap_idx_t ref; + + /* Notification structure. */ + + notifiable_t notifiable; + +} process_t; + + + +/* Principal functions. */ + +process_t *process_new(); +void process_init(process_t *process); +long process_start(process_t *process, file_t *file, process_notifier_t *notifier); + +/* Notification support. */ + +notifiable_t *process_notifiable(process_t *process); +notify_flags_t process_notifications(process_t *process); +notify_values_t process_notification_values(process_t *process); +void process_notify_close(process_notifier_t *notifier); +process_notifier_t *process_notify_local(); +process_notifier_t *process_notify_task(); +long process_notify_get_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t *endpoint); +long process_notify_remove_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t endpoint); +long process_notify_wait_process(process_t *process, process_notifier_t *notifier); +long process_notify_wait_processes(process_t **process, process_notifier_t *notifier); + +EXTERN_C_END + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 97d131d6a09b -r 9c5e1a1b92aa libfsclient/lib/src/Makefile --- a/libfsclient/lib/src/Makefile Sat Feb 18 22:48:39 2023 +0100 +++ b/libfsclient/lib/src/Makefile Thu Feb 23 23:49:26 2023 +0100 @@ -17,13 +17,13 @@ CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \ mapped_file notifier notification opener \ - opener_context pipe pipe_opener + opener_context pipe pipe_opener process_creator # Generated and plain source files. CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) -PLAIN_SRC_CC = client.cc file.cc notifier.cc +PLAIN_SRC_CC = client.cc file.cc notifier.cc process.cc # Normal definitions. diff -r 97d131d6a09b -r 9c5e1a1b92aa libfsclient/lib/src/notifier.cc --- a/libfsclient/lib/src/notifier.cc Sat Feb 18 22:48:39 2023 +0100 +++ b/libfsclient/lib/src/notifier.cc Thu Feb 23 23:49:26 2023 +0100 @@ -188,51 +188,29 @@ long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags) { - /* Acquire the lock for state lookup. */ - - std::unique_lock state_guard(_state_lock); - - ObjectNotificationState &state = object_state(object, true); - long err; - - /* Create a notification endpoint, if necessary. */ + l4_cap_idx_t endpoint; + long err = get_endpoint(object, &endpoint, true); - if (state.is_null()) - { - err = ipc_server_new_for_thread(&state.endpoint, object, _thread); + if (err) + return err; - if (err) - return err; - } - - /* Subscribe, sending the notification endpoint. */ + /* Subscribe, sending the notification endpoint via the principal reference + for the object. */ client_Notification notify(object->base->ref); - err = notify.subscribe(state.endpoint, flags); - - if (err) - { - ipc_cap_free_um(state.endpoint); - _state.erase(object); - return err; - } - - return L4_EOK; + return notify.subscribe(endpoint, flags); } /* Unsubscribe from notification events on an object. */ long ObjectNotifier::unsubscribe(notifiable_t *object) { - /* Acquire the lock for state lookup. */ - - std::unique_lock state_guard(_state_lock); + l4_cap_idx_t endpoint; + long err = get_endpoint(object, &endpoint, false); - ObjectNotificationState &state = object_state(object, false); - - if (state.is_null()) - return -L4_EINVAL; + if (err) + return err; /* Unsubscribe via the notification interface. */ @@ -240,7 +218,46 @@ notify.unsubscribe(); - ipc_cap_free_um(state.endpoint); + return remove_endpoint(object, endpoint); +} + +/* Obtain a notification endpoint for an object. */ + +long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create) +{ + /* Acquire the lock for state lookup. */ + + std::unique_lock state_guard(_state_lock); + + ObjectNotificationState &state = object_state(object, create); + + /* Create a notification endpoint, if necessary. */ + + if (state.is_null()) + { + if (create) + { + long err = ipc_server_new_for_thread(&state.endpoint, object, _thread); + + if (err) + return err; + } + else + return -L4_ENOENT; + } + + *endpoint = state.endpoint; + return L4_EOK; +} + +/* Remove a notification endpoint for an object. */ + +long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint) +{ + if (l4_is_invalid_cap(endpoint)) + return -L4_EINVAL; + + ipc_cap_free_um(endpoint); _state.erase(object); diff -r 97d131d6a09b -r 9c5e1a1b92aa libfsclient/lib/src/process.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsclient/lib/src/process.cc Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,197 @@ +/* + * Process-related convenience functions. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include + +#include "process_creator_client.h" + +#include "file.h" +#include "process.h" +#include "notifier.h" + + + +/* Create a new process object. */ + +process_t *process_new() +{ + process_t *process = (process_t *) malloc(sizeof(process_t)); + + if (process == NULL) + return NULL; + + process_init(process); + return process; +} + +/* Initialise the given process structure. */ + +void process_init(process_t *process) +{ + process->ref = L4_INVALID_CAP; + + /* Initialise the notifiable section of the structure. */ + + process->notifiable.notifications = 0; + process->notifiable.base = (notifiable_base_t *) process; +} + +/* Start a process using the given file as payload. + NOTE: This does not yet communicate arguments or obtain input/output + pipes. */ + +long process_start(process_t *process, file_t *file, process_notifier_t *notifier) +{ + l4_cap_idx_t server = l4re_env_get_cap("pserver"); + + if (l4_is_invalid_cap(server)) + return -L4_ENOMEM; + + /* Obtain a notification endpoint. */ + + l4_cap_idx_t endpoint; + long err = process_notify_get_endpoint(process, notifier, &endpoint); + + if (err) + return err; + + /* Obtain a client for the process creator. */ + + client_ProcessCreator creator(server); + + /* Start the process, supplying the given endpoint. */ + + return creator.start(file->ref, endpoint); +} + + + +/* NOTE: Much of the code below could be unified with the file-related + notification code. */ + +/* Opaque notifier type for process_notifier_t. */ + +struct process_notifier +{ + ObjectNotifier *obj; +}; + +/* Conversion to the generic notification types. */ + +notifiable_t *process_notifiable(process_t *process) +{ + return &process->notifiable; +} + +/* Return the notification flags for a process. */ + +notify_flags_t process_notifications(process_t *process) +{ + return process->notifiable.notifications; +} + +/* Return the notification values for a process. */ + +notify_values_t process_notification_values(process_t *process) +{ + return process->notifiable.values; +} + +/* Close a notifier object. */ + +void process_notify_close(process_notifier_t *notifier) +{ + delete notifier->obj; + delete notifier; +} + +/* Obtain a local notifier object. */ + +process_notifier_t *process_notify_local() +{ + process_notifier_t *notifier = new process_notifier_t; + + notifier->obj = notifier_get_local_notifier(); + return notifier; +} + +/* Obtain the task-wide notifier object. */ + +process_notifier_t *process_notify_task() +{ + process_notifier_t *notifier = new process_notifier_t; + + notifier->obj = notifier_get_task_notifier(); + return notifier; +} + +/* Subscribe to notification events on a process. */ + +long process_notify_get_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t *endpoint) +{ + return notifier->obj->get_endpoint(process_notifiable(process), endpoint, true); +} + +/* Unsubscribe from notification events on a process. */ + +long process_notify_remove_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t endpoint) +{ + return notifier->obj->remove_endpoint(process_notifiable(process), endpoint); +} + +/* Wait for a notification event on a process. */ + +long process_notify_wait_process(process_t *process, process_notifier_t *notifier) +{ + SpecificObjectNotifier *specific_notifier = dynamic_cast(notifier->obj); + long err = specific_notifier->wait_object(process_notifiable(process)); + + /* Unsubscribe if a closure notification has been received. */ + + //if (!err && (process->notifiable.notifications & NOTIFY_PEER_CLOSED)) + //process_notify_unsubscribe(process, notifier); + + return err; +} + +/* Wait for notification events on processes. */ + +long process_notify_wait_processes(process_t **process, process_notifier_t *notifier) +{ + GeneralObjectNotifier *general_notifier = dynamic_cast(notifier->obj); + notifiable_t *notifiable; + long err = general_notifier->wait(¬ifiable); + + *process = (process_t *) notifiable->base; + + /* Unsubscribe if a closure notification has been received. */ + + //if (!err && ((*file)->notifiable.notifications & NOTIFY_PEER_CLOSED)) + //file_notify_unsubscribe(*file, notifier); + + return err; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 97d131d6a09b -r 9c5e1a1b92aa libsystypes/idl/process_creator.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/process_creator.idl Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,7 @@ +interface ProcessCreator +{ + /* Start a process, using the given file reference as the payload, indicating + a notifier to receive notifications. */ + + [opcode(30)] void start(in cap program, in cap notifier); +}; diff -r 97d131d6a09b -r 9c5e1a1b92aa servers/Control --- a/servers/Control Sat Feb 18 22:48:39 2023 +0100 +++ b/servers/Control Thu Feb 23 23:49:26 2023 +0100 @@ -1,3 +1,3 @@ -requires: libstdc++ libc libipc libfsserver libmem libe2access_blockserver +requires: libstdc++ libc libipc libfsserver libmem libe2access_blockserver libexec provides: fsservers maintainer: paul@boddie.org.uk diff -r 97d131d6a09b -r 9c5e1a1b92aa servers/Makefile --- a/servers/Makefile Sat Feb 18 22:48:39 2023 +0100 +++ b/servers/Makefile Thu Feb 23 23:49:26 2023 +0100 @@ -6,6 +6,7 @@ ext2_server \ host_server \ pipe_server \ + process_server \ test_server MODE = static @@ -18,8 +19,10 @@ SRC_CC_pipe_server = pipe_server.cc +SRC_CC_process_server = process_server.cc + SRC_CC_test_server = test_file_server.cc -REQUIRES_LIBS = l4re_c-util libmem libfsserver libipc libstdc++ libsystypes libe2access_blockserver +REQUIRES_LIBS = l4re_c-util libmem libfsserver libipc libstdc++ libsystypes libe2access_blockserver libexec include $(L4DIR)/mk/prog.mk diff -r 97d131d6a09b -r 9c5e1a1b92aa servers/process_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servers/process_server.cc Thu Feb 23 23:49:26 2023 +0100 @@ -0,0 +1,77 @@ +/* + * A process server providing a way of creating new processes. + * + * Copyright (C) 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include +#include + +#include +#include + + + +/* Server program. */ + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + printf("Need a region mapper.\n"); + return 1; + } + + char *rm_filename = argv[1]; + const char *server_name = (argc > 2) ? argv[2] : "pserver"; + long err; + + /* Introduce concurrency control. */ + + err = ipc_thread_init(); + + if (err) + { + printf("Initialisation error: %s\n", l4sys_errtostr(err)); + return 1; + } + + ProcessCreatorResource creator(rm_filename); + + /* Register a server associating it with the given object. */ + + ResourceServer server(&creator); + err = server.bind(server_name); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Starting server...\n"); + server.start(); + return 0; +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 97d131d6a09b -r 9c5e1a1b92aa tests/Control --- a/tests/Control Sat Feb 18 22:48:39 2023 +0100 +++ b/tests/Control Thu Feb 23 23:49:26 2023 +0100 @@ -1,3 +1,3 @@ -requires: libstdc++ libc libexec libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files +requires: libstdc++ libc libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files provides: fstests maintainer: paul@boddie.org.uk diff -r 97d131d6a09b -r 9c5e1a1b92aa tests/Makefile --- a/tests/Makefile Sat Feb 18 22:48:39 2023 +0100 +++ b/tests/Makefile Thu Feb 23 23:49:26 2023 +0100 @@ -32,13 +32,11 @@ # Required interfaces. -CLIENT_INTERFACES_CC_dstest_exec = notifier CLIENT_INTERFACES_CC_dstest_file_mapping = dataspace CLIENT_INTERFACES_CC = dataspace notifier # Generated and plain source files. -CLIENT_INTERFACES_SRC_CC_dstest_exec = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC_dstest_exec)) CLIENT_INTERFACES_SRC_CC_dstest_file_mapping = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC_dstest_file_mapping)) # Normal source files. @@ -77,7 +75,7 @@ SRC_CC_dstest_align = dstest_align.cc -REQUIRES_LIBS = l4re_c-util libexec libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver +REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) include $(L4DIR)/mk/prog.mk diff -r 97d131d6a09b -r 9c5e1a1b92aa tests/dstest_exec.cc --- a/tests/dstest_exec.cc Sat Feb 18 22:48:39 2023 +0100 +++ b/tests/dstest_exec.cc Thu Feb 23 23:49:26 2023 +0100 @@ -23,7 +23,8 @@ #include #include -#include +#include +#include #include #include @@ -31,34 +32,18 @@ -class local_Notifier : public Notifier -{ -public: - long notify(notify_flags_t flags, notify_values_t values) - { - printf("Notified with flags: %" pFMTnotify_flags "x\n", flags); - printf("Notified with values: %ld, %ld\n", values.sig, values.val); - - return L4_EOK; - } -}; - - - int main(int argc, char *argv[]) { long err; - if (argc < 3) + if (argc < 2) { - printf("Need a region mapper and the actual program to run.\n"); + printf("Need the program to run.\n"); return 1; } - char *rm_filename = argv[1]; - char *program_filename = argv[2]; + char *program_filename = argv[1]; - ProcessCreator creator(rm_filename); file_t *program_file = client_open(program_filename, O_RDONLY); if (!client_opened(program_file)) @@ -67,10 +52,18 @@ return 1; } - local_Notifier notifier; + /* Create a new process structure and obtain the common notifier. */ + + process_t *process = process_new(); + process_notifier_t *notifier = process_notify_task(); - creator.set_notifier(¬ifier); - err = creator.start(program_file, argc - 2, (const char **) argv + 2); + /* Start a process for the given program, specifying a notifier from which an + endpoint will be obtained for notifications. */ + + err = process_start(process, program_file, notifier); + + /* NOTE: Need to be able to send arguments, which would be sent via a context, + although capabilities could be sent via arguments. */ if (err) { @@ -79,17 +72,18 @@ } printf("Finished program initiation.\n"); - printf("End of test.\n"); + + /* Wait for a signal from the process. */ + + err = process_notify_wait_process(process, notifier); - /* NOTE: Should be able to obtain a notification for when the program - finishes, which might be done using a capability deletion IRQ. - Eventually, this program will operate as a server, invoking new - programs and handling termination. This test would then merely - involve the invocation of a utility function. */ + notify_flags_t flags = process_notifications(process); + notify_values_t values = process_notification_values(process); - while (1) - l4_sleep_forever(); + printf("Notified with flags: %" pFMTnotify_flags "x\n", flags); + printf("Notified with values: %ld, %ld\n", values.sig, values.val); + printf("End of test.\n"); return 0; }