ChorusOS 4.0 Hot Restart Programmer's Guide

B.3 The restartSpawn Example

The restartSpawn example comprises two actors: HR_parent.r and HR_child.r. Both actors must be compiled as supervisor actors. See "4.5 Putting It All Together: the restartSpawn Example Program" for an overview of the restartSpawn example.

B.3.1 HR_parent.c

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <am/afexec.h>
#include <pmm/chPmm.h>
#include <exec/chModules.h>
#include <hr/hr.h>
#include <err.h>
#include <errno.h>

#define PM_MEDIUM "RAM"
#define PM_NAME "PARENT_PM"
#define MAX_LOOPS 8

/*
 * Some static variables
 */
char baseName[PATH_MAX];
char last_global_data;

/*
 * Declaration of objects that will be stored in persistent memory.
 * restarted: number of times the actor has been restarted.
 * counter: number of times the actor's main loop is run.
 */
typedef struct _HR_Status {
    int restarted;
    int counter;
} HR_Status;

    /*
     * Wait "sec" seconds.
     */
    void
waitSec(int sec)
{
    KnTimeVal delay;
    delay.tmSec = sec;
    delay.tmNSec = 0;
	
    threadDelay(&delay);
}

    /*
     * Create a child hot restartable actor.
     * Start the child actor only if the parent has
     * not been hot restarted.
     */
    void
childCreate()
{
    KnCap childCap;
    KnActorPrivilege curActPriv;
    PmmName childName;
    int res;
    int childAid = -1;
    char path[PATH_MAX];
    char* argv[3];
	
    res = actorPrivilege(K_MYACTOR, &curActPriv, NULL);
    if (res != K_OK) {
        printf("actorPrivilege failed, res=%d\n", res);
	HR_EXIT_HDL();
	exit(-1);
    }
    
    if (curActPriv != K_SUPACTOR) {
    	argv[0] = "HR_child";
    } else {
        argv[0] = "HR_child_u";
    }
	
    argv[1] = NULL;
    argv[2] = NULL;
    
    strcpy(childName.medium, "RAM");
    strcpy(childName.name, "CHILD");
	
    strcpy(path, baseName);
    if (curActPriv == K_SUPACTOR) {
        strcat(path, "HR_child");
    } else {
        strcat(path, "HR_child_u");
    }
	
    childAid = hrfexecv(&childName, path, &childCap, NULL, argv);
	
    if (childAid == -1) {
        printf("Cannot hrfexecv(%s), error=%d\n", path, errno);
        HR_EXIT_HDL();
        exit(-1);
    } 
}

    /*
     * Cause a hot restart by exiting without
     * first calling HR_EXIT_HDL().
     */
    void
crash_exit()
{
    printf("\nPARENT hot-restarts (exits with no HR_EXIT_HDL)!\n");
    exit(1);
}

    /*
     * Cause a segmentation fault.
     */
    void
crash_seg()
{
    KnRgnDesc      rgn;
    unsigned long* badSupPtr;
    int            res;
	
    rgn.options = K_ANYWHERE | K_RESERVED;
    rgn.size    = vmPageSize();
    rgn.opaque1 = NULL;
    rgn.opaque2 = 0;
    res = rgnAllocate(K_MYACTOR, &rgn);
    if (res != K_OK) {
        printf("unable to allocate a page res=%d\n", res);
        return;
    }
    
    badSupPtr = (unsigned long*) rgn.startAddr;

    printf("\nPARENT crashes (segmentation fault)!\n");

        /* 
         * Generate an unrecoverable page fault, since 
         * VIRTUAL_ADDRESS_SPACE is true
         */
    *badSupPtr = (unsigned long) 0xffffffff;
	
        /*
         * it should never return with 
         */
    printf("Can't generate a crash\n");
    return;
}

    /*
     * Cause a failure due to division by 0.
     * Note: This does not crash on some platforms.
     */
    int
crash_div()
{
    int i;
    int z;
    int x = 1;
	
    printf("\nPARENT tries to crash with division by 0!\n");
    for (i = 10; i > -1; i--) {
        z = x/i;
    }
    return z;
}

    /*
     * Perform a site restart.
     */
    void
site_restart()
{
    char*       argv[3];
    int         res;
	
    argv[0] = "shutdown";
    argv[1] = "-i";
    argv[2] = "1";
	
    res = sysShutdown (3, argv);
	
    if (res) {
        printf("parent error=%d\n", res);

    } else {
		
        waitSec(5);
        printf("Timeout ! \n");
    }
}

    /*
     * Kill the group actors and free persistent memory
     * blocks allocated by the parent actor.
     */
    void
clean_up(PmmName *np)
{
    int res;
    int group = 1;
    int actId;
	
    actId = agetId();
	
    res=pmmFree(np);
    if (res != K_OK) {
        printf("\nCannot free the persistent memory block called %s."
               " Error = %d\n", np->name, res);
        HR_EXIT_HDL();
        exit(-1);
    }
    printf("\nPersistent memory has been freed.\n");

    group=hrGetActorGroup(actId);
    if (group < 0) {
        printf("Cannot get actor group. Error = %s\n", errno);
        HR_EXIT_HDL();
        exit(-1);
    }

    printf("Example finished. Exit.\n");

    res=hrKillGroup(group);
    if (res != K_OK) {
        printf("Cannot kill actor group %d. Error = %d\n", group, res);
        HR_EXIT_HDL();
        exit(-1);
    }
}

    /*
     * main
     */
    int 
