1.1 --- a/libexec/include/exec/external_pager.h Thu Mar 23 15:42:39 2023 +0100
1.2 +++ b/libexec/include/exec/external_pager.h Fri Mar 24 00:46:26 2023 +0100
1.3 @@ -21,12 +21,10 @@
1.4
1.5 #pragma once
1.6
1.7 -#include <vector>
1.8 -
1.9 #include <exec/elf.h>
1.10 #include <exec/pager.h>
1.11 +#include <exec/process_monitor.h>
1.12 #include <exec/segment.h>
1.13 -#include <fsserver/notification.h>
1.14 #include <resource/resource.h>
1.15
1.16 #include "parent_pager_object_interface.h"
1.17 @@ -36,17 +34,18 @@
1.18 /* A simple system pager also acting as a region mapper. */
1.19
1.20 class ExternalPager : public ExecPager, public ParentPagerObject,
1.21 - public NotificationSupport, public Resource
1.22 + public Resource
1.23 {
1.24 protected:
1.25
1.26 /* Resources associated with the created process. */
1.27
1.28 l4_cap_idx_t _task = L4_INVALID_CAP, _mapped_task = L4_INVALID_CAP,
1.29 + _thread = L4_INVALID_CAP, _mapped_thread = L4_INVALID_CAP,
1.30 _parent = L4_INVALID_CAP, _mapped_parent = L4_INVALID_CAP,
1.31 - _pager = L4_INVALID_CAP, _mapped_pager = L4_INVALID_CAP,
1.32 - _ipc_gate = L4_INVALID_CAP;
1.33 - std::vector<l4_cap_idx_t> _threads, _mapped_threads;
1.34 + _pager = L4_INVALID_CAP, _mapped_pager = L4_INVALID_CAP;
1.35 +
1.36 + ProcessMonitor *_monitor = NULL;
1.37
1.38 /* Resources supporting the internal pager. */
1.39
1.40 @@ -63,13 +62,16 @@
1.41 virtual void *interface()
1.42 { return static_cast<ParentPagerObject *>(this); }
1.43
1.44 - /* Task and thread management. */
1.45 + /* Capability management. */
1.46
1.47 - virtual void add_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
1.48 - virtual void set_gate(l4_cap_idx_t cap);
1.49 virtual void set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
1.50 virtual void set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
1.51 virtual void set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
1.52 + virtual void set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
1.53 +
1.54 + /* Lifecycle management. */
1.55 +
1.56 + virtual void set_monitor(ProcessMonitor *monitor);
1.57
1.58 /* Internal pager resource management. */
1.59
1.60 @@ -96,12 +98,6 @@
1.61 /* Parent methods. */
1.62
1.63 virtual long signal(unsigned long sig, unsigned long val);
1.64 -
1.65 - /* Notification methods. */
1.66 -
1.67 - virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
1.68 -
1.69 - virtual long unsubscribe(l4_cap_idx_t notifier);
1.70 };
1.71
1.72 /* vim: tabstop=2 expandtab shiftwidth=2
2.1 --- a/libexec/include/exec/process.h Thu Mar 23 15:42:39 2023 +0100
2.2 +++ b/libexec/include/exec/process.h Fri Mar 24 00:46:26 2023 +0100
2.3 @@ -96,9 +96,9 @@
2.4 long configure_task(l4_cap_idx_t *task, l4_cap_idx_t *mapped_task,
2.5 unsigned int threads = 2);
2.6
2.7 - long configure_thread(l4_cap_idx_t rm, l4_cap_idx_t *mapped_rm = NULL);
2.8 + long set_pager(l4_cap_idx_t rm, l4_cap_idx_t *mapped_rm = NULL);
2.9
2.10 - long set_parent(l4_cap_idx_t parent, l4_cap_idx_t *mapped_parent);
2.11 + long set_parent(l4_cap_idx_t parent, l4_cap_idx_t *mapped_parent = NULL);
2.12
2.13 long map_capabilities(struct ipc_mapped_cap mapped_caps[],
2.14 bool to_count = true);
3.1 --- a/libexec/include/exec/process_creating.h Thu Mar 23 15:42:39 2023 +0100
3.2 +++ b/libexec/include/exec/process_creating.h Fri Mar 24 00:46:26 2023 +0100
3.3 @@ -27,6 +27,7 @@
3.4 #include <exec/external_pager.h>
3.5 #include <exec/memory.h>
3.6 #include <exec/process.h>
3.7 +#include <exec/process_monitor.h>
3.8 #include <ipc/map.h>
3.9
3.10
3.11 @@ -43,9 +44,10 @@
3.12 const char *_rm_filename;
3.13 file_t *_rm_file;
3.14
3.15 - /* External pager configuration. */
3.16 + /* External pager and process monitor. */
3.17
3.18 ExternalPager *_exec_pager = NULL;
3.19 + ProcessMonitor *_monitor = NULL;
3.20
3.21 /* Process construction. */
3.22
3.23 @@ -62,7 +64,7 @@
3.24 /* IPC gate for communication within the created task, plus allocated
3.25 capability. */
3.26
3.27 - l4_cap_idx_t _ipc_gate, _ipc_gate_cap;
3.28 + l4_cap_idx_t _internal_pager, _mapped_internal_pager;
3.29
3.30 /* Utility methods. */
3.31
3.32 @@ -74,9 +76,11 @@
3.33
3.34 long init_external_pager(l4_cap_idx_t *pager);
3.35
3.36 - long configure_task(l4_cap_idx_t pager);
3.37 + long init_process_monitor(l4_cap_idx_t *monitor);
3.38
3.39 - long create_ipc_gate();
3.40 + long configure_task();
3.41 +
3.42 + long allocate_internal_pager();
3.43
3.44 void init_region(struct exec_region *regions,
3.45 struct ipc_mapped_cap *mapped_caps,
3.46 @@ -84,7 +88,7 @@
3.47
3.48 long start_region_mapper(l4_cap_idx_t pager);
3.49
3.50 - long start_program(int argc, const char *argv[]);
3.51 + long start_program(l4_cap_idx_t monitor, int argc, const char *argv[]);
3.52
3.53 public:
3.54 explicit ProcessCreating(const char *rm_filename, file_t *rm_file);
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/libexec/include/exec/process_monitor.h Fri Mar 24 00:46:26 2023 +0100
4.3 @@ -0,0 +1,82 @@
4.4 +/*
4.5 + * A process monitor abstraction.
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 <fsserver/notification.h>
4.28 +#include <resource/resource.h>
4.29 +
4.30 +#include "parent_notification_object_interface.h"
4.31 +
4.32 +
4.33 +
4.34 +/* A process monitor receiving signals from a task. */
4.35 +
4.36 +class ProcessMonitor : public ParentNotificationObject, public NotificationSupport,
4.37 + public Resource
4.38 +{
4.39 +protected:
4.40 +
4.41 + /* Resources associated with the created process. */
4.42 +
4.43 + l4_cap_idx_t _pager = L4_INVALID_CAP, _mapped_pager = L4_INVALID_CAP,
4.44 + _parent = L4_INVALID_CAP, _mapped_parent = L4_INVALID_CAP,
4.45 + _task = L4_INVALID_CAP, _mapped_task = L4_INVALID_CAP,
4.46 + _thread = L4_INVALID_CAP, _mapped_thread = L4_INVALID_CAP;
4.47 +
4.48 +public:
4.49 + explicit ProcessMonitor();
4.50 +
4.51 + /* Server details. */
4.52 +
4.53 + virtual ipc_server_default_config_type config();
4.54 +
4.55 + virtual void *interface()
4.56 + { return static_cast<ParentNotificationObject *>(this); }
4.57 +
4.58 + /* Capability management. */
4.59 +
4.60 + virtual void set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
4.61 + virtual void set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
4.62 + virtual void set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
4.63 + virtual void set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap);
4.64 +
4.65 + /* Lifecycle management. */
4.66 +
4.67 + virtual void pager_ended();
4.68 +
4.69 + /* Resource methods. */
4.70 +
4.71 + virtual void close();
4.72 +
4.73 + /* Parent methods. */
4.74 +
4.75 + virtual long signal(unsigned long sig, unsigned long val);
4.76 +
4.77 + /* Notification methods. */
4.78 +
4.79 + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
4.80 +
4.81 + virtual long unsubscribe(l4_cap_idx_t notifier);
4.82 +};
4.83 +
4.84 +/* vim: tabstop=2 expandtab shiftwidth=2
4.85 +*/
5.1 --- a/libexec/lib/src/Makefile Thu Mar 23 15:42:39 2023 +0100
5.2 +++ b/libexec/lib/src/Makefile Fri Mar 24 00:46:26 2023 +0100
5.3 @@ -17,7 +17,9 @@
5.4
5.5 CLIENT_INTERFACES_CC = dataspace
5.6
5.7 -SERVER_INTERFACES_CC = opener pager_object parent_pager_object process_creator_context_object
5.8 +SERVER_INTERFACES_CC = \
5.9 + opener pager_object parent_notification_object \
5.10 + parent_pager_object process_creator_context_object
5.11
5.12 # Generated and plain source files.
5.13
5.14 @@ -36,6 +38,7 @@
5.15 process.cc process_creating.cc \
5.16 process_creator_context_resource.cc \
5.17 process_creator_resource.cc \
5.18 + process_monitor.cc \
5.19 segment.cc stack.cc
5.20
5.21 # Normal definitions.
6.1 --- a/libexec/lib/src/external_pager.cc Thu Mar 23 15:42:39 2023 +0100
6.2 +++ b/libexec/lib/src/external_pager.cc Fri Mar 24 00:46:26 2023 +0100
6.3 @@ -43,7 +43,7 @@
6.4 /* A simple system pager also acting as a region mapper. */
6.5
6.6 ExternalPager::ExternalPager(address_t start, address_t end)
6.7 -: ExecPager(start, end), NotificationSupport()
6.8 +: ExecPager(start, end)
6.9 {
6.10 }
6.11
6.12 @@ -94,30 +94,15 @@
6.13 for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++)
6.14 ipc_cap_free_um(*itc);
6.15
6.16 - /* Remove the created task. */
6.17 + /* Notify the monitor. */
6.18
6.19 - if (l4_is_valid_cap(_task))
6.20 - {
6.21 - ipc_unmap_capability(_task, _mapped_task);
6.22 - ipc_cap_free_um(_task);
6.23 - _task = L4_INVALID_CAP;
6.24 - }
6.25 + if (_monitor != NULL)
6.26 + _monitor->pager_ended();
6.27 }
6.28
6.29
6.30
6.31 -/* Manage the task and thread capabilities. */
6.32 -
6.33 -void ExternalPager::add_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
6.34 -{
6.35 - _threads.push_back(cap);
6.36 - _mapped_threads.push_back(mapped_cap);
6.37 -}
6.38 -
6.39 -void ExternalPager::set_gate(l4_cap_idx_t cap)
6.40 -{
6.41 - _ipc_gate = cap;
6.42 -}
6.43 +/* Capability management. */
6.44
6.45 void ExternalPager::set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
6.46 {
6.47 @@ -137,6 +122,21 @@
6.48 _mapped_task = mapped_cap;
6.49 }
6.50
6.51 +void ExternalPager::set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
6.52 +{
6.53 + _thread = cap;
6.54 + _mapped_thread = mapped_cap;
6.55 +}
6.56 +
6.57 +
6.58 +
6.59 +/* Lifecycle management. */
6.60 +
6.61 +void ExternalPager::set_monitor(ProcessMonitor *monitor)
6.62 +{
6.63 + _monitor = monitor;
6.64 +}
6.65 +
6.66
6.67
6.68 /* Manage pager resources. */
6.69 @@ -277,41 +277,23 @@
6.70
6.71 long ExternalPager::signal(unsigned long sig, unsigned long val)
6.72 {
6.73 - notify_all(NOTIFY_TASK_SIGNAL, (notify_values_t) {sig, val});
6.74 -
6.75 - /* Handle the termination event. */
6.76 + /* Handle the termination event of the internal pager. */
6.77
6.78 if (sig == 0)
6.79 {
6.80 - printf("Signal from task.\n");
6.81 -
6.82 - /* Once the program exits, the IPC gate connecting the program with its
6.83 - internal pager can be released. */
6.84 + printf("Signal from internal pager.\n");
6.85
6.86 - if (l4_is_valid_cap(_ipc_gate))
6.87 - {
6.88 - ipc_cap_free_um(_ipc_gate);
6.89 - _ipc_gate = L4_INVALID_CAP;
6.90 - }
6.91 -
6.92 - /* Upon exit of the program's internal pager, release the capabilities
6.93 - associated with this server. */
6.94 + /* For some reason, threads cannot be released by the process, so they are
6.95 + also unmapped on its behalf. */
6.96
6.97 - else if (l4_is_valid_cap(_task))
6.98 + if (l4_is_valid_cap(_thread))
6.99 {
6.100 - /* Threads. For some reason, these cannot be released by the process, so
6.101 - they are also unmapped on its behalf. */
6.102 -
6.103 - std::vector<l4_cap_idx_t>::iterator it;
6.104 + ipc_cap_free_um(_thread);
6.105 + ipc_unmap_capability(_task, _mapped_thread);
6.106 + _thread = L4_INVALID_CAP;
6.107
6.108 - for (it = _threads.begin(); it != _threads.end(); it++)
6.109 - ipc_cap_free_um(*it);
6.110 -
6.111 - for (it = _mapped_threads.begin(); it != _mapped_threads.end(); it++)
6.112 - ipc_unmap_capability(_task, *it);
6.113 -
6.114 - /* Parent and pager/region mapper. Freeing these after the threads should
6.115 - avoid warnings about invalid pager capabilities. */
6.116 + /* Parent and pager/region mapper. Freeing the pager after the thread
6.117 + should avoid warnings about invalid pager capabilities. */
6.118
6.119 ipc_unmap_capability(_task, _mapped_parent);
6.120 ipc_unmap_capability(_task, _mapped_pager);
6.121 @@ -321,21 +303,5 @@
6.122 return L4_EOK;
6.123 }
6.124
6.125 -
6.126 -
6.127 -/* Subscribe to notifications. */
6.128 -
6.129 -long ExternalPager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
6.130 -{
6.131 - return NotificationSupport::subscribe(notifier, flags);
6.132 -}
6.133 -
6.134 -/* Unsubscribe from notifications. */
6.135 -
6.136 -long ExternalPager::unsubscribe(l4_cap_idx_t notifier)
6.137 -{
6.138 - return NotificationSupport::unsubscribe(notifier);
6.139 -}
6.140 -
6.141 /* vim: tabstop=2 expandtab shiftwidth=2
6.142 */
7.1 --- a/libexec/lib/src/process.cc Thu Mar 23 15:42:39 2023 +0100
7.2 +++ b/libexec/lib/src/process.cc Fri Mar 24 00:46:26 2023 +0100
7.3 @@ -67,7 +67,6 @@
7.4 _env.log = L4_BASE_LOG_CAP;
7.5 _env.scheduler = L4_BASE_SCHEDULER_CAP;
7.6 _env.mem_alloc = L4_EXEC_MA_CAP;
7.7 - _env.parent = L4_EXEC_PARENT_CAP;
7.8
7.9 /* Capability details that are updated for each thread. Note that the region
7.10 mapper is redefined, but it would traditionally employ the given index. */
7.11 @@ -156,10 +155,10 @@
7.12 return map_capabilities(mapped_caps, false);
7.13 }
7.14
7.15 -/* Configure the thread environment, employing the given capability for the
7.16 - region mapper, returning its capability details in the new task. */
7.17 +/* Set the pager/region mapper of the new thread, using the given capability,
7.18 + returning its capability details in the new task. */
7.19
7.20 -long Process::configure_thread(l4_cap_idx_t rm, l4_cap_idx_t *mapped_rm)
7.21 +long Process::set_pager(l4_cap_idx_t rm, l4_cap_idx_t *mapped_rm)
7.22 {
7.23 /* Employ a distinct region mapper for each thread's environment, this acting
7.24 as pager. */
7.25 @@ -173,16 +172,28 @@
7.26 {
7.27 _env.rm = allocate_cap();
7.28 *mapped_rm = _env.rm;
7.29 - return ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.rm, rm, L4_CAP_FPAGE_RWS, 0});
7.30 + return ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.rm, rm,
7.31 + L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS});
7.32 }
7.33 }
7.34
7.35 -/* Set the parent of the new thread. */
7.36 +/* Set the parent of the new thread, using the default parent capability index
7.37 + if no mapped capability is provided. */
7.38
7.39 long Process::set_parent(l4_cap_idx_t parent, l4_cap_idx_t *mapped_parent)
7.40 {
7.41 - *mapped_parent = _env.parent;
7.42 - return ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.parent, parent, L4_CAP_FPAGE_RWS, 0});
7.43 + if ((mapped_parent != NULL) && l4_is_valid_cap(*mapped_parent))
7.44 + {
7.45 + _env.parent = *mapped_parent;
7.46 + return L4_EOK;
7.47 + }
7.48 + else
7.49 + {
7.50 + _env.parent = L4_EXEC_PARENT_CAP;
7.51 + *mapped_parent = _env.parent;
7.52 + return ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.parent,
7.53 + parent, L4_CAP_FPAGE_RWS, 0});
7.54 + }
7.55 }
7.56
7.57 /* Map capabilities into the task, counting them if indicated. If capability
8.1 --- a/libexec/lib/src/process_creating.cc Thu Mar 23 15:42:39 2023 +0100
8.2 +++ b/libexec/lib/src/process_creating.cc Fri Mar 24 00:46:26 2023 +0100
8.3 @@ -111,9 +111,26 @@
8.4 return L4_EOK;
8.5 }
8.6
8.7 +/* Initialise a resource to receive signals from the process. */
8.8 +
8.9 +long ProcessCreating::init_process_monitor(l4_cap_idx_t *monitor)
8.10 +{
8.11 + _monitor = new ProcessMonitor;
8.12 +
8.13 + /* Start the monitor in a separate thread. */
8.14 +
8.15 + long err = ResourceServer(_monitor).start_thread(monitor);
8.16 +
8.17 + if (err)
8.18 + return err;
8.19 +
8.20 + _exec_pager->set_monitor(_monitor);
8.21 + return L4_EOK;
8.22 +}
8.23 +
8.24 /* Configure the environment for the task. */
8.25
8.26 -long ProcessCreating::configure_task(l4_cap_idx_t pager)
8.27 +long ProcessCreating::configure_task()
8.28 {
8.29 l4_cap_idx_t task, mapped_task;
8.30 long err = _process.configure_task(&task, &mapped_task);
8.31 @@ -121,51 +138,32 @@
8.32 if (err)
8.33 return err;
8.34
8.35 - /* Record the task details in the pager for eventual resource deallocation. */
8.36 + /* Record the task details elsewhere for eventual resource deallocation. */
8.37
8.38 _exec_pager->set_task(task, mapped_task);
8.39 -
8.40 - /* Note the pager as the parent of the new task, recording its capability
8.41 - details in the new task. */
8.42 -
8.43 - l4_cap_idx_t mapped_parent;
8.44 - err = _process.set_parent(pager, &mapped_parent);
8.45 -
8.46 - if (err)
8.47 - return err;
8.48 -
8.49 - _exec_pager->set_parent(pager, mapped_parent);
8.50 + _monitor->set_task(task, mapped_task);
8.51 return L4_EOK;
8.52 }
8.53
8.54 -/* Create an unbound IPC gate for the region mapper and allocate it in the
8.55 - created process. */
8.56 +/* Create an unbound IPC gate for the internal pager/region mapper and allocate
8.57 + it in the created process. */
8.58
8.59 -long ProcessCreating::create_ipc_gate()
8.60 +long ProcessCreating::allocate_internal_pager()
8.61 {
8.62 - _ipc_gate_cap = _process.allocate_cap();
8.63 - _ipc_gate = ipc_cap_alloc();
8.64 + _mapped_internal_pager = _process.allocate_cap();
8.65 + _internal_pager = ipc_cap_alloc();
8.66
8.67 - if (l4_is_invalid_cap(_ipc_gate))
8.68 + if (l4_is_invalid_cap(_internal_pager))
8.69 return -L4_ENOMEM;
8.70
8.71 - long err = l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0));
8.72 -
8.73 - if (err)
8.74 - return err;
8.75 -
8.76 - /* The gate is retained because even after being mapped to the new task,
8.77 - releasing it will cause it to be deallocated. */
8.78 -
8.79 - _exec_pager->set_gate(_ipc_gate);
8.80 - return L4_EOK;
8.81 + return l4_error(l4_factory_create_gate(l4re_env()->factory, _internal_pager, L4_INVALID_CAP, 0));
8.82 }
8.83
8.84 /* Initialise and assign a region in a list to the created process. */
8.85
8.86 void ProcessCreating::init_region(struct exec_region *regions,
8.87 - struct ipc_mapped_cap *mapped_caps,
8.88 - struct exec_region &r, unsigned int &index)
8.89 + struct ipc_mapped_cap *mapped_caps,
8.90 + struct exec_region &r, unsigned int &index)
8.91 {
8.92 l4_cap_idx_t mapped_cap = _process.allocate_cap();
8.93
8.94 @@ -217,9 +215,11 @@
8.95
8.96 rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
8.97
8.98 - /* Introduce the server capability and terminate the capability array. */
8.99 + /* Introduce the internal pager capability and terminate the capability array. */
8.100
8.101 - rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
8.102 + rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_mapped_internal_pager,
8.103 + _internal_pager, L4_CAP_FPAGE_RWS,
8.104 + L4_FPAGE_C_OBJ_RIGHTS};
8.105 rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
8.106
8.107 /* Map these additional capabilities. */
8.108 @@ -234,7 +234,7 @@
8.109 mapping the capability and encoded in the entry below. */
8.110
8.111 l4re_env_cap_entry_t rm_init_caps[] = {
8.112 - l4re_env_cap_entry_t(ENV_INTERNAL_PAGER_NAME, _ipc_gate_cap, L4_CAP_FPAGE_RWS),
8.113 + l4re_env_cap_entry_t(ENV_INTERNAL_PAGER_NAME, _mapped_internal_pager, L4_CAP_FPAGE_RWS),
8.114 l4re_env_cap_entry_t()
8.115 };
8.116
8.117 @@ -246,13 +246,23 @@
8.118 exception handler plus region mapper). */
8.119
8.120 l4_cap_idx_t mapped_pager = L4_INVALID_CAP;
8.121 - err = _process.configure_thread(pager, &mapped_pager);
8.122 + err = _process.set_pager(pager, &mapped_pager);
8.123
8.124 if (err)
8.125 return err;
8.126
8.127 _exec_pager->set_pager(pager, mapped_pager);
8.128
8.129 + /* Note the pager as the parent of the new task, recording its capability
8.130 + details in the new task. */
8.131 +
8.132 + err = _process.set_parent(pager, &mapped_pager);
8.133 +
8.134 + if (err)
8.135 + return err;
8.136 +
8.137 + _exec_pager->set_parent(pager, mapped_pager);
8.138 +
8.139 /* Populate a thread stack with argument and environment details for the
8.140 region mapper, plus the initial server capability and region details. */
8.141
8.142 @@ -271,14 +281,14 @@
8.143 if (err)
8.144 return err;
8.145
8.146 - _exec_pager->add_thread(thread, mapped_thread);
8.147 + _exec_pager->set_thread(thread, mapped_thread);
8.148 return L4_EOK;
8.149 }
8.150
8.151 /* Configure a thread for a program, populate its stack, and start the
8.152 thread. */
8.153
8.154 -long ProcessCreating::start_program(int argc, const char *argv[])
8.155 +long ProcessCreating::start_program(l4_cap_idx_t monitor, int argc, const char *argv[])
8.156 {
8.157 /* NOTE: Environment vector is currently not defined. */
8.158
8.159 @@ -287,12 +297,25 @@
8.160 /* Configure the environment for the thread, specifying the pager (and
8.161 exception handler plus region mapper). */
8.162
8.163 - l4_cap_idx_t mapped_pager = _ipc_gate_cap;
8.164 - long err = _process.configure_thread(_ipc_gate, &mapped_pager);
8.165 + l4_cap_idx_t mapped_pager = _mapped_internal_pager;
8.166 + long err = _process.set_pager(_internal_pager, &mapped_pager);
8.167
8.168 if (err)
8.169 return err;
8.170
8.171 + _monitor->set_pager(_internal_pager, _mapped_internal_pager);
8.172 +
8.173 + /* Note the monitor as the parent of the new task, recording its capability
8.174 + details in the new task. */
8.175 +
8.176 + l4_cap_idx_t mapped_parent = L4_INVALID_CAP;
8.177 + err = _process.set_parent(monitor, &mapped_parent);
8.178 +
8.179 + if (err)
8.180 + return err;
8.181 +
8.182 + _monitor->set_parent(monitor, mapped_parent);
8.183 +
8.184 /* Obtain the filesystem capability for exporting to the task. */
8.185
8.186 l4_cap_idx_t fsserver_cap = _process.allocate_cap();
8.187 @@ -338,13 +361,13 @@
8.188 if (err)
8.189 return err;
8.190
8.191 - _exec_pager->add_thread(thread, mapped_thread);
8.192 + _monitor->set_thread(thread, mapped_thread);
8.193 return L4_EOK;
8.194 }
8.195
8.196 /* Start a new process for the payload indicated by the first of the given
8.197 - program arguments, returning a reference to the pager as an object for
8.198 - interacting with the process. */
8.199 + program arguments, returning a reference to the process monitor as an object
8.200 + for interacting with the process. */
8.201
8.202 long ProcessCreating::start(int argc, const char *argv[], l4_cap_idx_t *process)
8.203 {
8.204 @@ -368,6 +391,8 @@
8.205
8.206 /* Initialise the different elements of the process. */
8.207
8.208 + l4_cap_idx_t pager;
8.209 +
8.210 err = init_region_mapper();
8.211 if (err)
8.212 return err;
8.213 @@ -376,23 +401,27 @@
8.214 if (err)
8.215 return err;
8.216
8.217 - err = init_external_pager(process);
8.218 + err = init_external_pager(&pager);
8.219 if (err)
8.220 return err;
8.221
8.222 - err = configure_task(*process);
8.223 + err = init_process_monitor(process);
8.224 if (err)
8.225 return err;
8.226
8.227 - err = create_ipc_gate();
8.228 + err = configure_task();
8.229 if (err)
8.230 return err;
8.231
8.232 - err = start_region_mapper(*process);
8.233 + err = allocate_internal_pager();
8.234 if (err)
8.235 return err;
8.236
8.237 - err = start_program(argc, argv);
8.238 + err = start_region_mapper(pager);
8.239 + if (err)
8.240 + return err;
8.241 +
8.242 + err = start_program(*process, argc, argv);
8.243 if (err)
8.244 return err;
8.245
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/libexec/lib/src/process_monitor.cc Fri Mar 24 00:46:26 2023 +0100
9.3 @@ -0,0 +1,158 @@
9.4 +/*
9.5 + * A process monitor abstraction.
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 <ipc/cap_alloc.h>
9.26 +#include <ipc/map.h>
9.27 +#include <systypes/base.h>
9.28 +
9.29 +#include <stdio.h>
9.30 +
9.31 +#include "process_monitor.h"
9.32 +#include "parent_notification_object_server.h"
9.33 +
9.34 +
9.35 +
9.36 +/* A process monitor receiving signals from a task. */
9.37 +
9.38 +ProcessMonitor::ProcessMonitor()
9.39 +: NotificationSupport()
9.40 +{
9.41 +}
9.42 +
9.43 +ipc_server_default_config_type ProcessMonitor::config()
9.44 +{
9.45 + return config_ParentNotificationObject;
9.46 +}
9.47 +
9.48 +
9.49 +
9.50 +/* Close the process monitor. */
9.51 +
9.52 +void ProcessMonitor::close()
9.53 +{
9.54 + printf("Process monitor closing...\n");
9.55 +
9.56 + if (l4_is_valid_cap(_task))
9.57 + {
9.58 + ipc_unmap_capability(_task, _mapped_task);
9.59 + ipc_cap_free_um(_task);
9.60 + _task = L4_INVALID_CAP;
9.61 + }
9.62 +}
9.63 +
9.64 +
9.65 +
9.66 +/* Capability management. */
9.67 +
9.68 +void ProcessMonitor::set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
9.69 +{
9.70 + _pager = cap;
9.71 + _mapped_pager = mapped_cap;
9.72 +}
9.73 +
9.74 +void ProcessMonitor::set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
9.75 +{
9.76 + _parent = cap;
9.77 + _mapped_parent = mapped_cap;
9.78 +}
9.79 +
9.80 +void ProcessMonitor::set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
9.81 +{
9.82 + _task = cap;
9.83 + _mapped_task = mapped_cap;
9.84 +}
9.85 +
9.86 +void ProcessMonitor::set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)
9.87 +{
9.88 + _thread = cap;
9.89 + _mapped_thread = mapped_cap;
9.90 +}
9.91 +
9.92 +
9.93 +
9.94 +/* Lifecycle management. */
9.95 +
9.96 +void ProcessMonitor::pager_ended()
9.97 +{
9.98 + /* Release the program thread and its reference to this object. This will
9.99 + cause this object to be closed. */
9.100 +
9.101 + if (l4_is_valid_cap(_thread))
9.102 + {
9.103 + ipc_unmap_capability(_task, _mapped_thread);
9.104 + ipc_cap_free_um(_thread);
9.105 + _thread = L4_INVALID_CAP;
9.106 +
9.107 + ipc_unmap_capability(_task, _mapped_parent);
9.108 + }
9.109 +}
9.110 +
9.111 +
9.112 +
9.113 +/* Receive signals from a task. */
9.114 +
9.115 +long ProcessMonitor::signal(unsigned long sig, unsigned long val)
9.116 +{
9.117 + notify_all(NOTIFY_TASK_SIGNAL, (notify_values_t) {sig, val});
9.118 +
9.119 + /* Handle the termination event. */
9.120 +
9.121 + if (sig == 0)
9.122 + {
9.123 + printf("Signal from task.\n");
9.124 +
9.125 + /* Once the program exits, the IPC gate connecting the program with its
9.126 + internal pager can be released. This will cause the internal pager to
9.127 + finish, which is then handled by the external pager. */
9.128 +
9.129 + if (l4_is_valid_cap(_pager))
9.130 + {
9.131 + ipc_cap_free_um(_pager);
9.132 + _pager = L4_INVALID_CAP;
9.133 + }
9.134 +
9.135 + /* The thread is not released here since the initiator of the process
9.136 + needs to be able to receive a reference to this object, but if the
9.137 + process terminates and the thread is released, this object may be
9.138 + released before the initiator obtains a reference to it. */
9.139 + }
9.140 +
9.141 + return L4_EOK;
9.142 +}
9.143 +
9.144 +
9.145 +
9.146 +/* Subscribe to notifications. */
9.147 +
9.148 +long ProcessMonitor::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
9.149 +{
9.150 + return NotificationSupport::subscribe(notifier, flags);
9.151 +}
9.152 +
9.153 +/* Unsubscribe from notifications. */
9.154 +
9.155 +long ProcessMonitor::unsubscribe(l4_cap_idx_t notifier)
9.156 +{
9.157 + return NotificationSupport::unsubscribe(notifier);
9.158 +}
9.159 +
9.160 +/* vim: tabstop=2 expandtab shiftwidth=2
9.161 +*/
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/libsystypes/idl/parent_notification_object.idl Fri Mar 24 00:46:26 2023 +0100
10.3 @@ -0,0 +1,4 @@
10.4 +import "notification.idl";
10.5 +import "parent.idl";
10.6 +
10.7 +interface ParentNotificationObject composes Parent, Notification;