L4Re/departure

libfsclient/lib/src/process.cc

575:66ab00dc7dd0
11 months ago Paul Boddie Consolidated some of the notification functionality.
     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 /* Utility functions. */    38     39 static bool _process_terminated(notifiable_t *notifiable)    40 {    41   return ((notifiable->notifications & NOTIFY_TASK_SIGNAL) &&    42           (notifiable->values.sig == 0)) ||    43          (notifiable->notifications & NOTIFY_TASK_ERROR);    44 }    45     46     47     48 /* Create a new process object. */    49     50 process_t *process_new()    51 {    52   process_t *process = (process_t *) malloc(sizeof(process_t));    53     54   if (process == NULL)    55     return NULL;    56     57   process_init(process);    58   return process;    59 }    60     61 /* Discard the given process. */    62     63 void process_close(process_t *process)    64 {    65   if (process == NULL)    66     return;    67     68   if (l4_is_valid_cap(process->ref))    69     ipc_cap_free_um(process->ref);    70     71   process_init(process);    72 }    73     74 /* Return any process initiation error. */    75     76 long process_error(process_t *process)    77 {    78   if (process->notifiable.notifications & NOTIFY_TASK_ALL)    79     return process->notifiable.values.val;    80   else    81     return L4_EOK;    82 }    83     84 /* Initialise the given process structure. */    85     86 void process_init(process_t *process)    87 {    88   process->ref = L4_INVALID_CAP;    89     90   /* Initialise the notifiable section of the structure. */    91     92   process->notifiable.notifications = 0;    93   process->notifiable.pending_notifications = 0;    94   process->notifiable.base = (notifiable_base_t *) process;    95   process->notifiable.handler = NULL;    96 }    97     98 /* Start a process using the given arguments.    99    NOTE: This does not yet obtain input/output pipes. */   100    101 long process_start(process_t *process, int argc, const char *argv[])   102 {   103   l4_cap_idx_t server = l4re_env_get_cap(ENV_PROCESS_SERVER_NAME);   104    105   if (l4_is_invalid_cap(server))   106     return -L4_ENOENT;   107    108   /* Obtain a context for process creation. */   109    110   file_t context;   111   long err = file_context(&context, server);   112    113   if (err)   114     return err;   115    116   offset_t pos = 0, written;   117    118   for (int i = 0; i < argc; i++)   119   {   120     if (!file_string_set(&context, argv[i], pos, &written))   121       return -L4_ENOMEM;   122    123     pos += written + 1;   124   }   125    126   /* Obtain a client for the process creator context. */   127    128   client_ProcessCreatorContext creator(context.ref);   129    130   /* Start the process, obtaining a reference to it. */   131    132   err = creator.start(argc, &process->ref);   133    134   /* Initialise the notifiable section of the structure. */   135    136   process->notifiable.notifications = 0;   137   process->notifiable.pending_notifications = 0;   138   process->notifiable.base = (notifiable_base_t *) process;   139    140   /* Close the context, although a separate mechanism could permit contexts to   141      open several processes. */   142    143   file_close(&context);   144   return err;   145 }   146    147    148    149 /* Conversion to the generic notification types. */   150    151 notifiable_t *process_notifiable(process_t *process)   152 {   153   return notify_notifiable((notifiable_base_t *) process);   154 }   155    156 /* Return the notification flags for a process. */   157    158 notify_flags_t process_notifications(process_t *process)   159 {   160   return notify_notifications((notifiable_base_t *) process);   161 }   162    163 /* Return the notification values for a process. */   164    165 notify_values_t process_notification_values(process_t *process)   166 {   167   return notify_notification_values((notifiable_base_t *) process);   168 }   169    170 /* Wait for a notification event on a process. */   171    172 long process_notify_wait_process(process_t *process, notifier_t *notifier)   173 {   174   long err = notify_wait(process_notifiable(process), notifier);   175    176   /* Unsubscribe if a termination notification has been received. */   177    178   if (!err && _process_terminated(process_notifiable(process)))   179     notify_unsubscribe(process_notifiable(process), notifier);   180    181   return err;   182 }   183    184 /* Wait for notification events on processes. */   185    186 long process_notify_wait_processes(process_t **process, notifier_t *notifier)   187 {   188   notifiable_t *notifiable;   189   long err = notify_wait_many(&notifiable, notifier);   190    191   *process = (process_t *) notifiable->base;   192    193   /* Unsubscribe if a termination notification has been received. */   194    195   if (!err && _process_terminated(notifiable))   196     notify_unsubscribe(notifiable, notifier);   197    198   return err;   199 }   200    201 // vim: tabstop=2 expandtab shiftwidth=2