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