main(int argc, char** argv, char**envp)
{
	
    int res;
    int counter;
    int ref;
    int* mem_version;
    static PmmName name; 
    HR_Status* st;
    char* endPath;
    KnActorPrivilege curActPriv;
	
        /* 
         * Check that argc != 0. Otherwise exit.
         */
    if(argc==0) {
        printf("Cannot start this test. argc == %d. Exit.\n", argc);
        HR_EXIT_HDL();
        exit(-1);
    }

    res = actorPrivilege(K_MYACTOR, &curActPriv, NULL);
    if (res != K_OK) {
        printf("actorPrivilege failed, res=%d\n", res);
        HR_EXIT_HDL();
        exit(-1);
    }

    if (curActPriv != K_SUPACTOR) {
        printf("This example can only be run in supervisor mode. Exit.\n");
        HR_EXIT_HDL();
        exit(-1);
    }

        /*
         * If the example runs in flat memory mode, it will not work.
         * Some of the failures will not always cause a hot-restart.
         * Print an error message and exit.
         */
    res = sysGetConf(K_MODULE_MEM_NAME, K_GETCONF_VERSION, mem_version);
    if (res != K_OK) {
        printf("Cannot get memory configuration."
               " res=%d\n", res);
        HR_EXIT_HDL();
        exit(-1);
    }
	
    if (*mem_version==K_MEM_VERSION_FLM) {
        printf("Sorry. The example cannot be run in flat memory"
               " configuration. Exit.\n");
        HR_EXIT_HDL();
        exit(-1);
    }
	
        /*
         * Get the directory of the current actor.
         */
    strcpy(baseName, argv[0]);
    endPath = strrchr(baseName, '/');
    *(endPath+1) = '\0';
	
        /* 
         * Initialize the name and medium fields to identify 
         * the HR_Status structure.
         */
    bzero(&name, sizeof(name));
    strcpy(name.medium,PM_MEDIUM);
    strcpy(name.name,PM_NAME);
	
        /*
         * Allocate or map the data in st in persistent memory.
         */
    res=pmmAllocate((VmAddr *)&st,
                    &name,
                    sizeof(HR_Status),
                    HR_GROUP_KEY,
                    HR_GROUP_KEYSIZE);
	
    if (res != K_OK) {
        printf("Cannot allocate or map the persistent memory block called %s."
               " Error = %d, errno=%d\n", name.name, res, errno);
        HR_EXIT_HDL();
        exit(-1);
    }
	
        /*
         * If the actor has been restarted, print out a message.
         */
    if (st->restarted>0) {
        printf("PARENT RESTARTS (%d-th time)\n", st->restarted);
    }
	
        /*
         * Increase the "restarted" counter.
         */
    st->restarted++;
	
	
        /*
         * Create a child hot-restartable actor.
         */
    childCreate();
	
        /* 
         * main loop
         * provokes different faults in the parent actor.
         * This causes the parent AND the child to hot restart.
         */
    while ( st->counter<MAX_LOOPS ) {
        waitSec(2 + rand() % 2);
        st->counter++;
        ref = (st->counter%5);
        switch ( ref ) {
            case 1:
                crash_seg();
                break;
            case 2:
                res = crash_div();
                    /* 
                     * If you get here, it means that division by 0 does not
                     * crash your system! 
                     */
                printf("The parent actor does not crash"
                       " with division by 0. Continue.\n");
                break;
            case 3:
                crash_exit();
                break;
            case 4:
                site_restart();
                break;
            default:
                break;
        }
    }
	
        /*
         * Example complete. Free persistent memory blocks and exit.
         */
    clean_up(&name);

}

B.3.2 HR_child.c

#include <stdio.h>
#include <strings.h>
#include <pmm/chPmm.h>
#include <hr/hr.h>
#include <exec/chExec.h>
#include <pd/chPd.h>
#include <errno.h>

#define PM_MEDIUM "RAM"
#define PM_NAME "CHILD_PM"
#define MESSAGE_NAME "CHILD_MESSAGE"
#define MESSAGE_SIZE 100

typedef struct _HR_Status {
    int restarted;
    int checkpoint;
} HR_Status;

/* 
 * Static variables
 */
static HR_Status *st;

    /*
     * Wait "sec" seconds.
     */
    void 
waitSec(int sec)
{
    KnTimeVal delay;
    delay.tmSec = sec;
    delay.tmNSec = 0;
	
    (void) threadDelay(&delay);
}

    /*
     * General operations in all steps.
     */
    void 
gen_step (char** message, char* m_out) 
{
    strcat(*message, m_out);
    printf("%s", m_out);
    fflush(NULL);
	
        /* 
         * st is stored in persistent memory. 
         * If the actor does not reach the end of the next instruction
         * before a hot restart, the current step will be repeated.
         */
    st->checkpoint=++(st->checkpoint) % 4;
}

    /*
     * step1
     */
    void 
