1.1 --- a/conf/dstest_exec.cfg Sat Feb 18 22:48:39 2023 +0100
1.2 +++ b/conf/dstest_exec.cfg Thu Feb 23 23:49:26 2023 +0100
1.3 @@ -20,7 +20,7 @@
1.4 caps = {
1.5 server = block_server:svr(),
1.6 },
1.7 - log = { "blocksvr", "r" },
1.8 + log = { "blocks", "r" },
1.9 },
1.10 "rom/block_server", "10");
1.11
1.12 @@ -32,7 +32,7 @@
1.13 pipes = pipe_server,
1.14 ext2svr = ext2svr:svr(),
1.15 },
1.16 - log = { "ext2svr", "y" },
1.17 + log = { "ext2", "y" },
1.18 },
1.19 "rom/ext2_server", "blocksvr", "rom/e2test.fs", "20", "ext2svr");
1.20
1.21 @@ -41,10 +41,22 @@
1.22 local open_for_user = 6;
1.23 local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18);
1.24
1.25 +local process_server = l:new_channel();
1.26 +
1.27 l:startv({
1.28 caps = {
1.29 server = ext2svr_paulb,
1.30 + pserver = process_server:svr(),
1.31 + },
1.32 + log = { "process", "y" },
1.33 + },
1.34 + "rom/process_server", "home/paulb/exec_region_mapper");
1.35 +
1.36 +l:startv({
1.37 + caps = {
1.38 + server = ext2svr_paulb,
1.39 + pserver = process_server,
1.40 },
1.41 log = { "client", "g" },
1.42 },
1.43 - "rom/dstest_exec", "home/paulb/exec_region_mapper", "home/paulb/dstest_exec_payload", "hello", "world");
1.44 + "rom/dstest_exec", "home/paulb/dstest_exec_payload", "hello", "world");
2.1 --- a/conf/dstest_exec.list Sat Feb 18 22:48:39 2023 +0100
2.2 +++ b/conf/dstest_exec.list Thu Feb 23 23:49:26 2023 +0100
2.3 @@ -8,6 +8,7 @@
2.4 module ext2_server
2.5 module block_server
2.6 module pipe_server
2.7 +module process_server
2.8 module lib4re-c.so
2.9 module lib4re-c-util.so
2.10 module lib4re.so
3.1 --- a/libexec/Control Sat Feb 18 22:48:39 2023 +0100
3.2 +++ b/libexec/Control Thu Feb 23 23:49:26 2023 +0100
3.3 @@ -1,3 +1,3 @@
3.4 -requires: libstdc++ libc libmem libipc libsystypes libfsclient
3.5 +requires: libstdc++ libc libmem libipc libsystypes libfsclient libfsserver
3.6 provides: libexec
3.7 maintainer: paul@boddie.org.uk
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/libexec/include/exec/process_creating.h Thu Feb 23 23:49:26 2023 +0100
4.3 @@ -0,0 +1,91 @@
4.4 +/*
4.5 + * Support for executing code in new tasks and threads.
4.6 + *
4.7 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
4.8 + *
4.9 + * This program is free software; you can redistribute it and/or
4.10 + * modify it under the terms of the GNU General Public License as
4.11 + * published by the Free Software Foundation; either version 2 of
4.12 + * the License, or (at your option) any later version.
4.13 + *
4.14 + * This program is distributed in the hope that it will be useful,
4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 + * GNU General Public License for more details.
4.18 + *
4.19 + * You should have received a copy of the GNU General Public License
4.20 + * along with this program; if not, write to the Free Software
4.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
4.22 + * Boston, MA 02110-1301, USA
4.23 + */
4.24 +
4.25 +#pragma once
4.26 +
4.27 +#include <exec/elf.h>
4.28 +#include <exec/external_pager.h>
4.29 +#include <exec/memory.h>
4.30 +#include <exec/process.h>
4.31 +#include <ipc/map.h>
4.32 +#include <ipc/server.h>
4.33 +
4.34 +
4.35 +
4.36 +/* Process creator functionality. */
4.37 +
4.38 +class ProcessCreating
4.39 +{
4.40 +protected:
4.41 + const char *_rm_filename;
4.42 +
4.43 + /* External pager configuration. */
4.44 +
4.45 + ExternalPager _exec_pager;
4.46 + ipc_server_config_type _config;
4.47 +
4.48 + Process _process;
4.49 +
4.50 + /* Stack and payload descriptions. */
4.51 +
4.52 + ExplicitSegment _rm_stack;
4.53 + Payload *_rm_payload;
4.54 +
4.55 + ExplicitSegment _program_stack;
4.56 + Payload *_program_payload;
4.57 +
4.58 + /* IPC gate for communication within the created task, plus allocated
4.59 + capability. */
4.60 +
4.61 + l4_cap_idx_t _ipc_gate, _ipc_gate_cap;
4.62 +
4.63 + /* Utility methods. */
4.64 +
4.65 + long start_pager();
4.66 +
4.67 + long init_region_mapper();
4.68 +
4.69 + long init_program(file_t *file);
4.70 +
4.71 + long init_external_pager();
4.72 +
4.73 + long configure_task();
4.74 +
4.75 + long create_ipc_gate();
4.76 +
4.77 + void init_region(struct exec_region *regions,
4.78 + struct ipc_mapped_cap *mapped_caps,
4.79 + struct exec_region &r, unsigned int &index);
4.80 +
4.81 + long start_region_mapper();
4.82 +
4.83 + long start_program(int argc, const char *argv[]);
4.84 +
4.85 +public:
4.86 + explicit ProcessCreating(const char *rm_filename);
4.87 +
4.88 + virtual long start(file_t *file, int argc, const char *argv[]);
4.89 +
4.90 + virtual void set_notifier(Notifier *notifier);
4.91 +};
4.92 +
4.93 +/* vim: tabstop=2 expandtab shiftwidth=2
4.94 +*/
5.1 --- a/libexec/include/exec/process_creator.h Sat Feb 18 22:48:39 2023 +0100
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,91 +0,0 @@
5.4 -/*
5.5 - * Support for executing code in new tasks and threads.
5.6 - *
5.7 - * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
5.8 - *
5.9 - * This program is free software; you can redistribute it and/or
5.10 - * modify it under the terms of the GNU General Public License as
5.11 - * published by the Free Software Foundation; either version 2 of
5.12 - * the License, or (at your option) any later version.
5.13 - *
5.14 - * This program is distributed in the hope that it will be useful,
5.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.17 - * GNU General Public License for more details.
5.18 - *
5.19 - * You should have received a copy of the GNU General Public License
5.20 - * along with this program; if not, write to the Free Software
5.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
5.22 - * Boston, MA 02110-1301, USA
5.23 - */
5.24 -
5.25 -#pragma once
5.26 -
5.27 -#include <exec/elf.h>
5.28 -#include <exec/external_pager.h>
5.29 -#include <exec/memory.h>
5.30 -#include <exec/process.h>
5.31 -#include <ipc/map.h>
5.32 -#include <ipc/server.h>
5.33 -
5.34 -
5.35 -
5.36 -/* Process creator. */
5.37 -
5.38 -class ProcessCreator
5.39 -{
5.40 -protected:
5.41 - const char *_rm_filename;
5.42 -
5.43 - /* External pager configuration. */
5.44 -
5.45 - ExternalPager _exec_pager;
5.46 - ipc_server_config_type _config;
5.47 -
5.48 - Process _process;
5.49 -
5.50 - /* Stack and payload descriptions. */
5.51 -
5.52 - ExplicitSegment _rm_stack;
5.53 - Payload *_rm_payload;
5.54 -
5.55 - ExplicitSegment _program_stack;
5.56 - Payload *_program_payload;
5.57 -
5.58 - /* IPC gate for communication within the created task, plus allocated
5.59 - capability. */
5.60 -
5.61 - l4_cap_idx_t _ipc_gate, _ipc_gate_cap;
5.62 -
5.63 - /* Utility methods. */
5.64 -
5.65 - long start_pager();
5.66 -
5.67 - long init_region_mapper();
5.68 -
5.69 - long init_program(file_t *file);
5.70 -
5.71 - long init_external_pager();
5.72 -
5.73 - long configure_task();
5.74 -
5.75 - long create_ipc_gate();
5.76 -
5.77 - void init_region(struct exec_region *regions,
5.78 - struct ipc_mapped_cap *mapped_caps,
5.79 - struct exec_region &r, unsigned int &index);
5.80 -
5.81 - long start_region_mapper();
5.82 -
5.83 - long start_program(int argc, const char *argv[]);
5.84 -
5.85 -public:
5.86 - explicit ProcessCreator(const char *rm_filename);
5.87 -
5.88 - long start(file_t *file, int argc, const char *argv[]);
5.89 -
5.90 - void set_notifier(Notifier *notifier);
5.91 -};
5.92 -
5.93 -/* vim: tabstop=2 expandtab shiftwidth=2
5.94 -*/
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/libexec/include/exec/process_creator_resource.h Thu Feb 23 23:49:26 2023 +0100
6.3 @@ -0,0 +1,54 @@
6.4 +/*
6.5 + * Support for executing code in new tasks and threads.
6.6 + *
6.7 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
6.8 + *
6.9 + * This program is free software; you can redistribute it and/or
6.10 + * modify it under the terms of the GNU General Public License as
6.11 + * published by the Free Software Foundation; either version 2 of
6.12 + * the License, or (at your option) any later version.
6.13 + *
6.14 + * This program is distributed in the hope that it will be useful,
6.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.17 + * GNU General Public License for more details.
6.18 + *
6.19 + * You should have received a copy of the GNU General Public License
6.20 + * along with this program; if not, write to the Free Software
6.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
6.22 + * Boston, MA 02110-1301, USA
6.23 + */
6.24 +
6.25 +#pragma once
6.26 +
6.27 +#include <exec/process_creating.h>
6.28 +#include <fsserver/resource.h>
6.29 +
6.30 +#include "process_creator_interface.h"
6.31 +
6.32 +
6.33 +
6.34 +/* Process creator. */
6.35 +
6.36 +class ProcessCreatorResource : public Resource, public ProcessCreating,
6.37 + public ProcessCreator
6.38 +{
6.39 +public:
6.40 + explicit ProcessCreatorResource(const char *rm_filename);
6.41 +
6.42 + virtual ~ProcessCreatorResource();
6.43 +
6.44 + /* Server details. */
6.45 +
6.46 + ipc_server_default_config_type config();
6.47 +
6.48 + void *interface()
6.49 + { return static_cast<ProcessCreator *>(this); }
6.50 +
6.51 + /* Process creator interface methods. */
6.52 +
6.53 + virtual long start(l4_cap_idx_t program, l4_cap_idx_t notifier);
6.54 +};
6.55 +
6.56 +/* vim: tabstop=2 expandtab shiftwidth=2
6.57 +*/
7.1 --- a/libexec/lib/src/Makefile Sat Feb 18 22:48:39 2023 +0100
7.2 +++ b/libexec/lib/src/Makefile Thu Feb 23 23:49:26 2023 +0100
7.3 @@ -9,7 +9,7 @@
7.4 IDL_DIR = $(PKGDIR)/../libsystypes/idl
7.5 IDL_MK_DIR = $(L4DIR)/idl4re/mk
7.6 IDL_BUILD_DIR = .
7.7 -IDL_EXPORT_DIR = .
7.8 +IDL_EXPORT_DIR = $(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)/exec
7.9
7.10 include $(IDL_MK_DIR)/idl.mk
7.11
7.12 @@ -17,7 +17,7 @@
7.13
7.14 CLIENT_INTERFACES_CC = dataspace mapped_file notifier
7.15
7.16 -SERVER_INTERFACES_CC = pager_object parent_pager_object
7.17 +SERVER_INTERFACES_CC = pager_object parent_pager_object process_creator
7.18
7.19 # Generated and plain source files.
7.20
7.21 @@ -30,8 +30,9 @@
7.22 PLAIN_SRC_CC = \
7.23 common.cc elf.cc external_pager.cc \
7.24 internal_pager.cc memory.cc pager.cc \
7.25 - process.cc process_creator.cc segment.cc \
7.26 - stack.cc
7.27 + process.cc process_creating.cc \
7.28 + process_creator_resource.cc \
7.29 + segment.cc stack.cc
7.30
7.31 # Normal definitions.
7.32
7.33 @@ -40,7 +41,7 @@
7.34 $(SERVER_INTERFACES_SRC_CC) \
7.35 $(PLAIN_SRC_CC)
7.36
7.37 -REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient
7.38 +REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient libfsserver
7.39
7.40 PRIVATE_INCDIR = $(PKGDIR)/include/exec $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
7.41
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/libexec/lib/src/process_creating.cc Thu Feb 23 23:49:26 2023 +0100
8.3 @@ -0,0 +1,324 @@
8.4 +/*
8.5 + * Support for executing code in new tasks and threads.
8.6 + *
8.7 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
8.8 + *
8.9 + * This program is free software; you can redistribute it and/or
8.10 + * modify it under the terms of the GNU General Public License as
8.11 + * published by the Free Software Foundation; either version 2 of
8.12 + * the License, or (at your option) any later version.
8.13 + *
8.14 + * This program is distributed in the hope that it will be useful,
8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.17 + * GNU General Public License for more details.
8.18 + *
8.19 + * You should have received a copy of the GNU General Public License
8.20 + * along with this program; if not, write to the Free Software
8.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
8.22 + * Boston, MA 02110-1301, USA
8.23 + */
8.24 +
8.25 +#include <l4/re/env.h>
8.26 +
8.27 +#include <ipc/cap_alloc.h>
8.28 +#include <ipc/map.h>
8.29 +
8.30 +#include <stdio.h>
8.31 +
8.32 +#include <pthread-l4.h>
8.33 +#include <pthread.h>
8.34 +
8.35 +#include "parent_pager_object_server.h"
8.36 +#include "process_creating.h"
8.37 +
8.38 +
8.39 +
8.40 +/* Process stack configuration. */
8.41 +
8.42 +static const offset_t initial_stack_size = 16 * L4_PAGESIZE;
8.43 +
8.44 +
8.45 +
8.46 +/* Initialise the process creator with the details of a region mapper. */
8.47 +
8.48 +ProcessCreating::ProcessCreating(const char *rm_filename)
8.49 +: _rm_filename(rm_filename),
8.50 + _exec_pager(0, 10 * L4_PAGESIZE),
8.51 + _rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW),
8.52 + _program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW)
8.53 +{
8.54 +}
8.55 +
8.56 +/* Start the system pager in a separate thread. */
8.57 +
8.58 +long ProcessCreating::start_pager()
8.59 +{
8.60 + pthread_t pager_thread;
8.61 + pthread_attr_t attr;
8.62 +
8.63 + pthread_attr_init(&attr);
8.64 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8.65 +
8.66 + ipc_server_init_for(&_config, ParentPagerObject, &_exec_pager);
8.67 +
8.68 + long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &_config);
8.69 +
8.70 + if (err)
8.71 + return err;
8.72 +
8.73 + return ipc_server_start_config_thread(&_config, pthread_l4_cap(pager_thread));
8.74 +}
8.75 +
8.76 +/* Initialise the memory segments of the region mapper. These are mapped into
8.77 + this task so that we may access them, allowing the external pager in this
8.78 + task to use them. */
8.79 +
8.80 +long ProcessCreating::init_region_mapper()
8.81 +{
8.82 + long err = exec_get_payload(_rm_filename, &_rm_payload, true);
8.83 +
8.84 + if (err)
8.85 + return err;
8.86 +
8.87 + return _rm_stack.allocate(true);
8.88 +}
8.89 +
8.90 +/* Initialise the memory segments of the actual program. These are not mapped
8.91 + into this task, instead being accessed by the region mapper in the new
8.92 + task. */
8.93 +
8.94 +long ProcessCreating::init_program(file_t *file)
8.95 +{
8.96 + long err = exec_get_payload_file(file, &_program_payload, false);
8.97 +
8.98 + if (err)
8.99 + return err;
8.100 +
8.101 + return _program_stack.allocate(true);
8.102 +}
8.103 +
8.104 +/* Initialise an external system-level pager serving the region mapper in a
8.105 + created task. The allocated regions requested by the region mapper are
8.106 + constrained to an area of memory that must not overlap with the area reserved
8.107 + for the program being run. */
8.108 +
8.109 +long ProcessCreating::init_external_pager()
8.110 +{
8.111 + /* Initialise pager regions for the region mapper. */
8.112 +
8.113 + for (unsigned int i = 0; i < _rm_payload->segments(); i++)
8.114 + {
8.115 + if (_rm_payload->segment(i)->loadable())
8.116 + _exec_pager.add(_rm_payload->segment(i)->region());
8.117 + }
8.118 +
8.119 + /* Include the region mapper's stack region. */
8.120 +
8.121 + _exec_pager.add(_rm_stack.region());
8.122 +
8.123 + /* Start the pager in a separate thread. */
8.124 +
8.125 + return start_pager();
8.126 +}
8.127 +
8.128 +/* Configure the environment for the task. */
8.129 +
8.130 +long ProcessCreating::configure_task()
8.131 +{
8.132 + long err = _process.configure_task();
8.133 +
8.134 + if (err)
8.135 + return err;
8.136 +
8.137 + return _process.set_parent(_config.server);
8.138 +}
8.139 +
8.140 +/* Create an unbound IPC gate for the region mapper and allocate it in the
8.141 + created process. */
8.142 +
8.143 +long ProcessCreating::create_ipc_gate()
8.144 +{
8.145 + _ipc_gate_cap = _process.allocate_cap();
8.146 + _ipc_gate = ipc_cap_alloc();
8.147 +
8.148 + if (l4_is_invalid_cap(_ipc_gate))
8.149 + return -L4_ENOMEM;
8.150 +
8.151 + return l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0));
8.152 +}
8.153 +
8.154 +/* Initialise and assign a region in a list to the created process. */
8.155 +
8.156 +void ProcessCreating::init_region(struct exec_region *regions,
8.157 + struct ipc_mapped_cap *mapped_caps,
8.158 + struct exec_region &r, unsigned int &index)
8.159 +{
8.160 + l4_cap_idx_t mapped_cap = _process.allocate_cap();
8.161 +
8.162 + mapped_caps[index] = (struct ipc_mapped_cap) {mapped_cap, r.ds, L4_CAP_FPAGE_RWS, 0};
8.163 +
8.164 + /* Change the region definition to use the allocated capability in the created
8.165 + process. */
8.166 +
8.167 + regions[index] = r;
8.168 + regions[index].ds = mapped_cap;
8.169 + index++;
8.170 +}
8.171 +
8.172 +/* Initialise the region mapper with details of the payload program regions
8.173 + and of the associated capabilities, configure the region mapper thread,
8.174 + populate its stack, and start the thread. */
8.175 +
8.176 +long ProcessCreating::start_region_mapper()
8.177 +{
8.178 + /* Define regions employing dataspaces to provide program segments. */
8.179 +
8.180 + struct exec_region rm_regions[_rm_payload->segments() + 2];
8.181 +
8.182 + /* Define capabilities for mapping, including region dataspace capabilities,
8.183 + the stack dataspace capability, and the server capability. */
8.184 +
8.185 + struct ipc_mapped_cap rm_mapped_caps[_rm_payload->segments() + 3];
8.186 +
8.187 + /* Here, the arrays are sized for the maximum number of regions and
8.188 + capabilities, but in practice only the loadable segments are used, leaving
8.189 + fewer elements utilised. A terminating entry is employed to indicate the
8.190 + limit of utilised elements. */
8.191 +
8.192 + unsigned int rm_index = 0;
8.193 +
8.194 + for (unsigned int i = 0; i < _program_payload->segments(); i++)
8.195 + {
8.196 + Segment *s = _program_payload->segment(i);
8.197 +
8.198 + if (s->loadable())
8.199 + init_region(rm_regions, rm_mapped_caps, s->exec_region(), rm_index);
8.200 + }
8.201 +
8.202 + /* Introduce the stack region and capability. */
8.203 +
8.204 + init_region(rm_regions, rm_mapped_caps, _program_stack.exec_region(), rm_index);
8.205 +
8.206 + /* Terminate the region array. */
8.207 +
8.208 + rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
8.209 +
8.210 + /* Introduce the server capability and terminate the capability array. */
8.211 +
8.212 + rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
8.213 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
8.214 +
8.215 + /* Map these additional capabilities. */
8.216 +
8.217 + _process.map_capabilities(rm_mapped_caps, false);
8.218 +
8.219 + /* Define the IPC gate as an initial capability to be acquired by the region
8.220 + mapper via the l4re_env API. The capability index is assigned above when
8.221 + mapping the capability and encoded in the entry below. */
8.222 +
8.223 + l4re_env_cap_entry_t rm_init_caps[] = {
8.224 + l4re_env_cap_entry_t("server", _ipc_gate_cap, L4_CAP_FPAGE_RWS),
8.225 + l4re_env_cap_entry_t()
8.226 + };
8.227 +
8.228 + /* NOTE: Environment vector is currently not defined. */
8.229 +
8.230 + const char *envp[] = {NULL};
8.231 +
8.232 + /* Configure the environment for the thread, specifying the pager (and
8.233 + exception handler plus region mapper). */
8.234 +
8.235 + long err = _process.configure_thread(_config.server);
8.236 +
8.237 + if (err)
8.238 + return err;
8.239 +
8.240 + /* Populate a thread stack with argument and environment details for the
8.241 + region mapper, plus the initial server capability and region details. */
8.242 +
8.243 + const char *argv[] = {_rm_filename};
8.244 + Stack rm_st(_rm_stack);
8.245 +
8.246 + rm_st.set_init_caps(rm_init_caps);
8.247 + rm_st.set_regions(rm_regions);
8.248 + rm_st.populate(1, argv, envp);
8.249 +
8.250 + /* Start the region mapper thread in the appropriate stack. */
8.251 +
8.252 + return _process.thread_start(_rm_payload->entry_point(), rm_st);
8.253 +}
8.254 +
8.255 +/* Configure a thread for a program, populate its stack, and start the
8.256 + thread. */
8.257 +
8.258 +long ProcessCreating::start_program(int argc, const char *argv[])
8.259 +{
8.260 + /* NOTE: Environment vector is currently not defined. */
8.261 +
8.262 + const char *envp[] = {NULL};
8.263 +
8.264 + /* Configure the environment for the thread, specifying the pager (and
8.265 + exception handler plus region mapper). */
8.266 +
8.267 + long err = _process.configure_thread(_ipc_gate, _ipc_gate_cap);
8.268 +
8.269 + if (err)
8.270 + return err;
8.271 +
8.272 + /* Populate a thread stack with argument and environment details for the
8.273 + actual program. The server capability should be assigned to the region
8.274 + mapper capability slot already. */
8.275 +
8.276 + Stack program_st(_program_stack);
8.277 +
8.278 + program_st.populate(argc, argv, envp);
8.279 +
8.280 + /* Start the program thread in the appropriate stack. */
8.281 +
8.282 + return _process.thread_start(_program_payload->entry_point(), program_st);
8.283 +}
8.284 +
8.285 +/* Start a new process for the given payload, providing the indicated program
8.286 + arguments. */
8.287 +
8.288 +long ProcessCreating::start(file_t *file, int argc, const char *argv[])
8.289 +{
8.290 + long err;
8.291 +
8.292 + err = init_region_mapper();
8.293 + if (err)
8.294 + return err;
8.295 +
8.296 + err = init_program(file);
8.297 + if (err)
8.298 + return err;
8.299 +
8.300 + err = init_external_pager();
8.301 + if (err)
8.302 + return err;
8.303 +
8.304 + err = configure_task();
8.305 + if (err)
8.306 + return err;
8.307 +
8.308 + err = create_ipc_gate();
8.309 + if (err)
8.310 + return err;
8.311 +
8.312 + err = start_region_mapper();
8.313 + if (err)
8.314 + return err;
8.315 +
8.316 + return start_program(argc, argv);
8.317 +}
8.318 +
8.319 +/* Set the given notifier on the system-level pager for a process. */
8.320 +
8.321 +void ProcessCreating::set_notifier(Notifier *notifier)
8.322 +{
8.323 + _exec_pager.set_notifier(notifier);
8.324 +}
8.325 +
8.326 +/* vim: tabstop=2 expandtab shiftwidth=2
8.327 +*/
9.1 --- a/libexec/lib/src/process_creator.cc Sat Feb 18 22:48:39 2023 +0100
9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
9.3 @@ -1,324 +0,0 @@
9.4 -/*
9.5 - * Support for executing code in new tasks and threads.
9.6 - *
9.7 - * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
9.8 - *
9.9 - * This program is free software; you can redistribute it and/or
9.10 - * modify it under the terms of the GNU General Public License as
9.11 - * published by the Free Software Foundation; either version 2 of
9.12 - * the License, or (at your option) any later version.
9.13 - *
9.14 - * This program is distributed in the hope that it will be useful,
9.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.17 - * GNU General Public License for more details.
9.18 - *
9.19 - * You should have received a copy of the GNU General Public License
9.20 - * along with this program; if not, write to the Free Software
9.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
9.22 - * Boston, MA 02110-1301, USA
9.23 - */
9.24 -
9.25 -#include <l4/re/env.h>
9.26 -
9.27 -#include <ipc/cap_alloc.h>
9.28 -#include <ipc/map.h>
9.29 -
9.30 -#include <stdio.h>
9.31 -
9.32 -#include <pthread-l4.h>
9.33 -#include <pthread.h>
9.34 -
9.35 -#include "parent_pager_object_server.h"
9.36 -#include "process_creator.h"
9.37 -
9.38 -
9.39 -
9.40 -/* Process stack configuration. */
9.41 -
9.42 -static const offset_t initial_stack_size = 16 * L4_PAGESIZE;
9.43 -
9.44 -
9.45 -
9.46 -/* Initialise the process creator with the details of a region mapper. */
9.47 -
9.48 -ProcessCreator::ProcessCreator(const char *rm_filename)
9.49 -: _rm_filename(rm_filename),
9.50 - _exec_pager(0, 10 * L4_PAGESIZE),
9.51 - _rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW),
9.52 - _program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW)
9.53 -{
9.54 -}
9.55 -
9.56 -/* Start the system pager in a separate thread. */
9.57 -
9.58 -long ProcessCreator::start_pager()
9.59 -{
9.60 - pthread_t pager_thread;
9.61 - pthread_attr_t attr;
9.62 -
9.63 - pthread_attr_init(&attr);
9.64 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
9.65 -
9.66 - ipc_server_init_for(&_config, ParentPagerObject, &_exec_pager);
9.67 -
9.68 - long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &_config);
9.69 -
9.70 - if (err)
9.71 - return err;
9.72 -
9.73 - return ipc_server_start_config_thread(&_config, pthread_l4_cap(pager_thread));
9.74 -}
9.75 -
9.76 -/* Initialise the memory segments of the region mapper. These are mapped into
9.77 - this task so that we may access them, allowing the external pager in this
9.78 - task to use them. */
9.79 -
9.80 -long ProcessCreator::init_region_mapper()
9.81 -{
9.82 - long err = exec_get_payload(_rm_filename, &_rm_payload, true);
9.83 -
9.84 - if (err)
9.85 - return err;
9.86 -
9.87 - return _rm_stack.allocate(true);
9.88 -}
9.89 -
9.90 -/* Initialise the memory segments of the actual program. These are not mapped
9.91 - into this task, instead being accessed by the region mapper in the new
9.92 - task. */
9.93 -
9.94 -long ProcessCreator::init_program(file_t *file)
9.95 -{
9.96 - long err = exec_get_payload_file(file, &_program_payload, false);
9.97 -
9.98 - if (err)
9.99 - return err;
9.100 -
9.101 - return _program_stack.allocate(true);
9.102 -}
9.103 -
9.104 -/* Initialise an external system-level pager serving the region mapper in a
9.105 - created task. The allocated regions requested by the region mapper are
9.106 - constrained to an area of memory that must not overlap with the area reserved
9.107 - for the program being run. */
9.108 -
9.109 -long ProcessCreator::init_external_pager()
9.110 -{
9.111 - /* Initialise pager regions for the region mapper. */
9.112 -
9.113 - for (unsigned int i = 0; i < _rm_payload->segments(); i++)
9.114 - {
9.115 - if (_rm_payload->segment(i)->loadable())
9.116 - _exec_pager.add(_rm_payload->segment(i)->region());
9.117 - }
9.118 -
9.119 - /* Include the region mapper's stack region. */
9.120 -
9.121 - _exec_pager.add(_rm_stack.region());
9.122 -
9.123 - /* Start the pager in a separate thread. */
9.124 -
9.125 - return start_pager();
9.126 -}
9.127 -
9.128 -/* Configure the environment for the task. */
9.129 -
9.130 -long ProcessCreator::configure_task()
9.131 -{
9.132 - long err = _process.configure_task();
9.133 -
9.134 - if (err)
9.135 - return err;
9.136 -
9.137 - return _process.set_parent(_config.server);
9.138 -}
9.139 -
9.140 -/* Create an unbound IPC gate for the region mapper and allocate it in the
9.141 - created process. */
9.142 -
9.143 -long ProcessCreator::create_ipc_gate()
9.144 -{
9.145 - _ipc_gate_cap = _process.allocate_cap();
9.146 - _ipc_gate = ipc_cap_alloc();
9.147 -
9.148 - if (l4_is_invalid_cap(_ipc_gate))
9.149 - return -L4_ENOMEM;
9.150 -
9.151 - return l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0));
9.152 -}
9.153 -
9.154 -/* Initialise and assign a region in a list to the created process. */
9.155 -
9.156 -void ProcessCreator::init_region(struct exec_region *regions,
9.157 - struct ipc_mapped_cap *mapped_caps,
9.158 - struct exec_region &r, unsigned int &index)
9.159 -{
9.160 - l4_cap_idx_t mapped_cap = _process.allocate_cap();
9.161 -
9.162 - mapped_caps[index] = (struct ipc_mapped_cap) {mapped_cap, r.ds, L4_CAP_FPAGE_RWS, 0};
9.163 -
9.164 - /* Change the region definition to use the allocated capability in the created
9.165 - process. */
9.166 -
9.167 - regions[index] = r;
9.168 - regions[index].ds = mapped_cap;
9.169 - index++;
9.170 -}
9.171 -
9.172 -/* Initialise the region mapper with details of the payload program regions
9.173 - and of the associated capabilities, configure the region mapper thread,
9.174 - populate its stack, and start the thread. */
9.175 -
9.176 -long ProcessCreator::start_region_mapper()
9.177 -{
9.178 - /* Define regions employing dataspaces to provide program segments. */
9.179 -
9.180 - struct exec_region rm_regions[_rm_payload->segments() + 2];
9.181 -
9.182 - /* Define capabilities for mapping, including region dataspace capabilities,
9.183 - the stack dataspace capability, and the server capability. */
9.184 -
9.185 - struct ipc_mapped_cap rm_mapped_caps[_rm_payload->segments() + 3];
9.186 -
9.187 - /* Here, the arrays are sized for the maximum number of regions and
9.188 - capabilities, but in practice only the loadable segments are used, leaving
9.189 - fewer elements utilised. A terminating entry is employed to indicate the
9.190 - limit of utilised elements. */
9.191 -
9.192 - unsigned int rm_index = 0;
9.193 -
9.194 - for (unsigned int i = 0; i < _program_payload->segments(); i++)
9.195 - {
9.196 - Segment *s = _program_payload->segment(i);
9.197 -
9.198 - if (s->loadable())
9.199 - init_region(rm_regions, rm_mapped_caps, s->exec_region(), rm_index);
9.200 - }
9.201 -
9.202 - /* Introduce the stack region and capability. */
9.203 -
9.204 - init_region(rm_regions, rm_mapped_caps, _program_stack.exec_region(), rm_index);
9.205 -
9.206 - /* Terminate the region array. */
9.207 -
9.208 - rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
9.209 -
9.210 - /* Introduce the server capability and terminate the capability array. */
9.211 -
9.212 - rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
9.213 - rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
9.214 -
9.215 - /* Map these additional capabilities. */
9.216 -
9.217 - _process.map_capabilities(rm_mapped_caps, false);
9.218 -
9.219 - /* Define the IPC gate as an initial capability to be acquired by the region
9.220 - mapper via the l4re_env API. The capability index is assigned above when
9.221 - mapping the capability and encoded in the entry below. */
9.222 -
9.223 - l4re_env_cap_entry_t rm_init_caps[] = {
9.224 - l4re_env_cap_entry_t("server", _ipc_gate_cap, L4_CAP_FPAGE_RWS),
9.225 - l4re_env_cap_entry_t()
9.226 - };
9.227 -
9.228 - /* NOTE: Environment vector is currently not defined. */
9.229 -
9.230 - const char *envp[] = {NULL};
9.231 -
9.232 - /* Configure the environment for the thread, specifying the pager (and
9.233 - exception handler plus region mapper). */
9.234 -
9.235 - long err = _process.configure_thread(_config.server);
9.236 -
9.237 - if (err)
9.238 - return err;
9.239 -
9.240 - /* Populate a thread stack with argument and environment details for the
9.241 - region mapper, plus the initial server capability and region details. */
9.242 -
9.243 - const char *argv[] = {_rm_filename};
9.244 - Stack rm_st(_rm_stack);
9.245 -
9.246 - rm_st.set_init_caps(rm_init_caps);
9.247 - rm_st.set_regions(rm_regions);
9.248 - rm_st.populate(1, argv, envp);
9.249 -
9.250 - /* Start the region mapper thread in the appropriate stack. */
9.251 -
9.252 - return _process.thread_start(_rm_payload->entry_point(), rm_st);
9.253 -}
9.254 -
9.255 -/* Configure a thread for a program, populate its stack, and start the
9.256 - thread. */
9.257 -
9.258 -long ProcessCreator::start_program(int argc, const char *argv[])
9.259 -{
9.260 - /* NOTE: Environment vector is currently not defined. */
9.261 -
9.262 - const char *envp[] = {NULL};
9.263 -
9.264 - /* Configure the environment for the thread, specifying the pager (and
9.265 - exception handler plus region mapper). */
9.266 -
9.267 - long err = _process.configure_thread(_ipc_gate, _ipc_gate_cap);
9.268 -
9.269 - if (err)
9.270 - return err;
9.271 -
9.272 - /* Populate a thread stack with argument and environment details for the
9.273 - actual program. The server capability should be assigned to the region
9.274 - mapper capability slot already. */
9.275 -
9.276 - Stack program_st(_program_stack);
9.277 -
9.278 - program_st.populate(argc, argv, envp);
9.279 -
9.280 - /* Start the program thread in the appropriate stack. */
9.281 -
9.282 - return _process.thread_start(_program_payload->entry_point(), program_st);
9.283 -}
9.284 -
9.285 -/* Start a new process for the given payload, providing the indicated program
9.286 - arguments. */
9.287 -
9.288 -long ProcessCreator::start(file_t *file, int argc, const char *argv[])
9.289 -{
9.290 - long err;
9.291 -
9.292 - err = init_region_mapper();
9.293 - if (err)
9.294 - return err;
9.295 -
9.296 - err = init_program(file);
9.297 - if (err)
9.298 - return err;
9.299 -
9.300 - err = init_external_pager();
9.301 - if (err)
9.302 - return err;
9.303 -
9.304 - err = configure_task();
9.305 - if (err)
9.306 - return err;
9.307 -
9.308 - err = create_ipc_gate();
9.309 - if (err)
9.310 - return err;
9.311 -
9.312 - err = start_region_mapper();
9.313 - if (err)
9.314 - return err;
9.315 -
9.316 - return start_program(argc, argv);
9.317 -}
9.318 -
9.319 -/* Set the given notifier on the system-level pager for a process. */
9.320 -
9.321 -void ProcessCreator::set_notifier(Notifier *notifier)
9.322 -{
9.323 - _exec_pager.set_notifier(notifier);
9.324 -}
9.325 -
9.326 -/* vim: tabstop=2 expandtab shiftwidth=2
9.327 -*/
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/libexec/lib/src/process_creator_resource.cc Thu Feb 23 23:49:26 2023 +0100
10.3 @@ -0,0 +1,82 @@
10.4 +/*
10.5 + * A resource offering support for creating processes.
10.6 + *
10.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
10.8 + *
10.9 + * This program is free software; you can redistribute it and/or
10.10 + * modify it under the terms of the GNU General Public License as
10.11 + * published by the Free Software Foundation; either version 2 of
10.12 + * the License, or (at your option) any later version.
10.13 + *
10.14 + * This program is distributed in the hope that it will be useful,
10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.17 + * GNU General Public License for more details.
10.18 + *
10.19 + * You should have received a copy of the GNU General Public License
10.20 + * along with this program; if not, write to the Free Software
10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
10.22 + * Boston, MA 02110-1301, USA
10.23 + */
10.24 +
10.25 +#include <systypes/fcntl.h>
10.26 +
10.27 +#include "process_creating.h"
10.28 +#include "process_creator_resource.h"
10.29 +
10.30 +#include "notifier_client.h"
10.31 +#include "process_creator_server.h"
10.32 +
10.33 +
10.34 +
10.35 +/* Support for creating processes. */
10.36 +
10.37 +ProcessCreatorResource::ProcessCreatorResource(const char *rm_filename)
10.38 +: ProcessCreating(rm_filename)
10.39 +{
10.40 +}
10.41 +
10.42 +ProcessCreatorResource::~ProcessCreatorResource()
10.43 +{
10.44 +}
10.45 +
10.46 +ipc_server_default_config_type ProcessCreatorResource::config()
10.47 +{
10.48 + return config_ProcessCreator;
10.49 +}
10.50 +
10.51 +
10.52 +
10.53 +/* ProcessCreator interface methods. */
10.54 +
10.55 +long ProcessCreatorResource::start(l4_cap_idx_t program, l4_cap_idx_t notifier)
10.56 +{
10.57 + file_t file;
10.58 +
10.59 + file_init(&file);
10.60 + file.ref = program;
10.61 +
10.62 + /* Obtain a distinct and usable file object. */
10.63 +
10.64 + file_t *program_file = client_reopen(&file, O_RDONLY);
10.65 +
10.66 + /* NOTE: To be replaced with the actual arguments, perhaps involving a
10.67 + context object. */
10.68 +
10.69 + const char *argv[] = {"<program>"};
10.70 +
10.71 + long err = ProcessCreating::start(program_file, 1, argv);
10.72 +
10.73 + if (err)
10.74 + return err;
10.75 +
10.76 + /* NOTE: To be managed properly. */
10.77 +
10.78 + client_Notifier *n = new client_Notifier(notifier);
10.79 +
10.80 + set_notifier(n);
10.81 +
10.82 + return L4_EOK;
10.83 +}
10.84 +
10.85 +// vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/libfsclient/include/fsclient/notifier.h Sat Feb 18 22:48:39 2023 +0100
11.2 +++ b/libfsclient/include/fsclient/notifier.h Thu Feb 23 23:49:26 2023 +0100
11.3 @@ -106,6 +106,10 @@
11.4
11.5 virtual long unsubscribe(notifiable_t *object);
11.6
11.7 + virtual long get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create);
11.8 +
11.9 + virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
11.10 +
11.11 /* Event handling support. */
11.12
11.13 virtual void mainloop();
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/libfsclient/include/fsclient/process.h Thu Feb 23 23:49:26 2023 +0100
12.3 @@ -0,0 +1,78 @@
12.4 +/*
12.5 + * Process-related convenience functions and types.
12.6 + *
12.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
12.8 + *
12.9 + * This program is free software; you can redistribute it and/or
12.10 + * modify it under the terms of the GNU General Public License as
12.11 + * published by the Free Software Foundation; either version 2 of
12.12 + * the License, or (at your option) any later version.
12.13 + *
12.14 + * This program is distributed in the hope that it will be useful,
12.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
12.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12.17 + * GNU General Public License for more details.
12.18 + *
12.19 + * You should have received a copy of the GNU General Public License
12.20 + * along with this program; if not, write to the Free Software
12.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
12.22 + * Boston, MA 02110-1301, USA
12.23 + */
12.24 +
12.25 +#pragma once
12.26 +
12.27 +#include <l4/sys/types.h>
12.28 +
12.29 +#include <fsclient/file.h>
12.30 +#include <systypes/base.h>
12.31 +
12.32 +
12.33 +
12.34 +/* C compatibility types (defined in the implementation). */
12.35 +
12.36 +struct process_notifier;
12.37 +
12.38 +typedef struct process_notifier process_notifier_t;
12.39 +
12.40 +
12.41 +
12.42 +EXTERN_C_BEGIN
12.43 +
12.44 +/* File access abstraction compatible with notifiable_base_t. */
12.45 +
12.46 +typedef struct
12.47 +{
12.48 + /* File object reference. */
12.49 +
12.50 + l4_cap_idx_t ref;
12.51 +
12.52 + /* Notification structure. */
12.53 +
12.54 + notifiable_t notifiable;
12.55 +
12.56 +} process_t;
12.57 +
12.58 +
12.59 +
12.60 +/* Principal functions. */
12.61 +
12.62 +process_t *process_new();
12.63 +void process_init(process_t *process);
12.64 +long process_start(process_t *process, file_t *file, process_notifier_t *notifier);
12.65 +
12.66 +/* Notification support. */
12.67 +
12.68 +notifiable_t *process_notifiable(process_t *process);
12.69 +notify_flags_t process_notifications(process_t *process);
12.70 +notify_values_t process_notification_values(process_t *process);
12.71 +void process_notify_close(process_notifier_t *notifier);
12.72 +process_notifier_t *process_notify_local();
12.73 +process_notifier_t *process_notify_task();
12.74 +long process_notify_get_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t *endpoint);
12.75 +long process_notify_remove_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t endpoint);
12.76 +long process_notify_wait_process(process_t *process, process_notifier_t *notifier);
12.77 +long process_notify_wait_processes(process_t **process, process_notifier_t *notifier);
12.78 +
12.79 +EXTERN_C_END
12.80 +
12.81 +// vim: tabstop=2 expandtab shiftwidth=2
13.1 --- a/libfsclient/lib/src/Makefile Sat Feb 18 22:48:39 2023 +0100
13.2 +++ b/libfsclient/lib/src/Makefile Thu Feb 23 23:49:26 2023 +0100
13.3 @@ -17,13 +17,13 @@
13.4
13.5 CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \
13.6 mapped_file notifier notification opener \
13.7 - opener_context pipe pipe_opener
13.8 + opener_context pipe pipe_opener process_creator
13.9
13.10 # Generated and plain source files.
13.11
13.12 CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
13.13
13.14 -PLAIN_SRC_CC = client.cc file.cc notifier.cc
13.15 +PLAIN_SRC_CC = client.cc file.cc notifier.cc process.cc
13.16
13.17 # Normal definitions.
13.18
14.1 --- a/libfsclient/lib/src/notifier.cc Sat Feb 18 22:48:39 2023 +0100
14.2 +++ b/libfsclient/lib/src/notifier.cc Thu Feb 23 23:49:26 2023 +0100
14.3 @@ -188,51 +188,29 @@
14.4
14.5 long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
14.6 {
14.7 - /* Acquire the lock for state lookup. */
14.8 -
14.9 - std::unique_lock<std::mutex> state_guard(_state_lock);
14.10 -
14.11 - ObjectNotificationState &state = object_state(object, true);
14.12 - long err;
14.13 -
14.14 - /* Create a notification endpoint, if necessary. */
14.15 + l4_cap_idx_t endpoint;
14.16 + long err = get_endpoint(object, &endpoint, true);
14.17
14.18 - if (state.is_null())
14.19 - {
14.20 - err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
14.21 + if (err)
14.22 + return err;
14.23
14.24 - if (err)
14.25 - return err;
14.26 - }
14.27 -
14.28 - /* Subscribe, sending the notification endpoint. */
14.29 + /* Subscribe, sending the notification endpoint via the principal reference
14.30 + for the object. */
14.31
14.32 client_Notification notify(object->base->ref);
14.33
14.34 - err = notify.subscribe(state.endpoint, flags);
14.35 -
14.36 - if (err)
14.37 - {
14.38 - ipc_cap_free_um(state.endpoint);
14.39 - _state.erase(object);
14.40 - return err;
14.41 - }
14.42 -
14.43 - return L4_EOK;
14.44 + return notify.subscribe(endpoint, flags);
14.45 }
14.46
14.47 /* Unsubscribe from notification events on an object. */
14.48
14.49 long ObjectNotifier::unsubscribe(notifiable_t *object)
14.50 {
14.51 - /* Acquire the lock for state lookup. */
14.52 -
14.53 - std::unique_lock<std::mutex> state_guard(_state_lock);
14.54 + l4_cap_idx_t endpoint;
14.55 + long err = get_endpoint(object, &endpoint, false);
14.56
14.57 - ObjectNotificationState &state = object_state(object, false);
14.58 -
14.59 - if (state.is_null())
14.60 - return -L4_EINVAL;
14.61 + if (err)
14.62 + return err;
14.63
14.64 /* Unsubscribe via the notification interface. */
14.65
14.66 @@ -240,7 +218,46 @@
14.67
14.68 notify.unsubscribe();
14.69
14.70 - ipc_cap_free_um(state.endpoint);
14.71 + return remove_endpoint(object, endpoint);
14.72 +}
14.73 +
14.74 +/* Obtain a notification endpoint for an object. */
14.75 +
14.76 +long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create)
14.77 +{
14.78 + /* Acquire the lock for state lookup. */
14.79 +
14.80 + std::unique_lock<std::mutex> state_guard(_state_lock);
14.81 +
14.82 + ObjectNotificationState &state = object_state(object, create);
14.83 +
14.84 + /* Create a notification endpoint, if necessary. */
14.85 +
14.86 + if (state.is_null())
14.87 + {
14.88 + if (create)
14.89 + {
14.90 + long err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
14.91 +
14.92 + if (err)
14.93 + return err;
14.94 + }
14.95 + else
14.96 + return -L4_ENOENT;
14.97 + }
14.98 +
14.99 + *endpoint = state.endpoint;
14.100 + return L4_EOK;
14.101 +}
14.102 +
14.103 +/* Remove a notification endpoint for an object. */
14.104 +
14.105 +long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint)
14.106 +{
14.107 + if (l4_is_invalid_cap(endpoint))
14.108 + return -L4_EINVAL;
14.109 +
14.110 + ipc_cap_free_um(endpoint);
14.111
14.112 _state.erase(object);
14.113
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/libfsclient/lib/src/process.cc Thu Feb 23 23:49:26 2023 +0100
15.3 @@ -0,0 +1,197 @@
15.4 +/*
15.5 + * Process-related convenience functions.
15.6 + *
15.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
15.8 + *
15.9 + * This program is free software; you can redistribute it and/or
15.10 + * modify it under the terms of the GNU General Public License as
15.11 + * published by the Free Software Foundation; either version 2 of
15.12 + * the License, or (at your option) any later version.
15.13 + *
15.14 + * This program is distributed in the hope that it will be useful,
15.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
15.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15.17 + * GNU General Public License for more details.
15.18 + *
15.19 + * You should have received a copy of the GNU General Public License
15.20 + * along with this program; if not, write to the Free Software
15.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
15.22 + * Boston, MA 02110-1301, USA
15.23 + */
15.24 +
15.25 +#include <ipc/cap_alloc.h>
15.26 +#include <ipc/mem_ipc.h>
15.27 +
15.28 +#include <stdio.h>
15.29 +#include <stdlib.h>
15.30 +
15.31 +#include "process_creator_client.h"
15.32 +
15.33 +#include "file.h"
15.34 +#include "process.h"
15.35 +#include "notifier.h"
15.36 +
15.37 +
15.38 +
15.39 +/* Create a new process object. */
15.40 +
15.41 +process_t *process_new()
15.42 +{
15.43 + process_t *process = (process_t *) malloc(sizeof(process_t));
15.44 +
15.45 + if (process == NULL)
15.46 + return NULL;
15.47 +
15.48 + process_init(process);
15.49 + return process;
15.50 +}
15.51 +
15.52 +/* Initialise the given process structure. */
15.53 +
15.54 +void process_init(process_t *process)
15.55 +{
15.56 + process->ref = L4_INVALID_CAP;
15.57 +
15.58 + /* Initialise the notifiable section of the structure. */
15.59 +
15.60 + process->notifiable.notifications = 0;
15.61 + process->notifiable.base = (notifiable_base_t *) process;
15.62 +}
15.63 +
15.64 +/* Start a process using the given file as payload.
15.65 + NOTE: This does not yet communicate arguments or obtain input/output
15.66 + pipes. */
15.67 +
15.68 +long process_start(process_t *process, file_t *file, process_notifier_t *notifier)
15.69 +{
15.70 + l4_cap_idx_t server = l4re_env_get_cap("pserver");
15.71 +
15.72 + if (l4_is_invalid_cap(server))
15.73 + return -L4_ENOMEM;
15.74 +
15.75 + /* Obtain a notification endpoint. */
15.76 +
15.77 + l4_cap_idx_t endpoint;
15.78 + long err = process_notify_get_endpoint(process, notifier, &endpoint);
15.79 +
15.80 + if (err)
15.81 + return err;
15.82 +
15.83 + /* Obtain a client for the process creator. */
15.84 +
15.85 + client_ProcessCreator creator(server);
15.86 +
15.87 + /* Start the process, supplying the given endpoint. */
15.88 +
15.89 + return creator.start(file->ref, endpoint);
15.90 +}
15.91 +
15.92 +
15.93 +
15.94 +/* NOTE: Much of the code below could be unified with the file-related
15.95 + notification code. */
15.96 +
15.97 +/* Opaque notifier type for process_notifier_t. */
15.98 +
15.99 +struct process_notifier
15.100 +{
15.101 + ObjectNotifier *obj;
15.102 +};
15.103 +
15.104 +/* Conversion to the generic notification types. */
15.105 +
15.106 +notifiable_t *process_notifiable(process_t *process)
15.107 +{
15.108 + return &process->notifiable;
15.109 +}
15.110 +
15.111 +/* Return the notification flags for a process. */
15.112 +
15.113 +notify_flags_t process_notifications(process_t *process)
15.114 +{
15.115 + return process->notifiable.notifications;
15.116 +}
15.117 +
15.118 +/* Return the notification values for a process. */
15.119 +
15.120 +notify_values_t process_notification_values(process_t *process)
15.121 +{
15.122 + return process->notifiable.values;
15.123 +}
15.124 +
15.125 +/* Close a notifier object. */
15.126 +
15.127 +void process_notify_close(process_notifier_t *notifier)
15.128 +{
15.129 + delete notifier->obj;
15.130 + delete notifier;
15.131 +}
15.132 +
15.133 +/* Obtain a local notifier object. */
15.134 +
15.135 +process_notifier_t *process_notify_local()
15.136 +{
15.137 + process_notifier_t *notifier = new process_notifier_t;
15.138 +
15.139 + notifier->obj = notifier_get_local_notifier();
15.140 + return notifier;
15.141 +}
15.142 +
15.143 +/* Obtain the task-wide notifier object. */
15.144 +
15.145 +process_notifier_t *process_notify_task()
15.146 +{
15.147 + process_notifier_t *notifier = new process_notifier_t;
15.148 +
15.149 + notifier->obj = notifier_get_task_notifier();
15.150 + return notifier;
15.151 +}
15.152 +
15.153 +/* Subscribe to notification events on a process. */
15.154 +
15.155 +long process_notify_get_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t *endpoint)
15.156 +{
15.157 + return notifier->obj->get_endpoint(process_notifiable(process), endpoint, true);
15.158 +}
15.159 +
15.160 +/* Unsubscribe from notification events on a process. */
15.161 +
15.162 +long process_notify_remove_endpoint(process_t *process, process_notifier_t *notifier, l4_cap_idx_t endpoint)
15.163 +{
15.164 + return notifier->obj->remove_endpoint(process_notifiable(process), endpoint);
15.165 +}
15.166 +
15.167 +/* Wait for a notification event on a process. */
15.168 +
15.169 +long process_notify_wait_process(process_t *process, process_notifier_t *notifier)
15.170 +{
15.171 + SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj);
15.172 + long err = specific_notifier->wait_object(process_notifiable(process));
15.173 +
15.174 + /* Unsubscribe if a closure notification has been received. */
15.175 +
15.176 + //if (!err && (process->notifiable.notifications & NOTIFY_PEER_CLOSED))
15.177 + //process_notify_unsubscribe(process, notifier);
15.178 +
15.179 + return err;
15.180 +}
15.181 +
15.182 +/* Wait for notification events on processes. */
15.183 +
15.184 +long process_notify_wait_processes(process_t **process, process_notifier_t *notifier)
15.185 +{
15.186 + GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj);
15.187 + notifiable_t *notifiable;
15.188 + long err = general_notifier->wait(¬ifiable);
15.189 +
15.190 + *process = (process_t *) notifiable->base;
15.191 +
15.192 + /* Unsubscribe if a closure notification has been received. */
15.193 +
15.194 + //if (!err && ((*file)->notifiable.notifications & NOTIFY_PEER_CLOSED))
15.195 + //file_notify_unsubscribe(*file, notifier);
15.196 +
15.197 + return err;
15.198 +}
15.199 +
15.200 +// vim: tabstop=2 expandtab shiftwidth=2
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/libsystypes/idl/process_creator.idl Thu Feb 23 23:49:26 2023 +0100
16.3 @@ -0,0 +1,7 @@
16.4 +interface ProcessCreator
16.5 +{
16.6 + /* Start a process, using the given file reference as the payload, indicating
16.7 + a notifier to receive notifications. */
16.8 +
16.9 + [opcode(30)] void start(in cap program, in cap notifier);
16.10 +};
17.1 --- a/servers/Control Sat Feb 18 22:48:39 2023 +0100
17.2 +++ b/servers/Control Thu Feb 23 23:49:26 2023 +0100
17.3 @@ -1,3 +1,3 @@
17.4 -requires: libstdc++ libc libipc libfsserver libmem libe2access_blockserver
17.5 +requires: libstdc++ libc libipc libfsserver libmem libe2access_blockserver libexec
17.6 provides: fsservers
17.7 maintainer: paul@boddie.org.uk
18.1 --- a/servers/Makefile Sat Feb 18 22:48:39 2023 +0100
18.2 +++ b/servers/Makefile Thu Feb 23 23:49:26 2023 +0100
18.3 @@ -6,6 +6,7 @@
18.4 ext2_server \
18.5 host_server \
18.6 pipe_server \
18.7 + process_server \
18.8 test_server
18.9
18.10 MODE = static
18.11 @@ -18,8 +19,10 @@
18.12
18.13 SRC_CC_pipe_server = pipe_server.cc
18.14
18.15 +SRC_CC_process_server = process_server.cc
18.16 +
18.17 SRC_CC_test_server = test_file_server.cc
18.18
18.19 -REQUIRES_LIBS = l4re_c-util libmem libfsserver libipc libstdc++ libsystypes libe2access_blockserver
18.20 +REQUIRES_LIBS = l4re_c-util libmem libfsserver libipc libstdc++ libsystypes libe2access_blockserver libexec
18.21
18.22 include $(L4DIR)/mk/prog.mk
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/servers/process_server.cc Thu Feb 23 23:49:26 2023 +0100
19.3 @@ -0,0 +1,77 @@
19.4 +/*
19.5 + * A process server providing a way of creating new processes.
19.6 + *
19.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
19.8 + *
19.9 + * This program is free software; you can redistribute it and/or
19.10 + * modify it under the terms of the GNU General Public License as
19.11 + * published by the Free Software Foundation; either version 2 of
19.12 + * the License, or (at your option) any later version.
19.13 + *
19.14 + * This program is distributed in the hope that it will be useful,
19.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
19.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19.17 + * GNU General Public License for more details.
19.18 + *
19.19 + * You should have received a copy of the GNU General Public License
19.20 + * along with this program; if not, write to the Free Software
19.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19.22 + * Boston, MA 02110-1301, USA
19.23 + */
19.24 +
19.25 +#include <l4/sys/err.h>
19.26 +
19.27 +#include <ipc/thread.h>
19.28 +
19.29 +#include <stdio.h>
19.30 +#include <stdlib.h>
19.31 +
19.32 +#include <exec/process_creator_resource.h>
19.33 +#include <fsserver/resource_server.h>
19.34 +
19.35 +
19.36 +
19.37 +/* Server program. */
19.38 +
19.39 +int main(int argc, char *argv[])
19.40 +{
19.41 + if (argc < 2)
19.42 + {
19.43 + printf("Need a region mapper.\n");
19.44 + return 1;
19.45 + }
19.46 +
19.47 + char *rm_filename = argv[1];
19.48 + const char *server_name = (argc > 2) ? argv[2] : "pserver";
19.49 + long err;
19.50 +
19.51 + /* Introduce concurrency control. */
19.52 +
19.53 + err = ipc_thread_init();
19.54 +
19.55 + if (err)
19.56 + {
19.57 + printf("Initialisation error: %s\n", l4sys_errtostr(err));
19.58 + return 1;
19.59 + }
19.60 +
19.61 + ProcessCreatorResource creator(rm_filename);
19.62 +
19.63 + /* Register a server associating it with the given object. */
19.64 +
19.65 + ResourceServer server(&creator);
19.66 + err = server.bind(server_name);
19.67 +
19.68 + if (err)
19.69 + {
19.70 + printf("Could not bind server: %s\n", l4sys_errtostr(err));
19.71 + return 1;
19.72 + }
19.73 +
19.74 + printf("Starting server...\n");
19.75 + server.start();
19.76 + return 0;
19.77 +}
19.78 +
19.79 +/* vim: tabstop=2 expandtab shiftwidth=2
19.80 +*/
20.1 --- a/tests/Control Sat Feb 18 22:48:39 2023 +0100
20.2 +++ b/tests/Control Thu Feb 23 23:49:26 2023 +0100
20.3 @@ -1,3 +1,3 @@
20.4 -requires: libstdc++ libc libexec libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files
20.5 +requires: libstdc++ libc libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files
20.6 provides: fstests
20.7 maintainer: paul@boddie.org.uk
21.1 --- a/tests/Makefile Sat Feb 18 22:48:39 2023 +0100
21.2 +++ b/tests/Makefile Thu Feb 23 23:49:26 2023 +0100
21.3 @@ -32,13 +32,11 @@
21.4
21.5 # Required interfaces.
21.6
21.7 -CLIENT_INTERFACES_CC_dstest_exec = notifier
21.8 CLIENT_INTERFACES_CC_dstest_file_mapping = dataspace
21.9 CLIENT_INTERFACES_CC = dataspace notifier
21.10
21.11 # Generated and plain source files.
21.12
21.13 -CLIENT_INTERFACES_SRC_CC_dstest_exec = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC_dstest_exec))
21.14 CLIENT_INTERFACES_SRC_CC_dstest_file_mapping = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC_dstest_file_mapping))
21.15
21.16 # Normal source files.
21.17 @@ -77,7 +75,7 @@
21.18
21.19 SRC_CC_dstest_align = dstest_align.cc
21.20
21.21 -REQUIRES_LIBS = l4re_c-util libexec libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver
21.22 +REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver
21.23 PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
21.24
21.25 include $(L4DIR)/mk/prog.mk
22.1 --- a/tests/dstest_exec.cc Sat Feb 18 22:48:39 2023 +0100
22.2 +++ b/tests/dstest_exec.cc Thu Feb 23 23:49:26 2023 +0100
22.3 @@ -23,7 +23,8 @@
22.4 #include <l4/sys/err.h>
22.5 #include <l4/util/util.h>
22.6
22.7 -#include <exec/process_creator.h>
22.8 +#include <fsclient/client.h>
22.9 +#include <fsclient/process.h>
22.10 #include <systypes/fcntl.h>
22.11 #include <systypes/format.h>
22.12
22.13 @@ -31,34 +32,18 @@
22.14
22.15
22.16
22.17 -class local_Notifier : public Notifier
22.18 -{
22.19 -public:
22.20 - long notify(notify_flags_t flags, notify_values_t values)
22.21 - {
22.22 - printf("Notified with flags: %" pFMTnotify_flags "x\n", flags);
22.23 - printf("Notified with values: %ld, %ld\n", values.sig, values.val);
22.24 -
22.25 - return L4_EOK;
22.26 - }
22.27 -};
22.28 -
22.29 -
22.30 -
22.31 int main(int argc, char *argv[])
22.32 {
22.33 long err;
22.34
22.35 - if (argc < 3)
22.36 + if (argc < 2)
22.37 {
22.38 - printf("Need a region mapper and the actual program to run.\n");
22.39 + printf("Need the program to run.\n");
22.40 return 1;
22.41 }
22.42
22.43 - char *rm_filename = argv[1];
22.44 - char *program_filename = argv[2];
22.45 + char *program_filename = argv[1];
22.46
22.47 - ProcessCreator creator(rm_filename);
22.48 file_t *program_file = client_open(program_filename, O_RDONLY);
22.49
22.50 if (!client_opened(program_file))
22.51 @@ -67,10 +52,18 @@
22.52 return 1;
22.53 }
22.54
22.55 - local_Notifier notifier;
22.56 + /* Create a new process structure and obtain the common notifier. */
22.57 +
22.58 + process_t *process = process_new();
22.59 + process_notifier_t *notifier = process_notify_task();
22.60
22.61 - creator.set_notifier(¬ifier);
22.62 - err = creator.start(program_file, argc - 2, (const char **) argv + 2);
22.63 + /* Start a process for the given program, specifying a notifier from which an
22.64 + endpoint will be obtained for notifications. */
22.65 +
22.66 + err = process_start(process, program_file, notifier);
22.67 +
22.68 + /* NOTE: Need to be able to send arguments, which would be sent via a context,
22.69 + although capabilities could be sent via arguments. */
22.70
22.71 if (err)
22.72 {
22.73 @@ -79,17 +72,18 @@
22.74 }
22.75
22.76 printf("Finished program initiation.\n");
22.77 - printf("End of test.\n");
22.78 +
22.79 + /* Wait for a signal from the process. */
22.80 +
22.81 + err = process_notify_wait_process(process, notifier);
22.82
22.83 - /* NOTE: Should be able to obtain a notification for when the program
22.84 - finishes, which might be done using a capability deletion IRQ.
22.85 - Eventually, this program will operate as a server, invoking new
22.86 - programs and handling termination. This test would then merely
22.87 - involve the invocation of a utility function. */
22.88 + notify_flags_t flags = process_notifications(process);
22.89 + notify_values_t values = process_notification_values(process);
22.90
22.91 - while (1)
22.92 - l4_sleep_forever();
22.93 + printf("Notified with flags: %" pFMTnotify_flags "x\n", flags);
22.94 + printf("Notified with values: %ld, %ld\n", values.sig, values.val);
22.95
22.96 + printf("End of test.\n");
22.97 return 0;
22.98 }
22.99