Before proceeding with a description of the different functions in the Persistent Memory Manager API, consider the following simple restartable application, an implementation of the familiar "hello world" example. When the actor is run for the first time, it displays the following message on the host console:
Hello world!
When the actor is restarted, it displays the following message on the target console:
Hello again! I have been restarted.
The basic flow of execution is as follows:
The restartable actor begins at the start of its main() program, initializing its program data.
The actor uses the pmmAllocate(2RESTART)
function to allocate a block of persistent memory. This block
is used to store a status counter, which the actor sets to zero.
The first message is displayed, and the counter is increased by one.
The actor attempts to access an invalid pointer value, causing a crash so that the actor is restarted. Note that the ChorusOS VIRTUAL_ADDRESS_SPACE optional feature should be set to true for this crash to work.
The restartable actor recommences execution at the start of its main() program, and calls pmmAllocate() a second time to retrieve the value of the status counter.
As the counter is no longer zero, the actor displays the second message.
The actor calls pmmFree() to free the persistent memory block used to store the counter, and then exits cleanly.
#include <stdio.h> #include <pmm/chPmm.h> #include <hr/hr.h> #define HR_GROUP "HELLO_GROUP" int main() { int res; int any = 1; int* counter_p; /* It will be stored in persistent memory */ long *p; PmmName name; KnRgnDesc rgn; /* * Initialize the name and medium fields * to identify the persistent memory block in the system. */ bzero(&name, sizeof(name)); strcpy(name.medium,"RAM"); strcpy(name.name,"PM1"); /* * Initialize the block fields */ bzero(&rgn, sizeof(rgn)); rgn.options = K_ANYWHERE | K_RESERVED; rgn.size = vmPageSize(); res = rgnAllocate(K_MYACTOR, &rgn); if (res != K_OK) { printf("rgnAllocate() failed res=%d\n", res); HR_EXIT_HDL(); exit(-1); } p = (long*) rgn.startAddr; /* * From now on p is a bad pointer, since * VIRTUAL_ADDRESS_SPACE is true. */ /* * Allocate the persistent memory block that stores * counter_p. */ res=pmmAllocate((VmAddr *)&counter_p, &name,sizeof(int), HR_GROUP, sizeof(HR_GROUP)); 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); } /* * From the value of *counter_p the actor detects * whether it has been hot restarted or not. */ if ( *counter_p==0 ) { /* * This is the first time the actor is run. */ printf("Hello world!\n"); /* * Increment the counter */ (*counter_p)++; /* * Normally the next instruction causes a core dump and * a hot restart of the actor */ *p = 0xDeadBeef; } else { /* * The actor has been restarted * NOTE: this message will appear on the console! */ printf("The actor has been restarted.\n"); /* * Free the persistent memory block before exiting */ res = pmmFree(&name); if (res != K_OK) { printf(" pmmFree failed, res=%d. Exit\n", res); HR_EXIT_HDL(); exit(-1); } /* * Terminate cleanly. */ printf("Example finished. Exit.\n"); HR_EXIT_HDL(); exit(0); } /* Never reached */ }
The aspects of this program which are of interest for users of the Persistent Memory Manager API are discussed in the rest of this chapter.