step1 (char** message) 
{
    gen_step(message, " STEP 1 ");  
}

    /*
     * step2
     */
    void 
step2 (char** message) 
{
    gen_step(message, " STEP 2 ");
}

    /*
     * step3
     */
    void 
step3 (char** message) 
{
    gen_step(message, " STEP 3 ");
}

    /*
     * step4
     */
    void 
step4 (char** message) 
{	
    gen_step(message, " STEP 4 ");
	
        /*
         * Print out the entire message at the end of the cycle.
         * The entire message is printed even if the child actor is
	 * restarted during a cycle.
	 * 
         * =========== Message ===========
         *  STEP 1  STEP 2  STEP 3  STEP 4 
         * ======== End of message========
         *
         * Note that output from the parent actor may garble 
	 * this output.
         */
    printf("\n\n=========== Message ===========\n");
    printf("%s", *message);
    printf("\n======== End of message========\n\n");
	
        /*
         * Reset the message.
         */
    bzero(*message, MESSAGE_SIZE);
}

    /*
     * Function to be executed before the actor exits for any reason.
     */
    void 
before_exit() 
{
    printf("CHILD EXITS!\n");
}

    /*
     * main
     */
    int 
main(int argc, char** argv, char**envp)
{
	
    int	res;
    int	counter;
    static PmmName name;
    static PmmName m_name; 
    size_t size;
    PdKey key;  
    char message[MESSAGE_SIZE];
    KnActorPrivilege curActPriv;
	
    res = actorPrivilege(K_MYACTOR, &curActPriv, NULL);
    if (res != K_OK) {
        printf("actorPrivilege failed, res=%d\n", res);
        HR_EXIT_HDL();
        exit(-1);
    }
    if (curActPriv == K_SUPACTOR) {
            /*
             * Create a private actor data key with a destructor associated 
	     * with it.
             */
        res = padKeyCreate(&key, (KnPdHdl)before_exit);
        if(res != 0) {
            printf("Couldn't create PD key. Exit with errno %d\n", errno);
            HR_EXIT_HDL();

            exit(-1);
        }
		
        res = padSet(K_MYACTOR, key, "M");
        if (res != K_OK) {
            printf("Cannot set the PD key, error %d\n", res);
            HR_EXIT_HDL();
            exit(-1);
        }
    } else {
        res=atexit(&before_exit);

            /*
             * atexit() accepts up to 32 functions so this cannot fail.
             */
    }
	
        /* 
         * Initialize the name and medium fields for the HR_Status structure.
         */
    bzero(&name, sizeof(name));
    strcpy(name.medium,PM_MEDIUM);
    strcpy(name.name,PM_NAME);
	
        /*
         * Allocate or map the data in st in persistent memory.
         */
    res=pmmAllocate((VmAddr *)&st,
                    &name,
                    sizeof(HR_Status),
                    HR_GROUP_KEY,
                    HR_GROUP_KEYSIZE);
	
	
    if (res != K_OK) {
        printf("Cannot allocate or map the persistent memory block called %s."
               " Error = %d\n", name.name, res);
        HR_EXIT_HDL();
        exit(-1);
    }
	
        /* 
         * Initialize the name and medium fields for the message char buffer.
         */
    bzero(&m_name, sizeof(m_name));
    strcpy(m_name.medium,PM_MEDIUM);
    strcpy(m_name.name,MESSAGE_NAME);
	
        /*
         * Allocate or map the message data in persistent memory.
         */
    res=pmmAllocate((VmAddr *)&message, 
                    &m_name, 
                    MESSAGE_SIZE, 
                    HR_GROUP_KEY,
                    HR_GROUP_KEYSIZE);
	
    if (res != K_OK) {
        printf("Cannot allocate or map the persistent memory block called %s."
               " Error = %d\n", name.name, res);
        HR_EXIT_HDL();
        exit(-1);
    }
	
        /*
         * If the actor has been restarted, print out a message.
         */
    if (st->restarted>0) {
        printf("CHILD RESTARTS (%d-th time)\n", st->restarted);
    }
	
        /*
         * Increase the "restarted" counter.
         */
    st->restarted++;
	
        /*
         * Loop forever.
         * Each time the parent actor crashes, the child actor will be
         * stopped with it since they belong 
         * to the same group.
         */
    while ( 1 ) {
        waitSec(1);
        switch ( st->checkpoint ) {
            case 0:
                step1(&message);
                break;
            case 1:
                step2(&message);
                break;
            case 2:
                step3(&message);
                break;
            case 3:
                step4(&message);
                break;
            default:
                break;
        }
    }
    return 0;
	
}

B.3.3 Imakefile for HR_parent.c and HR_child.c

SRCS = HR_child.c HR_parent.c

SupActorTarget(HR_child.r,HR_child.o,$(NUCLEUS_DIR)/lib/pmm/pmmlib.a)
SupActorTarget(HR_parent.r,HR_parent.o,$(NUCLEUS_DIR)/lib/pmm/pmmlib.a)

Depend($(SRCS))