The restartSpawn example comprises two processes: HR_parent.r and HR_child.r. Both processes must be compiled as supervisor processes (see "Putting It All Together: the restartSpawn Example Program" for an overview of the restartSpawn example).
#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 process has been restarted. * counter: number of times the process'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; (void) threadDelay(&delay); } /* * Create a child hot restartable process. * Start the child process only if the parent has * not been hot restarted. */ void childCreate() { KnCap childCap; KnprocessPrivilege curActPriv; PmmName childName; int res; int childPid = -1; char path[PATH_MAX]; char* argv[3]; res = processPrivilege(K_MYprocess, &curActPriv, NULL); if (res != K_OK) { printf("processPrivilege failed, res=%d\n", res); HR_EXIT_HDL(); exit(-1); } if (curActPriv != K_SUPprocess) { 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_SUPprocess) { strcat(path, "HR_child"); } else { strcat(path, "HR_child_u"); } childPid = hrfexecv(&childName, path, &childCap, NULL, argv); if (childPid == -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_MYprocess, &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 processes and free persistent memory * blocks allocated by the parent process. */ 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=hrGetprocessGroup(actId); if (group < 0) { printf("Cannot get process 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 process 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; KnprocessPrivilege 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 = processPrivilege(K_MYprocess, &curActPriv, NULL); if (res != K_OK) { printf("processPrivilege failed, res=%d\n", res); HR_EXIT_HDL(); exit(-1); } if (curActPriv != K_SUPprocess) { 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 process. */ 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 process 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 process. */ childCreate(); /* * main loop * provokes different faults in the parent process. * 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 process 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); }
#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 process 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 process * is restarted during a cycle. * * =========== Message =========== * STEP 1 STEP 2 STEP 3 STEP 4 * ======== End of message======== * * Note that output from the parent process 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 process 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]; KnprocessPrivilege curActPriv; res = processPrivilege(K_MYprocess, &curActPriv, NULL); if (res != K_OK) { printf("processPrivilege failed, res=%d\n", res); HR_EXIT_HDL(); exit(-1); } if (curActPriv == K_SUPprocess) { /* * Create a private process 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_MYprocess, 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 process 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 process crashes, the child process 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; }
SRCS = HR_child.c HR_parent.c SupprocessTarget(HR_child.r,HR_child.o,$(NUCLEUS_DIR)/lib/pmm/pmmlib.a) SupprocessTarget(HR_parent.r,HR_parent.o,$(NUCLEUS_DIR)/lib/pmm/pmmlib.a) Depend($(SRCS))