1 /* 2 * A process monitor abstraction. 3 * 4 * Copyright (C) 2022, 2023, 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/sys/thread.h> 23 24 #include <ipc/cap_alloc.h> 25 #include <ipc/map.h> 26 #include <systypes/base.h> 27 28 #include <stdio.h> 29 30 #include "process_monitor.h" 31 #include "parent_notification_object_server.h" 32 33 34 35 /* A process monitor receiving signals from a task. */ 36 37 ProcessMonitor::ProcessMonitor(bool debug) 38 : NotificationSupport(), _debug(debug) 39 { 40 } 41 42 ipc_server_default_config_type ProcessMonitor::config() 43 { 44 return config_ParentNotificationObject; 45 } 46 47 48 49 /* Close the process monitor. */ 50 51 void ProcessMonitor::close() 52 { 53 if (_debug) 54 printf("Process monitor closing...\n"); 55 } 56 57 58 59 /* Capability management. */ 60 61 void ProcessMonitor::set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 62 { 63 _pager = cap; 64 _mapped_pager = mapped_cap; 65 } 66 67 void ProcessMonitor::set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 68 { 69 _parent = cap; 70 _mapped_parent = mapped_cap; 71 } 72 73 void ProcessMonitor::set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 74 { 75 _task = cap; 76 _mapped_task = mapped_cap; 77 } 78 79 void ProcessMonitor::set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 80 { 81 _thread = cap; 82 _mapped_thread = mapped_cap; 83 } 84 85 86 87 /* Lifecycle management. */ 88 89 void ProcessMonitor::pager_ended() 90 { 91 /* Release the program thread and its reference to this object, leaving only 92 the program initiator with a reference. When the initiator releases its 93 reference, this object will be closed. */ 94 95 if (l4_is_valid_cap(_thread)) 96 { 97 ipc_unmap_capability(_task, _mapped_thread); 98 ipc_cap_free_um(_thread); 99 _thread = L4_INVALID_CAP; 100 101 ipc_unmap_capability(_task, _mapped_parent); 102 } 103 104 /* Release the program task. This will release any capabilities that might be 105 blocking the initiator, such as those involving pipes or streams. */ 106 107 if (l4_is_valid_cap(_task)) 108 { 109 ipc_unmap_capability(_task, _mapped_task); 110 ipc_cap_free_um(_task); 111 _task = L4_INVALID_CAP; 112 } 113 } 114 115 116 117 /* Receive signals from a task. */ 118 119 long ProcessMonitor::signal(unsigned long sig, unsigned long val) 120 { 121 notify_all(NOTIFY_TASK_SIGNAL, (notify_values_t) {sig, val}); 122 123 /* Handle the termination event. */ 124 125 if (sig == 0) 126 { 127 if (_debug) 128 printf("Signal from task.\n"); 129 130 /* Cancel any IPC to avoid spurious pager warnings. */ 131 132 l4_thread_ex_regs(_pager, ~0UL, ~0UL, L4_THREAD_EX_REGS_CANCEL); 133 134 /* Once the program exits, the IPC gate connecting the program with its 135 internal pager can be released. This will cause the internal pager to 136 finish, which is then handled by the external pager. */ 137 138 if (l4_is_valid_cap(_pager)) 139 { 140 ipc_cap_free_um(_pager); 141 _pager = L4_INVALID_CAP; 142 } 143 144 /* The thread is not released here since the initiator of the process 145 needs to be able to receive a reference to this object, but if the 146 process terminates and the thread is released, this object may be 147 released before the initiator obtains a reference to it. */ 148 } 149 150 return L4_EOK; 151 } 152 153 154 155 /* Subscribe to notifications. */ 156 157 long ProcessMonitor::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) 158 { 159 unsubscribe(); 160 161 _notifier = notifier; 162 return NotificationSupport::subscribe(_notifier, flags); 163 } 164 165 /* Unsubscribe from notifications. */ 166 167 long ProcessMonitor::unsubscribe() 168 { 169 if (l4_is_valid_cap(_notifier)) 170 { 171 long err = NotificationSupport::unsubscribe(_notifier); 172 _notifier = L4_INVALID_CAP; 173 return err; 174 } 175 else 176 return L4_EOK; 177 } 178 179 /* vim: tabstop=2 expandtab shiftwidth=2 180 */