L4Re/departure

Annotated libfsclient/lib/src/process.cc

578:2eef58fe12d1
11 months ago Paul Boddie Introduced process spawning convenience functions.
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@559 37
/* Utility functions. */
paul@559 38
paul@575 39
static bool _process_terminated(notifiable_t *notifiable)
paul@559 40
{
paul@575 41
  return ((notifiable->notifications & NOTIFY_TASK_SIGNAL) &&
paul@575 42
          (notifiable->values.sig == 0)) ||
paul@575 43
         (notifiable->notifications & NOTIFY_TASK_ERROR);
paul@559 44
}
paul@559 45
paul@559 46
paul@559 47
paul@483 48
/* Create a new process object. */
paul@483 49
paul@483 50
process_t *process_new()
paul@483 51
{
paul@483 52
  process_t *process = (process_t *) malloc(sizeof(process_t));
paul@483 53
paul@483 54
  if (process == NULL)
paul@483 55
    return NULL;
paul@483 56
paul@483 57
  process_init(process);
paul@483 58
  return process;
paul@483 59
}
paul@483 60
paul@492 61
/* Discard the given process. */
paul@492 62
paul@492 63
void process_close(process_t *process)
paul@492 64
{
paul@492 65
  if (process == NULL)
paul@492 66
    return;
paul@492 67
paul@492 68
  if (l4_is_valid_cap(process->ref))
paul@492 69
    ipc_cap_free_um(process->ref);
paul@492 70
paul@492 71
  process_init(process);
paul@492 72
}
paul@492 73
paul@559 74
/* Return any process initiation error. */
paul@559 75
paul@559 76
long process_error(process_t *process)
paul@559 77
{
paul@559 78
  if (process->notifiable.notifications & NOTIFY_TASK_ALL)
paul@559 79
    return process->notifiable.values.val;
paul@559 80
  else
paul@559 81
    return L4_EOK;
paul@559 82
}
paul@559 83
paul@578 84
/* Discard and free the given process, similar to process_close but freeing the
paul@578 85
   structure instead of reinitialising it. */
paul@578 86
paul@578 87
void process_free(process_t *process)
paul@578 88
{
paul@578 89
  if (process == NULL)
paul@578 90
    return;
paul@578 91
paul@578 92
  if (l4_is_valid_cap(process->ref))
paul@578 93
    ipc_cap_free_um(process->ref);
paul@578 94
paul@578 95
  free(process);
paul@578 96
}
paul@578 97
paul@483 98
/* Initialise the given process structure. */
paul@483 99
paul@483 100
void process_init(process_t *process)
paul@483 101
{
paul@483 102
  process->ref = L4_INVALID_CAP;
paul@555 103
paul@555 104
  /* Initialise the notifiable section of the structure. */
paul@555 105
paul@555 106
  process->notifiable.notifications = 0;
paul@559 107
  process->notifiable.pending_notifications = 0;
paul@555 108
  process->notifiable.base = (notifiable_base_t *) process;
paul@555 109
  process->notifiable.handler = NULL;
paul@483 110
}
paul@483 111
paul@578 112
/* A convenience function for creating and starting a process. */
paul@578 113
paul@578 114
long process_spawn(int argc, const char *argv[], process_t **process)
paul@578 115
{
paul@578 116
  *process = process_new();
paul@578 117
paul@578 118
  /* Start the process with the given arguments. */
paul@578 119
paul@578 120
  if (*process != NULL)
paul@578 121
    return process_start(*process, argc, argv);
paul@578 122
  else
paul@578 123
    return -L4_ENOMEM;
paul@578 124
}
paul@578 125
paul@491 126
/* Start a process using the given arguments.
paul@491 127
   NOTE: This does not yet obtain input/output pipes. */
paul@483 128
paul@559 129
long process_start(process_t *process, int argc, const char *argv[])
paul@483 130
{
paul@507 131
  l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME);
paul@483 132
paul@483 133
  if (l4_is_invalid_cap(server))
paul@507 134
    return -L4_ENOENT;
paul@483 135
paul@491 136
  /* Obtain a context for process creation. */
paul@491 137
paul@491 138
  file_t context;
paul@491 139
  long err = file_context(&context, server);
paul@491 140
paul@491 141
  if (err)
paul@491 142
    return err;
paul@491 143
paul@491 144
  offset_t pos = 0, written;
paul@483 145
paul@491 146
  for (int i = 0; i < argc; i++)
paul@491 147
  {
paul@491 148
    if (!file_string_set(&context, argv[i], pos, &written))
paul@491 149
      return -L4_ENOMEM;
paul@491 150
paul@491 151
    pos += written + 1;
paul@491 152
  }
