ChorusOS 4.0 Introduction

Spawning an Actor

So far, two ways of loading and running actors have been described: either the inclusion of the actor as part of the system image, or the usage of the arun mechanism. The ChorusOS operating system also enables an actor to dynamically spawn another actor 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 <am/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 will execute the binary file stored in the file named path. The main thread of this actor will run the main routine of the program. This thread will have the same scheduling attributes and stack size as an actor loaded using the arun mechanism.

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

The afexec() service comes in several variants, similar to the UNIX exec() call variants. When successful, all afexec() routines return the actor identifier of the newly created actor. Otherwise, they return -1, and the error code is returned in the errno variable.

Most of the time, application writers will not need to use the afexec() service. They will use either the arun facility or include the actor as part of the system image. However, for convenience, some examples within this document do use this service.

Below is an example of use of the afexecve() service call.


Example 5-3 Spawning an Actor

#include <stdio.h>
#include <errno.h>
#include <am/afexec.h>

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

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_USER_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 segment 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 aid 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);
    }
  }
  exit(0);
}



Note -

This example assumes that argv[0] is valid, and the actor is linked with the ~lib/classix/libcx.a library, since 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 make an exception and be deleted.