ChorusOS 5.0 Application Developer's Guide

Execution Environment of Actors and Processes

Actors have a different execution environment depending on whether they are loaded dynamically or at boot time. Processes have the same execution environment because they are always loaded dynamically.

An actor loaded at boot time has no arguments or environment. Consequently, argc is set to 0, and argv and argp are null pointers. If an actor loaded at boot time is linked with the embedded library, it can perform basic I/O operations such as printing traces on the system console using the printf() C library routine. It can also read characters entered at the keyboard through scanf() and similar C library routines. If the actor is linked with the libc.a library, it must open /dev/console three times to activate stdin, stdout, or stderr (to enable the printf() and scanf() operations).

The main thread of an actor loaded at boot time belongs to the SCHED_FIFO scheduling policy (see "Setting Scheduling Attributes") . The main thread has 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.

Start a dynamically loaded actor or processes as a regular C application with arguments and an environment:

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

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

Application Context

The context of an application depends on how the system is configured. A process 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 can also create, open, close, read and write files or sockets.

A process runs on behalf of a user who is identified by a credentials structure. The process credentials include:

The process credentials are specified in the data structure cx_cred_t, which includes the following members:

uid_t           cr_uid;       /* process's user ID */
gid_t           cr_gid;       /* process's group ID */
unsigned short  cr_ngroups;   /* number of groups in cr_groups */
gid_t           cr_groups[];  /* supplementary group list */

Note -

The ChorusOS operating system concept of credentials is simpler than the UNIX one. The ChorusOS operating system does not differentiate between real or effective user and group identification because it is not supported.


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

Standard I/O

A process can take advantage of the entire C library for dealing with I/O. In addition to the I/O interface provided by the C library, a process 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 can be run as a process and illustrates the way in which the C library can be used from a process.


Example 3-2 Using the C Library from a Process

#include <stdio.h>
#include <stdlib.h>
#include <chorus.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 -

Referencing argv[0] without checking if argc is greater than zero can cause the process to incur 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 and processes. It makes no difference whether the actors or process are loaded at boot time or dynamically, or whether they are running as user or supervisor applications.

Terminating an Application

You can terminate an application by invoking the exit() routine, as with any typical C program. Invoking exit() ensures that all resources used by the application are freed. I/O buffers are flushed, all open files are closed, and other system resources provided by features configured within the system are automatically released.