ChorusOS 4.0 Introduction

Execution Environment of Actors

The execution environment of actors varies slightly depending on whether the actors have been loaded dynamically or at boot time.

An actor loaded at boot time does not have any arguments or environment. If it is linked with the embedded library, it may perform very simple input or output operations such as printing traces on the system console using the printf() C library routine. It may also read characters typed in from the keyboard of the system console through the scanf() C library routine. If it is linked with the libcx.a library, it must first open /dev/console three times in order to activate stdin, stdout, or stderr and allow printf() or scanf() operations on the system console. The main thread of an actor loaded at boot time will belong to the SCHED_FIFO scheduling policy, with an arbitrary priority depending on the rank of the actor within the system image. The size of the stack provided to the main thread of this type of actor is defined by a system-wide tunable parameter.

A dynamically loaded actor is started as a regular C program with arguments and environments:

int main(int argc, char** argv, char** envp)
{
        /* Main routine of a dynamically loaded actor */
        /* regardless of whether the actor is a user  */
        /* or supervisor actor.                       */
}

The standard input, output and error files of an extended actor may be redirected so that the I/O operations performed by this actor occur either on the system console, on a regular file (accessed through NFS) or on a terminal window of the host system. The main thread of a dynamically loaded actor has its scheduling policy, priority and stack size set according to system-wide tunable parameters.

Actor Context

The precise context of an actor depends on how the system is configured. An extended actor has a file context similar to the file context of a UNIX process: it has a root directory as well as a current directory. It may also create, open, close, read and write files or sockets.

An extended actor runs on behalf of a user who is identified by means of a credentials structure. The actor credentials include: the identifier of the user, the identifier of the group of the user as well as a possibly empty list of identifiers of supplementary groups. Readers familiar with the concept of credentials in UNIX should note that the ChorusOS operating system concept of credentials is simpler than the UNIX one. ChorusOS 4.0 does not differentiate between real or effective user/group identification as it is not supported.

These actor credentials are used for file access. They are also used when the ChorusOS operating system runs in secured mode to check the validity of an operation. For example, in secured mode only the superuser, whose user identifier is 0, may load supervisor actors.

Standard Input/Output (I/O)

An extended actor may take advantage of the entire C library for dealing with I/O. In addition to the I/O interface provided by the C library, an extended actor may also use POSIX I/O services such as open, read, or write, as well as POSIX socket services such as socket, bind, and connect.

The following program may be run as an actor, and illustrates the way in which the C library might be used from an actor.


Example 5-2 Using the C Library from an Actor

#include <stdio.h
#include <stdlib.h>
#include <chorus/stat.h>

#define  BUF_SIZE 80

struct stat st;

int main(int argc, char** argv, char** envp)
{
   FILE* file;
   FILE* filew;
   char* buf;
   int res;

   if (argc != 2 && argc != 3) {
      fprintf(stderr, "Usage: %s filename\n", argv[0]);
      exit(1);
   }

   file = fopen(argv[1], "r");

   if (file == NULL) {
      fprintf(stderr, "Cannot open file %s\n", argv[1]);
      exit(1);
   }

   res = stat(argv[1], &st);
   if (res < 0) {
      fprintf(stderr, "Cannot stat file\n");
      exit(1);
   }

   printf("File size is %d mode 0x%x\n", st.st_size, st.st_mode);

   buf = (char*) malloc(BUF_SIZE);
   if (buf == NULL) {
      fprintf(stderr, "Cannot allocate buffer\n");
      exit(1);
   }

   bzero(buf, BUF_SIZE);
   res = read(fileno(file), buf, 80);
   if (res == -1) {
      fprintf(stderr, "Cannot read file\n");
      exit(1);
   }

   printf("%s\n", buf);

   if (argv[2] != NULL) {
      filew = fopen(argv[2], "w");

      if (filew == NULL) {
         fprintf(stderr, "Cannot open file %s\n", argv[2]);
         exit(1);
      }

      printf("Type any input you like: \n");

      do {
         scanf("%80s", buf);
         printf("buf=%s\n", buf);
         fprintf(filew, "%s", buf);
         printf("buf=%s\n", buf);
      } while (buf[0] != 'Q');
   }
   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.


Allocating Memory

In any C program, memory can be dynamically allocated by means of the malloc() C library routine within actors, whether loaded at boot time or dynamically, and whether running as user or supervisor actors.

Example 5-2 shows a usage of the malloc() routine.

Terminating an Actor

As shown in the previous example, an actor may terminate by invoking the exit() routine, as with any typical C program. Invoking exit() ensures that all resources used by the actor are freed: I/O buffers will be flushed, all open files are closed, and all other system resources provided by features configured within the system are released automatically.