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 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);
}