paul@491 153
paul@491 154
  /* Obtain a client for the process creator context. */
paul@491 155
paul@491 156
  client_ProcessCreatorContext creator(context.ref);
paul@483 157
paul@484 158
  /* Start the process, obtaining a reference to it. */
paul@483 159
paul@491 160
  err = creator.start(argc, &process->ref);
paul@491 161
paul@492 162
  /* Initialise the notifiable section of the structure. */
paul@492 163
paul@492 164
  process->notifiable.notifications = 0;
paul@559 165
  process->notifiable.pending_notifications = 0;
paul@492 166
  process->notifiable.base = (notifiable_base_t *) process;
paul@492 167
paul@491 168
  /* Close the context, although a separate mechanism could permit contexts to
paul@491 169
     open several processes. */
paul@491 170
paul@491 171
  file_close(&context);
paul@491 172
  return err;
paul@483 173
}
paul@483 174
paul@578 175
/* A convenience function for waiting for a started process. */
paul@578 176
paul@578 177
long process_wait(process_t *process, notify_flags_t *flags, notify_values_t *values)
paul@578 178
{
paul@578 179
  /* Obtain the common notifier. */
paul@578 180
paul@578 181
  notifier_t *notifier = notify_get_task();
paul@578 182
paul@578 183
  /* Subscribe to the process for notifications. */
paul@578 184
paul@578 185
  long err = notify_subscribe(process_notifiable(process), NOTIFY_TASK_ALL, notifier);
paul@578 186
paul@578 187
  if (err)
paul@578 188
    return err;
paul@578 189
paul@578 190
  /* Wait for a signal from the process. */
paul@578 191
paul@578 192
  err = process_notify_wait_process(process, notifier);
paul@578 193
paul@578 194
  if (err)
paul@578 195
    return err;
paul@578 196
paul@578 197
  /* Obtain the notification flags and values. */
paul@578 198
paul@578 199
  *flags = process_notifications(process);
paul@578 200
  *values = process_notification_values(process);
paul@578 201
paul@578 202
  /* Obtain any error, closing the process. */
paul@578 203
paul@578 204
  err = process_error(process);
paul@578 205
  process_free(process);
paul@578 206
  return err;
paul@578 207
}
paul@578 208
paul@483 209
paul@483 210
paul@483 211
/* Conversion to the generic notification types. */
paul@483 212
paul@483 213
notifiable_t *process_notifiable(process_t *process)
paul@483 214
{
paul@575 215
  return notify_notifiable((notifiable_base_t *) process);
paul@483 216
}
paul@483 217
paul@483 218
/* Return the notification flags for a process. */
paul@483 219
paul@483 220
notify_flags_t process_notifications(process_t *process)
paul@483 221
{
paul@575 222
  return notify_notifications((notifiable_base_t *) process);
paul@483 223
}
paul@483 224
paul@483 225
/* Return the notification values for a process. */
paul@483 226
paul@483 227
notify_values_t process_notification_values(process_t *process)
paul@483 228
{
paul@575 229
  return notify_notification_values((notifiable_base_t *) process);
paul@483 230
}
paul@483 231
paul@483 232
/* Wait for a notification event on a process. */
paul@483 233
paul@575 234
long process_notify_wait_process(process_t *process, notifier_t *notifier)
paul@483 235
{
paul@575 236
  long err = notify_wait(process_notifiable(process), notifier);
paul@483 237
paul@484 238
  /* Unsubscribe if a termination notification has been received. */
paul@483 239
paul@575 240
  if (!err && _process_terminated(process_notifiable(process)))
paul@575 241
    notify_unsubscribe(process_notifiable(process), notifier);
paul@483 242
paul@483 243
  return err;
paul@483 244
}
paul@483 245
paul@483 246
/* Wait for notification events on processes. */
paul@483 247
paul@575 248
long process_notify_wait_processes(process_t **process, notifier_t *notifier)
paul@483 249
{
paul@483 250
  notifiable_t *notifiable;
paul@575 251
  long err = notify_wait_many(&notifiable, notifier);
paul@483 252
paul@483 253
  *process = (process_t *) notifiable->base;
paul@483 254
paul@484 255
  /* Unsubscribe if a termination notification has been received. */
paul@483 256
paul@575 257
  if (!err && _process_terminated(notifiable))
paul@575 258
    notify_unsubscribe(notifiable, notifier);
paul@483 259
paul@483 260
  return err;
paul@483 261
}
paul@483 262
paul@483 263
// vim: tabstop=2 expandtab shiftwidth=2