paul@483 | 1 | /* |
paul@483 | 2 | * Process-related convenience functions. |
paul@483 | 3 | * |
paul@483 | 4 | * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk> |
paul@483 | 5 | * |
paul@483 | 6 | * This program is free software; you can redistribute it and/or |
paul@483 | 7 | * modify it under the terms of the GNU General Public License as |
paul@483 | 8 | * published by the Free Software Foundation; either version 2 of |
paul@483 | 9 | * the License, or (at your option) any later version. |
paul@483 | 10 | * |
paul@483 | 11 | * This program is distributed in the hope that it will be useful, |
paul@483 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@483 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@483 | 14 | * GNU General Public License for more details. |
paul@483 | 15 | * |
paul@483 | 16 | * You should have received a copy of the GNU General Public License |
paul@483 | 17 | * along with this program; if not, write to the Free Software |
paul@483 | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@483 | 19 | * Boston, MA 02110-1301, USA |
paul@483 | 20 | */ |
paul@483 | 21 | |
paul@483 | 22 | #include <ipc/cap_alloc.h> |
paul@483 | 23 | #include <ipc/mem_ipc.h> |
paul@531 | 24 | #include <notifier/notifier.h> |
paul@507 | 25 | #include <systypes/env.h> |
paul@483 | 26 | |
paul@483 | 27 | #include <stdio.h> |
paul@483 | 28 | #include <stdlib.h> |
paul@483 | 29 | |
paul@491 | 30 | #include "process_creator_context_client.h" |
paul@483 | 31 | |
paul@483 | 32 | #include "file.h" |
paul@483 | 33 | #include "process.h" |
paul@483 | 34 | |
paul@483 | 35 | |
paul@483 | 36 | |
paul@483 | 37 | /* Create a new process object. */ |
paul@483 | 38 | |
paul@483 | 39 | process_t *process_new() |
paul@483 | 40 | { |
paul@483 | 41 | process_t *process = (process_t *) malloc(sizeof(process_t)); |
paul@483 | 42 | |
paul@483 | 43 | if (process == NULL) |
paul@483 | 44 | return NULL; |
paul@483 | 45 | |
paul@483 | 46 | process_init(process); |
paul@483 | 47 | return process; |
paul@483 | 48 | } |
paul@483 | 49 | |
paul@492 | 50 | /* Discard the given process. */ |
paul@492 | 51 | |
paul@492 | 52 | void process_close(process_t *process) |
paul@492 | 53 | { |
paul@492 | 54 | if (process == NULL) |
paul@492 | 55 | return; |
paul@492 | 56 | |
paul@492 | 57 | if (l4_is_valid_cap(process->ref)) |
paul@492 | 58 | ipc_cap_free_um(process->ref); |
paul@492 | 59 | |
paul@492 | 60 | process_init(process); |
paul@492 | 61 | } |
paul@492 | 62 | |
paul@483 | 63 | /* Initialise the given process structure. */ |
paul@483 | 64 | |
paul@483 | 65 | void process_init(process_t *process) |
paul@483 | 66 | { |
paul@483 | 67 | process->ref = L4_INVALID_CAP; |
paul@483 | 68 | } |
paul@483 | 69 | |
paul@491 | 70 | /* Start a process using the given arguments. |
paul@491 | 71 | NOTE: This does not yet obtain input/output pipes. */ |
paul@483 | 72 | |
paul@491 | 73 | long process_start(process_t *process, int argc, char *argv[]) |
paul@483 | 74 | { |
paul@507 | 75 | l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME); |
paul@483 | 76 | |
paul@483 | 77 | if (l4_is_invalid_cap(server)) |
paul@507 | 78 | return -L4_ENOENT; |
paul@483 | 79 | |
paul@491 | 80 | /* Obtain a context for process creation. */ |
paul@491 | 81 | |
paul@491 | 82 | file_t context; |
paul@491 | 83 | long err = file_context(&context, server); |
paul@491 | 84 | |
paul@491 | 85 | if (err) |
paul@491 | 86 | return err; |
paul@491 | 87 | |
paul@491 | 88 | offset_t pos = 0, written; |
paul@483 | 89 | |
paul@491 | 90 | for (int i = 0; i < argc; i++) |
paul@491 | 91 | { |
paul@491 | 92 | if (!file_string_set(&context, argv[i], pos, &written)) |
paul@491 | 93 | return -L4_ENOMEM; |
paul@491 | 94 | |
paul@491 | 95 | pos += written + 1; |
paul@491 | 96 | } |
paul@491 | 97 | |
paul@491 | 98 | /* Obtain a client for the process creator context. */ |
paul@491 | 99 | |
paul@491 | 100 | client_ProcessCreatorContext creator(context.ref); |
paul@483 | 101 | |
paul@484 | 102 | /* Start the process, obtaining a reference to it. */ |
paul@483 | 103 | |
paul@491 | 104 | err = creator.start(argc, &process->ref); |
paul@491 | 105 | |
paul@492 | 106 | /* Initialise the notifiable section of the structure. */ |
paul@492 | 107 | |
paul@492 | 108 | process->notifiable.notifications = 0; |
paul@492 | 109 | process->notifiable.base = (notifiable_base_t *) process; |
paul@492 | 110 | |
paul@491 | 111 | /* Close the context, although a separate mechanism could permit contexts to |
paul@491 | 112 | open several processes. */ |
paul@491 | 113 | |
paul@491 | 114 | file_close(&context); |
paul@491 | 115 | return err; |
paul@483 | 116 | } |
paul@483 | 117 | |
paul@483 | 118 | |
paul@483 | 119 | |
paul@483 | 120 | /* NOTE: Much of the code below could be unified with the file-related |
paul@483 | 121 | notification code. */ |
paul@483 | 122 | |
paul@483 | 123 | /* Opaque notifier type for process_notifier_t. */ |
paul@483 | 124 | |
paul@483 | 125 | struct process_notifier |
paul@483 | 126 | { |
paul@483 | 127 | ObjectNotifier *obj; |
paul@483 | 128 | }; |
paul@483 | 129 | |
paul@483 | 130 | /* Conversion to the generic notification types. */ |
paul@483 | 131 | |
paul@483 | 132 | notifiable_t *process_notifiable(process_t *process) |
paul@483 | 133 | { |
paul@483 | 134 | return &process->notifiable; |
paul@483 | 135 | } |
paul@483 | 136 | |
paul@483 | 137 | /* Return the notification flags for a process. */ |
paul@483 | 138 | |
paul@483 | 139 | notify_flags_t process_notifications(process_t *process) |
paul@483 | 140 | { |
paul@483 | 141 | return process->notifiable.notifications; |
paul@483 | 142 | } |
paul@483 | 143 | |
paul@483 | 144 | /* Return the notification values for a process. */ |
paul@483 | 145 | |
paul@483 | 146 | notify_values_t process_notification_values(process_t *process) |
paul@483 | 147 | { |
paul@483 | 148 | return process->notifiable.values; |
paul@483 | 149 | } |
paul@483 | 150 | |
paul@483 | 151 | /* Close a notifier object. */ |
paul@483 | 152 | |
paul@483 | 153 | void process_notify_close(process_notifier_t *notifier) |
paul@483 | 154 | { |
paul@483 | 155 | delete notifier->obj; |
paul@483 | 156 | delete notifier; |
paul@483 | 157 | } |
paul@483 | 158 | |
paul@483 | 159 | /* Obtain a local notifier object. */ |
paul@483 | 160 | |
paul@483 | 161 | process_notifier_t *process_notify_local() |
paul@483 | 162 | { |
paul@483 | 163 | process_notifier_t *notifier = new process_notifier_t; |
paul@483 | 164 | |
paul@483 | 165 | notifier->obj = notifier_get_local_notifier(); |
paul@483 | 166 | return notifier; |
paul@483 | 167 | } |
paul@483 | 168 | |
paul@483 | 169 | /* Obtain the task-wide notifier object. */ |
paul@483 | 170 | |
paul@483 | 171 | process_notifier_t *process_notify_task() |
paul@483 | 172 | { |
paul@483 | 173 | process_notifier_t *notifier = new process_notifier_t; |
paul@483 | 174 | |
paul@483 | 175 | notifier->obj = notifier_get_task_notifier(); |
paul@483 | 176 | return notifier; |
paul@483 | 177 | } |
paul@483 | 178 | |
paul@483 | 179 | /* Subscribe to notification events on a process. */ |
paul@483 | 180 | |
paul@484 | 181 | long process_notify_subscribe(process_t *process, notify_flags_t flags, process_notifier_t *notifier) |
paul@483 | 182 | { |
paul@484 | 183 | return notifier->obj->subscribe(process_notifiable(process), flags); |
paul@483 | 184 | } |
paul@483 | 185 | |
paul@483 | 186 | /* Unsubscribe from notification events on a process. */ |
paul@483 | 187 | |
paul@484 | 188 | long process_notify_unsubscribe(process_t *process, process_notifier_t *notifier) |
paul@483 | 189 | { |
paul@484 | 190 | return notifier->obj->unsubscribe(process_notifiable(process)); |
paul@483 | 191 | } |
paul@483 | 192 | |
paul@483 | 193 | /* Wait for a notification event on a process. */ |
paul@483 | 194 | |
paul@483 | 195 | long process_notify_wait_process(process_t *process, process_notifier_t *notifier) |
paul@483 | 196 | { |
paul@483 | 197 | SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj); |
paul@483 | 198 | long err = specific_notifier->wait_object(process_notifiable(process)); |
paul@483 | 199 | |
paul@484 | 200 | /* Unsubscribe if a termination notification has been received. */ |
paul@483 | 201 | |
paul@484 | 202 | if (!err && (process->notifiable.notifications & NOTIFY_TASK_SIGNAL) && |
paul@484 | 203 | (process->notifiable.values.sig == 0)) |
paul@492 | 204 | { |
paul@484 | 205 | process_notify_unsubscribe(process, notifier); |
paul@492 | 206 | process_close(process); |
paul@492 | 207 | } |
paul@483 | 208 | |
paul@483 | 209 | return err; |
paul@483 | 210 | } |
paul@483 | 211 | |
paul@483 | 212 | /* Wait for notification events on processes. */ |
paul@483 | 213 | |
paul@483 | 214 | long process_notify_wait_processes(process_t **process, process_notifier_t *notifier) |
paul@483 | 215 | { |
paul@483 | 216 | GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj); |
paul@483 | 217 | notifiable_t *notifiable; |
paul@483 | 218 | long err = general_notifier->wait(¬ifiable); |
paul@483 | 219 | |
paul@483 | 220 | *process = (process_t *) notifiable->base; |
paul@483 | 221 | |
paul@484 | 222 | /* Unsubscribe if a termination notification has been received. */ |
paul@483 | 223 | |
paul@484 | 224 | if (!err && ((*process)->notifiable.notifications & NOTIFY_TASK_SIGNAL) && |
paul@484 | 225 | ((*process)->notifiable.values.sig == 0)) |
paul@492 | 226 | { |
paul@484 | 227 | process_notify_unsubscribe(*process, notifier); |
paul@492 | 228 | process_close(*process); |
paul@492 | 229 | } |
paul@483 | 230 | |
paul@483 | 231 | return err; |
paul@483 | 232 | } |
paul@483 | 233 | |
paul@483 | 234 | // vim: tabstop=2 expandtab shiftwidth=2 |