1 /* 2 * Process-related convenience functions. 3 * 4 * Copyright (C) 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 <ipc/cap_alloc.h> 23 #include <ipc/mem_ipc.h> 24 #include <notifier/notifier.h> 25 #include <systypes/env.h> 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 30 #include "process_creator_context_client.h" 31 32 #include "file.h" 33 #include "process.h" 34 35 36 37 /* Create a new process object. */ 38 39 process_t *process_new() 40 { 41 process_t *process = (process_t *) malloc(sizeof(process_t)); 42 43 if (process == NULL) 44 return NULL; 45 46 process_init(process); 47 return process; 48 } 49 50 /* Discard the given process. */ 51 52 void process_close(process_t *process) 53 { 54 if (process == NULL) 55 return; 56 57 if (l4_is_valid_cap(process->ref)) 58 ipc_cap_free_um(process->ref); 59 60 process_init(process); 61 } 62 63 /* Initialise the given process structure. */ 64 65 void process_init(process_t *process) 66 { 67 process->ref = L4_INVALID_CAP; 68 69 /* Initialise the notifiable section of the structure. */ 70 71 process->notifiable.notifications = 0; 72 process->notifiable.base = (notifiable_base_t *) process; 73 process->notifiable.handler = NULL; 74 } 75 76 /* Start a process using the given arguments. 77 NOTE: This does not yet obtain input/output pipes. */ 78 79 long process_start(process_t *process, int argc, char *argv[]) 80 { 81 l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME); 82 83 if (l4_is_invalid_cap(server)) 84 return -L4_ENOENT; 85 86 /* Obtain a context for process creation. */ 87 88 file_t context; 89 long err = file_context(&context, server); 90 91 if (err) 92 return err; 93 94 offset_t pos = 0, written; 95 96 for (int i = 0; i < argc; i++) 97 { 98 if (!file_string_set(&context, argv[i], pos, &written)) 99 return -L4_ENOMEM; 100 101 pos += written + 1; 102 } 103 104 /* Obtain a client for the process creator context. */ 105 106 client_ProcessCreatorContext creator(context.ref); 107 108 /* Start the process, obtaining a reference to it. */ 109 110 err = creator.start(argc, &process->ref); 111 112 /* Initialise the notifiable section of the structure. */ 113 114 process->notifiable.notifications = 0; 115 process->notifiable.base = (notifiable_base_t *) process; 116 117 /* Close the context, although a separate mechanism could permit contexts to 118 open several processes. */ 119 120 file_close(&context); 121 return err; 122 } 123 124 125 126 /* NOTE: Much of the code below could be unified with the file-related 127 notification code. */ 128 129 /* Opaque notifier type for process_notifier_t. */ 130 131 struct process_notifier 132 { 133 ObjectNotifier *obj; 134 }; 135 136 /* Conversion to the generic notification types. */ 137 138 notifiable_t *process_notifiable(process_t *process) 139 { 140 return &process->notifiable; 141 } 142 143 /* Return the notification flags for a process. */ 144 145 notify_flags_t process_notifications(process_t *process) 146 { 147 return process->notifiable.notifications; 148 } 149 150 /* Return the notification values for a process. */ 151 152 notify_values_t process_notification_values(process_t *process) 153 { 154 return process->notifiable.values; 155 } 156 157 /* Close a notifier object. */ 158 159 void process_notify_close(process_notifier_t *notifier) 160 { 161 delete notifier->obj; 162 delete notifier; 163 } 164 165 /* Obtain a local notifier object. */ 166 167 process_notifier_t *process_notify_local() 168 { 169 process_notifier_t *notifier = new process_notifier_t; 170 171 notifier->obj = notifier_get_local_notifier(); 172 return notifier; 173 } 174 175 /* Obtain the task-wide notifier object. */ 176 177 process_notifier_t *process_notify_task() 178 { 179 process_notifier_t *notifier = new process_notifier_t; 180 181 notifier->obj = notifier_get_task_notifier(); 182 return notifier; 183 } 184 185 /* Subscribe to notification events on a process. */ 186 187 long process_notify_subscribe(process_t *process, notify_flags_t flags, process_notifier_t *notifier) 188 { 189 return notifier->obj->subscribe(process_notifiable(process), flags); 190 } 191 192 /* Unsubscribe from notification events on a process. */ 193 194 long process_notify_unsubscribe(process_t *process, process_notifier_t *notifier) 195 { 196 return notifier->obj->unsubscribe(process_notifiable(process)); 197 } 198 199 /* Wait for a notification event on a process. */ 200 201 long process_notify_wait_process(process_t *process, process_notifier_t *notifier) 202 { 203 long err = notifier->obj->wait_object(process_notifiable(process)); 204 205 /* Unsubscribe if a termination notification has been received. */ 206 207 if (!err && (process->notifiable.notifications & NOTIFY_TASK_SIGNAL) && 208 (process->notifiable.values.sig == 0)) 209 { 210 process_notify_unsubscribe(process, notifier); 211 process_close(process); 212 } 213 214 return err; 215 } 216 217 /* Wait for notification events on processes. */ 218 219 long process_notify_wait_processes(process_t **process, process_notifier_t *notifier) 220 { 221 notifiable_t *notifiable; 222 long err = notifier->obj->wait(¬ifiable); 223 224 *process = (process_t *) notifiable->base; 225 226 /* Unsubscribe if a termination notification has been received. */ 227 228 if (!err && ((*process)->notifiable.notifications & NOTIFY_TASK_SIGNAL) && 229 ((*process)->notifiable.values.sig == 0)) 230 { 231 process_notify_unsubscribe(*process, notifier); 232 process_close(*process); 233 } 234 235 return err; 236 } 237 238 // vim: tabstop=2 expandtab shiftwidth=2