1 /* 2 * A process monitor abstraction. 3 * 4 * Copyright (C) 2022, 2023 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() 38 : NotificationSupport() 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 printf("Process monitor closing...\n"); 54 } 55 56 57 58 /* Capability management. */ 59 60 void ProcessMonitor::set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 61 { 62 _pager = cap; 63 _mapped_pager = mapped_cap; 64 } 65 66 void ProcessMonitor::set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 67 { 68 _parent = cap; 69 _mapped_parent = mapped_cap; 70 } 71 72 void ProcessMonitor::set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 73 { 74 _task = cap; 75 _mapped_task = mapped_cap; 76 } 77 78 void ProcessMonitor::set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap) 79 { 80 _thread = cap; 81 _mapped_thread = mapped_cap; 82 } 83 84 85 86 /* Lifecycle management. */ 87 88 void ProcessMonitor::pager_ended() 89 { 90 /* Release the program thread and its reference to this object, leaving only 91 the program initiator with a reference. When the initiator releases its 92 reference, this object will be closed. */ 93 94 if (l4_is_valid_cap(_thread)) 95 { 96 ipc_unmap_capability(_task, _mapped_thread); 97 ipc_cap_free_um(_thread); 98 _thread = L4_INVALID_CAP; 99 100 ipc_unmap_capability(_task, _mapped_parent); 101 } 102 103 /* Release the program task. This will release any capabilities that might be 104 blocking the initiator, such as those involving pipes or streams. */ 105 106 if (l4_is_valid_cap(_task)) 107 { 108 ipc_unmap_capability(_task, _mapped_task); 109 ipc_cap_free_um(_task); 110 _task = L4_INVALID_CAP; 111 } 112 } 113 114 115 116 /* Receive signals from a task. */ 117 118 long ProcessMonitor::signal(unsigned long sig, unsigned long val) 119 { 120 notify_all(NOTIFY_TASK_SIGNAL, (notify_values_t) {sig, val}); 121 122 /* Handle the termination event. */ 123 124 if (sig == 0) 125 { 126 printf("Signal from task.\n"); 127 128 /* Cancel any IPC to avoid spurious pager warnings. */ 129 130 l4_thread_ex_regs(_pager, ~0UL, ~0UL, L4_THREAD_EX_REGS_CANCEL); 131 132 /* Once the program exits, the IPC gate connecting the program with its 133 internal pager can be released. This will cause the internal pager to 134 finish, which is then handled by the external pager. */ 135 136 if (l4_is_valid_cap(_pager)) 137 { 138 ipc_cap_free_um(_pager); 139 _pager = L4_INVALID_CAP; 140 } 141 142 /* The thread is not released here since the initiator of the process 143 needs to be able to receive a reference to this object, but if the 144 process terminates and the thread is released, this object may be 145 released before the initiator obtains a reference to it. */ 146 } 147 148 return L4_EOK; 149 } 150 151 152 153 /* Subscribe to notifications. */ 154 155 long ProcessMonitor::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) 156 { 157 unsubscribe(); 158 159 _notifier = notifier; 160 return NotificationSupport::subscribe(_notifier, flags); 161 } 162 163 /* Unsubscribe from notifications. */ 164 165 long ProcessMonitor::unsubscribe() 166 { 167 if (l4_is_valid_cap(_notifier)) 168 { 169 long err = NotificationSupport::unsubscribe(_notifier); 170 _notifier = L4_INVALID_CAP; 171 return err; 172 } 173 else 174 return L4_EOK; 175 } 176 177 /* vim: tabstop=2 expandtab shiftwidth=2 178 */