# HG changeset patch # User Paul Boddie # Date 1677863738 -3600 # Node ID dbed58b9eb942e31f6fff4e1ffbb691720d7814f # Parent fbac8f26ad0e6b3763e67b90533431b624dc36d6 Handle termination signals, decoupling programs from their pagers and releasing resources, so that an external pager can be closed after notifying the task that initiated the creation of a process. diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/include/exec/external_pager.h --- a/libexec/include/exec/external_pager.h Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/include/exec/external_pager.h Fri Mar 03 18:15:38 2023 +0100 @@ -35,6 +35,9 @@ class ExternalPager : public ExecPager, public ParentPagerObject, public NotificationSupport, public Resource { +protected: + l4_cap_idx_t _task, _server, _ipc_gate; + public: explicit ExternalPager(address_t start = 0, address_t end = 0); @@ -45,6 +48,16 @@ virtual void *interface() { return static_cast(this); } + /* Task and thread management. */ + + virtual void set_task(l4_cap_idx_t cap); + virtual void set_server(l4_cap_idx_t cap); + virtual void set_gate(l4_cap_idx_t cap); + + /* Resource methods. */ + + virtual void close(); + /* Notification methods, implementing PagerObject. */ virtual long exception(l4_exc_regs_t regs, diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/include/exec/process.h --- a/libexec/include/exec/process.h Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/include/exec/process.h Fri Mar 03 18:15:38 2023 +0100 @@ -1,7 +1,7 @@ /* * Support for initialising programs in new tasks and threads. * - * Copyright (C) 2022 Paul Boddie + * Copyright (C) 2022, 2023 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -95,12 +95,14 @@ long configure_thread(l4_cap_idx_t server, l4_cap_idx_t mapped_cap = L4_INVALID_CAP); + l4_cap_idx_t get_task(); + long set_parent(l4_cap_idx_t server); long map_capabilities(struct ipc_mapped_cap mapped_caps[], bool to_count = true); - long thread_start(l4_addr_t program_start, Stack &st); + long thread_start(l4_addr_t program_start, Stack &st, l4_cap_idx_t *thread); }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/lib/src/external_pager.cc --- a/libexec/lib/src/external_pager.cc Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/lib/src/external_pager.cc Fri Mar 03 18:15:38 2023 +0100 @@ -20,8 +20,10 @@ */ #include +#include #include +#include #include #include #include @@ -46,9 +48,50 @@ ipc_server_default_config_type ExternalPager::config() { - return config_ParentPagerObject; + return config_ParentPagerObject; +} + + + +/* Close the pager. */ + +void ExternalPager::close() +{ + printf("Pager closing...\n"); + + /* Unmap all regions. */ + + MappedRegions::iterator it; + + for (it = _regions.begin(); it != _regions.end(); it++) + { + MappedRegion &r = it->second; + + ipc_detach_dataspace((void *) r.ds_start); + } } + + +/* Manage the task and thread capabilities. */ + +void ExternalPager::set_task(l4_cap_idx_t cap) +{ + _task = cap; +} + +void ExternalPager::set_server(l4_cap_idx_t cap) +{ + _server = cap; +} + +void ExternalPager::set_gate(l4_cap_idx_t cap) +{ + _ipc_gate = cap; +} + + + /* Handle a general exception. */ long ExternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) @@ -165,15 +208,45 @@ return err; } + + /* Receive signals from a task. */ long ExternalPager::signal(unsigned long sig, unsigned long val) { notify_all(NOTIFY_TASK_SIGNAL, (notify_values_t) {sig, val}); + /* Handle the termination event. */ + + if (sig == 0) + { + /* Once the program exits, the IPC gate connecting the program with its + internal pager can be released. */ + + if (l4_is_valid_cap(_ipc_gate)) + { + l4_task_unmap(L4RE_THIS_TASK_CAP, l4_obj_fpage(_ipc_gate, 0, L4_CAP_FPAGE_RWSD), L4_FP_ALL_SPACES); + _ipc_gate = L4_INVALID_CAP; + } + + /* Upon exit of the program's internal pager, release the capabilities + associated with this server. */ + + else if (l4_is_valid_cap(_task)) + { + /* NOTE: Capability indexes to be obtained from the process creation + activity. */ + + l4_task_unmap(_task, l4_obj_fpage(0x13UL << L4_CAP_SHIFT, 0, L4_CAP_FPAGE_RWSD), L4_FP_ALL_SPACES); + l4_task_unmap(_task, l4_obj_fpage(0x19UL << L4_CAP_SHIFT, 0, L4_CAP_FPAGE_RWSD), L4_FP_ALL_SPACES); + } + } + return L4_EOK; } + + /* Subscribe to notifications. */ long ExternalPager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/lib/src/process.cc --- a/libexec/lib/src/process.cc Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/lib/src/process.cc Fri Mar 03 18:15:38 2023 +0100 @@ -1,7 +1,7 @@ /* * Support for initialising programs in new tasks and threads. * - * Copyright (C) 2022 Paul Boddie + * Copyright (C) 2022, 2023 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -107,6 +107,13 @@ return l4_error(l4_factory_create_thread(l4re_env()->factory, *thread)); } +/* Task access. */ + +l4_cap_idx_t Process::get_task() +{ + return _task; +} + /* Configure the task environment. */ long Process::configure_task(unsigned int threads) @@ -184,12 +191,11 @@ /* Create, initialise and start a thread. */ -long Process::thread_start(l4_addr_t program_start, Stack &st) +long Process::thread_start(l4_addr_t program_start, Stack &st, l4_cap_idx_t *thread) { - l4_cap_idx_t thread; long err; - err = create_thread(&thread); + err = create_thread(thread); if (err) return err; @@ -208,11 +214,11 @@ l4_thread_control_exc_handler(_env.rm); l4_thread_control_bind((l4_utcb_t *) l4_fpage_memaddr(_env.utcb_area), _task); - err = l4_error(l4_thread_control_commit(thread)); + err = l4_error(l4_thread_control_commit(*thread)); if (err) { - ipc_cap_free(thread); + ipc_cap_free(*thread); return err; } @@ -220,7 +226,7 @@ _env.main_thread = allocate_cap(); - ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS, 0}); + ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, *thread, L4_CAP_FPAGE_RWS, 0}); /* Populate the initial environment in the thread. */ @@ -236,7 +242,7 @@ /* Set the start details. */ - err = l4_error(l4_thread_ex_regs(thread, program_start, st.start_address(), 0)); + err = l4_error(l4_thread_ex_regs(*thread, program_start, st.start_address(), 0)); if (err) return err; @@ -249,7 +255,7 @@ l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO); - return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp)); + return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, *thread, &sp)); } /* vim: tabstop=2 expandtab shiftwidth=2 diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/lib/src/process_creating.cc --- a/libexec/lib/src/process_creating.cc Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/lib/src/process_creating.cc Fri Mar 03 18:15:38 2023 +0100 @@ -97,7 +97,12 @@ /* Start the pager in a separate thread. */ - return ResourceServer(_exec_pager).start_thread(pager); + long err = ResourceServer(_exec_pager).start_thread(pager); + + if (err) + return err; + + return L4_EOK; } /* Configure the environment for the task. */ @@ -224,7 +229,14 @@ /* Start the region mapper thread in the appropriate stack. */ - return _process.thread_start(_rm_payload->entry_point(), rm_st); + l4_cap_idx_t thread; + err = _process.thread_start(_rm_payload->entry_point(), rm_st, &thread); + + if (err) + return err; + + ipc_cap_free_um(thread); + return L4_EOK; } /* Configure a thread for a program, populate its stack, and start the @@ -254,7 +266,14 @@ /* Start the program thread in the appropriate stack. */ - return _process.thread_start(_program_payload->entry_point(), program_st); + l4_cap_idx_t thread; + err = _process.thread_start(_program_payload->entry_point(), program_st, &thread); + + if (err) + return err; + + ipc_cap_free_um(thread); + return L4_EOK; } /* Start a new process for the given payload, providing the indicated program @@ -293,6 +312,12 @@ if (err) return err; + /* Note the task and IPC gate on the pager object. */ + + _exec_pager->set_server(*process); + _exec_pager->set_task(_process.get_task()); + _exec_pager->set_gate(_ipc_gate); + /* Discard instances created to initialise the process. NOTE: The region mapper payload could be retained instead of being reconstructed each time. */ diff -r fbac8f26ad0e -r dbed58b9eb94 libexec/rm/region_mapper.cc --- a/libexec/rm/region_mapper.cc Tue Feb 28 22:40:02 2023 +0100 +++ b/libexec/rm/region_mapper.cc Fri Mar 03 18:15:38 2023 +0100 @@ -1,7 +1,7 @@ /* * A region mapper for deployment in a new task. * - * Copyright (C) 2022 Paul Boddie + * Copyright (C) 2022, 2023 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -69,7 +69,16 @@ printf("Pager capability: %lx\n", l4re_env_get_cap("server")); printf("Main thread: %lx\n", l4re_env()->main_thread); - ipc_server_loop_for(PagerObject, &exec_pager, "server"); + /* Initialise the server, enabling notifications. */ + + ipc_server_config_type config; + ipc_server_init_for(&config, PagerObject, &exec_pager); + config.notifications = 1; + + /* Bind to the named capability and serve until the IPC gate is released. */ + + ipc_server_bind("server", (l4_umword_t) &config, &config.server); + ipc_server_start_config(&config); printf("Ending pager...\n"); return 0; diff -r fbac8f26ad0e -r dbed58b9eb94 libfsclient/include/fsclient/process.h --- a/libfsclient/include/fsclient/process.h Tue Feb 28 22:40:02 2023 +0100 +++ b/libfsclient/include/fsclient/process.h Fri Mar 03 18:15:38 2023 +0100 @@ -57,6 +57,7 @@ /* Principal functions. */ process_t *process_new(); +void process_close(process_t *process); void process_init(process_t *process); long process_start(process_t *process, int argc, char *argv[]); diff -r fbac8f26ad0e -r dbed58b9eb94 libfsclient/lib/src/process.cc --- a/libfsclient/lib/src/process.cc Tue Feb 28 22:40:02 2023 +0100 +++ b/libfsclient/lib/src/process.cc Fri Mar 03 18:15:38 2023 +0100 @@ -46,16 +46,24 @@ return process; } +/* Discard the given process. */ + +void process_close(process_t *process) +{ + if (process == NULL) + return; + + if (l4_is_valid_cap(process->ref)) + ipc_cap_free_um(process->ref); + + process_init(process); +} + /* Initialise the given process structure. */ void process_init(process_t *process) { process->ref = L4_INVALID_CAP; - - /* Initialise the notifiable section of the structure. */ - - process->notifiable.notifications = 0; - process->notifiable.base = (notifiable_base_t *) process; } /* Start a process using the given arguments. @@ -94,6 +102,11 @@ err = creator.start(argc, &process->ref); + /* Initialise the notifiable section of the structure. */ + + process->notifiable.notifications = 0; + process->notifiable.base = (notifiable_base_t *) process; + /* Close the context, although a separate mechanism could permit contexts to open several processes. */ @@ -187,7 +200,10 @@ if (!err && (process->notifiable.notifications & NOTIFY_TASK_SIGNAL) && (process->notifiable.values.sig == 0)) + { process_notify_unsubscribe(process, notifier); + process_close(process); + } return err; } @@ -206,7 +222,10 @@ if (!err && ((*process)->notifiable.notifications & NOTIFY_TASK_SIGNAL) && ((*process)->notifiable.values.sig == 0)) + { process_notify_unsubscribe(*process, notifier); + process_close(*process); + } return err; }