L4Re/departure

Changeset

543:f2f170ce32e8
2023-03-24 Paul Boddie raw files shortlog changelog graph Changed the process monitoring architecture, separating monitoring of the actual program from that done by the external pager of the internal pager/region mapper.
libexec/include/exec/external_pager.h (file) libexec/include/exec/process.h (file) libexec/include/exec/process_creating.h (file) libexec/include/exec/process_monitor.h (file) libexec/lib/src/Makefile (file) libexec/lib/src/external_pager.cc (file) libexec/lib/src/process.cc (file) libexec/lib/src/process_creating.cc (file) libexec/lib/src/process_monitor.cc (file) libsystypes/idl/parent_notification_object.idl (file)
     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;