ChorusOS 5.0 Application Developer's Guide

Spawning a Process or Actor

Processes can be spawned using the posix_spawn system call. Actors can also be spawned using the afexec system call.


Note -

Processes can also be launched using the fork() and exec() system calls. For more information, see the fork(2POSIX) and exec(3POSIX) man pages.


Spawning a Process

A process can spawn another process dynamically using the posix_spawn() or posix_spawnp() function. This spawned process can be either a supervisor or a user process.

Example 3-3 creates a new process. The spawned process executes a binary file stored in the file named path. Note that the example uses posix_spawnp() and not posix_spawn(). The posix_spawnp() function searches for the binary file in all directories specified by the PATH environment variable. If you use posix_spawn() instead, you must specify the full path to the binary file.

The main thread of this process runs the main routine of the program. This thread has the same scheduling attributes and stack size as an embedded actor loaded manually.

argv and spawnedEnv are pointers to the array of arguments and environments that are received by the newly created process.

If successful, all posix_spawn() and posix_spawnp() routines return 0. Otherwise, they return an error code.


Note -

The value of errno is unspecified.


In the example:


Example 3-3 Spawning a Process

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <span.h>
#include <string.h>

char*   spawnedArgs[3];
char*   spawnedEnv[1];
char*   tagPtr = "Welcome newly created process!";

int main(int argc, char* argv[])
{
  int          res;
  pid_t        pid;
  
  if (argc == 1) {
        /*
         * This is the first process (or spawning process):
         *   Binary file used to load this process is passed
         *   as argv[0],
         *
         *   Set an argument in order to enable the second
         *   process to know it is the second one.
         */
    spawnedArgs[0] = argv[0];
    spawnedArgs[1] = tagPtr;
    spawnedArgs[2] = NULL;
    spawnedEnv[0] = NULL;
    res = posix_spawnp(&pid, spawnedArgs[0], NULL, 
          NULL, spawnedArgs, spawnedEnv);
    if (res != 0) {
      printf("Cannot spawn second process, error %d\n", res);
      exit(1);
    }
    printf("I successfully created a process whose pid is %d\n", pid);
  } else {
        /*
         * This is the spawned process:
         *   Check the number of args,
         *   Print args,
         *   Exit
         */
    if ((argc == 2) && (strcmp(tagPtr, argv[1]) == 0)) {
            /*
             * This is really the spawned process.
             */
        printf("My spawning process passed me this argument: %s\n",
               argv[1]);
    } else {
        printf("You ran %s with an argument. Do not!\n", argv[0]);
        exit(1);
    }
  }
  exit(0);
}

Spawning an Actor

The ChorusOS operating system enables an actor to spawn another actor dynamically from a binary file. This spawned actor may be either a supervisor or a user actor. This service is similar to the exec() UNIX system call:

#include <cx/afexec.h>
int afexecve (const char* path,
              KnCap* actorCap,
              const AcParam* param,
              char* const* argv,
              char* const* envp); 

This service creates a new actor whose capability is returned by the system at the location pointed to by the actorCap argument. The actor created executes the binary file stored in the file named path. If the file named path does not exist, afexec() will attempt to find path.gz. The main thread of this actor runs the main routine of the program. This thread has the same scheduling attributes and stack size as an actor loaded using the arun command.

argv and envp are pointers to the array of arguments and environments that will be received by the newly created actor.

There are several variants of the afexec(2K) service that are similar to the UNIX exec() call variants. If successful, all afexec(2K) routines return the actor identifier of the newly created actor. Otherwise, they return -1, and the error code is returned in the errno variable.

In most instances, you do not need to use the afexec(2K) service. Instead, simply execute the actor manually, or include the actor as part of the system image. However, for convenience, some examples within this chapter do use this service.

The following example illustrates the use of the afexecve(2K) service call. In this example:


Note -

This example assumes that argv[0] is valid, and that the actor is linked with the os/lib/libc.a library because the library is common to both user and supervisor actors. Referencing argv[0] without checking if argc is greater than zero can cause the actor to create an exception and be deleted.



Example 3-4 Spawning an Actor

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <cx/afexec.h>

AcParam param;
char*   spawnedArgs[3];
char*   tagPtr = "Welcome newly created actor!";

int main(int argc, char** argv, char**envp)
{
  KnCap        spawnedCap;
  int          res;

  if (argc == 1) {
        /*
         * This is the first actor (or spawning actor):
         *   Binary file used to load this actor is passed
         *   by "arun" as argv[0],
         * 
         *   Set an argument in order to enable the second
         *   actor to know it is the second one.
         */

    param.acFlags = AFX_ANY_SPACE;

    spawnedArgs[0] = argv[0];
    spawnedArgs[1] = tagPtr;
    spawnedArgs[2] = NULL;
 
        /*
         * Other fields are implicitly set to NULL, as 
         * param is allocated within the bss of the program.
         */
    res = afexecve(argv[0], &spawnedCap, &param, spawnedArgs, envp);

    if (res == -1) {
      printf("Cannot spawn second actor, error %d\n", errno);
      exit(1);
    }
    printf("I succeeded creating actor whose pid is %d\n", res);

  } else {

        /*
         * This is the spawned actor:
         * Check the number of args,
         * Print args,
         * Exit
         */
    if ((argc == 2) && (strcmp(tagPtr, argv[1]) == 0)) {

        /*
				* This is really the spawned actor.
         */
	printf("My spawning actor passed me this argument: %s\n", argv[1]);
    } else {
	    printf("You ran %s with an argument, you should not!\n", argv[0]);
	    exit(1);
    }

  }
  return 0; 
}