X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=snapshot.cc;h=24e8d073ca1330eb778b897955e500dab30f9c5e;hp=66faacd8e445510f57c7714ce9ccd60a1ee95f3c;hb=f8a45d8d10f16533c926096c7538b4d9be73240b;hpb=923b6a3cc2e14f3bf6fc660d760abb5686b97914 diff --git a/snapshot.cc b/snapshot.cc index 66faacd8..24e8d073 100644 --- a/snapshot.cc +++ b/snapshot.cc @@ -12,6 +12,10 @@ #include "mymemory.h" #include "common.h" #include "context.h" +#include "model.h" + + +#if USE_MPROTECT_SNAPSHOT /** PageAlignedAdressUpdate return a page aligned address for the * address being added as a side effect the numBytes are also changed. @@ -21,8 +25,6 @@ static void * PageAlignAddressUpward(void *addr) return (void *)((((uintptr_t)addr) + PAGESIZE - 1) & ~(PAGESIZE - 1)); } -#if USE_MPROTECT_SNAPSHOT - /* Each SnapShotRecord lists the firstbackingpage that must be written to * revert to that snapshot */ struct SnapShotRecord { @@ -40,8 +42,8 @@ struct BackingPageRecord { /* Struct for each memory region */ struct MemoryRegion { - void *basePtr; // base of memory region - int sizeInPages; // size of memory region in pages + void *basePtr; // base of memory region + int sizeInPages; // size of memory region in pages }; /** ReturnPageAlignedAddress returns a page aligned address for the @@ -57,19 +59,19 @@ struct mprot_snapshotter { mprot_snapshotter(unsigned int numbackingpages, unsigned int numsnapshots, unsigned int nummemoryregions); ~mprot_snapshotter(); - struct MemoryRegion *regionsToSnapShot; //This pointer references an array of memory regions to snapshot - snapshot_page_t *backingStore; //This pointer references an array of snapshotpage's that form the backing store - void *backingStoreBasePtr; //This pointer references an array of snapshotpage's that form the backing store - struct BackingPageRecord *backingRecords; //This pointer references an array of backingpagerecord's (same number of elements as backingstore - struct SnapShotRecord *snapShots; //This pointer references the snapshot array + struct MemoryRegion *regionsToSnapShot; //This pointer references an array of memory regions to snapshot + snapshot_page_t *backingStore; //This pointer references an array of snapshotpage's that form the backing store + void *backingStoreBasePtr; //This pointer references an array of snapshotpage's that form the backing store + struct BackingPageRecord *backingRecords; //This pointer references an array of backingpagerecord's (same number of elements as backingstore + struct SnapShotRecord *snapShots; //This pointer references the snapshot array - unsigned int lastSnapShot; //Stores the next snapshot record we should use - unsigned int lastBackingPage; //Stores the next backingpage we should use - unsigned int lastRegion; //Stores the next memory region to be used + unsigned int lastSnapShot; //Stores the next snapshot record we should use + unsigned int lastBackingPage; //Stores the next backingpage we should use + unsigned int lastRegion; //Stores the next memory region to be used - unsigned int maxRegions; //Stores the max number of memory regions we support - unsigned int maxBackingPages; //Stores the total number of backing pages - unsigned int maxSnapShots; //Stores the total number of snapshots we allow + unsigned int maxRegions; //Stores the max number of memory regions we support + unsigned int maxBackingPages; //Stores the total number of backing pages + unsigned int maxSnapShots; //Stores the total number of snapshots we allow MEMALLOC }; @@ -108,13 +110,13 @@ static void mprot_handle_pf(int sig, siginfo_t *si, void *unused) if (si->si_code == SEGV_MAPERR) { model_print("Segmentation fault at %p\n", si->si_addr); model_print("For debugging, place breakpoint at: %s:%d\n", - __FILE__, __LINE__); + __FILE__, __LINE__); // print_trace(); // Trace printing may cause dynamic memory allocation exit(EXIT_FAILURE); } void* addr = ReturnPageAlignedAddress(si->si_addr); - unsigned int backingpage = mprot_snap->lastBackingPage++; //Could run out of pages... + unsigned int backingpage = mprot_snap->lastBackingPage++; //Could run out of pages... if (backingpage == mprot_snap->maxBackingPages) { model_print("Out of backing pages at %p\n", si->si_addr); exit(EXIT_FAILURE); @@ -132,8 +134,8 @@ static void mprot_handle_pf(int sig, siginfo_t *si, void *unused) } static void mprot_snapshot_init(unsigned int numbackingpages, - unsigned int numsnapshots, unsigned int nummemoryregions, - unsigned int numheappages, VoidFuncPtr entryPoint) + unsigned int numsnapshots, unsigned int nummemoryregions, + unsigned int numheappages) { /* Setup a stack for our signal handler.... */ stack_t ss; @@ -167,7 +169,7 @@ static void mprot_snapshot_init(unsigned int numbackingpages, memset(&si, 0, sizeof(si)); si.si_addr = ss.ss_sp; mprot_handle_pf(SIGSEGV, &si, NULL); - mprot_snap->lastBackingPage--; //remove the fake page we copied + mprot_snap->lastBackingPage--; //remove the fake page we copied void *basemySpace = model_malloc((numheappages + 1) * PAGESIZE); void *pagealignedbase = PageAlignAddressUpward(basemySpace); @@ -178,8 +180,11 @@ static void mprot_snapshot_init(unsigned int numbackingpages, pagealignedbase = PageAlignAddressUpward(base_model_snapshot_space); model_snapshot_space = create_mspace_with_base(pagealignedbase, numheappages * PAGESIZE, 1); snapshot_add_memory_region(pagealignedbase, numheappages); +} - entryPoint(); +static void mprot_startExecution(ucontext_t * context, VoidFuncPtr entryPoint) { + /* setup the shared-stack context */ + create_context(context, fork_snap->mStackBase, model_calloc(STACK_SIZE_DEFAULT, 1), STACK_SIZE_DEFAULT, entryPoint); } static void mprot_add_to_snapshot(void *addr, unsigned int numPages) @@ -191,15 +196,15 @@ static void mprot_add_to_snapshot(void *addr, unsigned int numPages) } DEBUG("snapshot region %p-%p (%u page%s)\n", - addr, (char *)addr + numPages * PAGESIZE, numPages, - numPages > 1 ? "s" : ""); + addr, (char *)addr + numPages * PAGESIZE, numPages, + numPages > 1 ? "s" : ""); mprot_snap->regionsToSnapShot[memoryregion].basePtr = addr; mprot_snap->regionsToSnapShot[memoryregion].sizeInPages = numPages; } static snapshot_id mprot_take_snapshot() { - for (unsigned int region = 0; region < mprot_snap->lastRegion; region++) { + for (unsigned int region = 0;region < mprot_snap->lastRegion;region++) { if (mprotect(mprot_snap->regionsToSnapShot[region].basePtr, mprot_snap->regionsToSnapShot[region].sizeInPages * sizeof(snapshot_page_t), PROT_READ) == -1) { perror("mprotect"); model_print("Failed to mprotect inside of takeSnapShot\n"); @@ -220,7 +225,7 @@ static void mprot_roll_back(snapshot_id theID) { #if USE_MPROTECT_SNAPSHOT == 2 if (mprot_snap->lastSnapShot == (theID + 1)) { - for (unsigned int page = mprot_snap->snapShots[theID].firstBackingPage; page < mprot_snap->lastBackingPage; page++) { + for (unsigned int page = mprot_snap->snapShots[theID].firstBackingPage;page < mprot_snap->lastBackingPage;page++) { memcpy(mprot_snap->backingRecords[page].basePtrOfPage, &mprot_snap->backingStore[page], sizeof(snapshot_page_t)); } return; @@ -228,14 +233,14 @@ static void mprot_roll_back(snapshot_id theID) #endif HashTable< void *, bool, uintptr_t, 4, model_malloc, model_calloc, model_free> duplicateMap; - for (unsigned int region = 0; region < mprot_snap->lastRegion; region++) { + for (unsigned int region = 0;region < mprot_snap->lastRegion;region++) { if (mprotect(mprot_snap->regionsToSnapShot[region].basePtr, mprot_snap->regionsToSnapShot[region].sizeInPages * sizeof(snapshot_page_t), PROT_READ | PROT_WRITE) == -1) { perror("mprotect"); model_print("Failed to mprotect inside of takeSnapShot\n"); exit(EXIT_FAILURE); } } - for (unsigned int page = mprot_snap->snapShots[theID].firstBackingPage; page < mprot_snap->lastBackingPage; page++) { + for (unsigned int page = mprot_snap->snapShots[theID].firstBackingPage;page < mprot_snap->lastBackingPage;page++) { if (!duplicateMap.contains(mprot_snap->backingRecords[page].basePtrOfPage)) { duplicateMap.put(mprot_snap->backingRecords[page].basePtrOfPage, true); memcpy(mprot_snap->backingRecords[page].basePtrOfPage, &mprot_snap->backingStore[page], sizeof(snapshot_page_t)); @@ -243,13 +248,13 @@ static void mprot_roll_back(snapshot_id theID) } mprot_snap->lastSnapShot = theID; mprot_snap->lastBackingPage = mprot_snap->snapShots[theID].firstBackingPage; - mprot_take_snapshot(); //Make sure current snapshot is still good...All later ones are cleared + mprot_take_snapshot(); //Make sure current snapshot is still good...All later ones are cleared } -#else /* !USE_MPROTECT_SNAPSHOT */ +#else /* !USE_MPROTECT_SNAPSHOT */ -#define SHARED_MEMORY_DEFAULT (100 * ((size_t)1 << 20)) // 100mb for the shared memory -#define STACK_SIZE_DEFAULT (((size_t)1 << 20) * 20) // 20 mb out of the above 100 mb for my stack +#define SHARED_MEMORY_DEFAULT (200 * ((size_t)1 << 20)) // 100mb for the shared memory +#define STACK_SIZE_DEFAULT (((size_t)1 << 20) * 20) // 20 mb out of the above 100 mb for my stack struct fork_snapshotter { /** @brief Pointer to the shared (non-snapshot) memory heap base @@ -273,35 +278,29 @@ struct fork_snapshotter { */ volatile snapshot_id mIDToRollback; - /** - * @brief The context for the shared (non-snapshot) stack - * - * This context is passed between the various processes which represent - * various snapshot states. It should be used primarily for the - * "client-side" code, not the main snapshot loop. - */ - ucontext_t shared_ctxt; + /** @brief Inter-process tracking of the next snapshot ID */ snapshot_id currSnapShotID; }; static struct fork_snapshotter *fork_snap = NULL; +ucontext_t shared_ctxt; /** @statics -* These variables are necessary because the stack is shared region and -* there exists a race between all processes executing the same function. -* To avoid the problem above, we require variables allocated in 'safe' regions. -* The bug was actually observed with the forkID, these variables below are -* used to indicate the various contexts to which to switch to. -* -* @private_ctxt: the context which is internal to the current process. Used -* for running the internal snapshot/rollback loop. -* @exit_ctxt: a special context used just for exiting from a process (so we -* can use swapcontext() instead of setcontext() + hacks) -* @snapshotid: it is a running counter for the various forked processes -* snapshotid. it is incremented and set in a persistently shared record -*/ + * These variables are necessary because the stack is shared region and + * there exists a race between all processes executing the same function. + * To avoid the problem above, we require variables allocated in 'safe' regions. + * The bug was actually observed with the forkID, these variables below are + * used to indicate the various contexts to which to switch to. + * + * @private_ctxt: the context which is internal to the current process. Used + * for running the internal snapshot/rollback loop. + * @exit_ctxt: a special context used just for exiting from a process (so we + * can use swapcontext() instead of setcontext() + hacks) + * @snapshotid: it is a running counter for the various forked processes + * snapshotid. it is incremented and set in a persistently shared record + */ static ucontext_t private_ctxt; static ucontext_t exit_ctxt; static snapshot_id snapshotid = 0; @@ -314,11 +313,12 @@ static snapshot_id snapshotid = 0; * @param func The entry point function for the context */ static void create_context(ucontext_t *ctxt, void *stack, size_t stacksize, - void (*func)(void)) + void (*func)(void)) { getcontext(ctxt); ctxt->uc_stack.ss_sp = stack; ctxt->uc_stack.ss_size = stacksize; + ctxt->uc_link = NULL; makecontext(ctxt, func, 0); } @@ -326,7 +326,7 @@ static void create_context(ucontext_t *ctxt, void *stack, size_t stacksize, * process */ static void fork_exit() { - /* Intentionally empty */ + _Exit(EXIT_SUCCESS); } static void createSharedMemory() @@ -361,39 +361,38 @@ mspace create_shared_mspace() } static void fork_snapshot_init(unsigned int numbackingpages, - unsigned int numsnapshots, unsigned int nummemoryregions, - unsigned int numheappages, VoidFuncPtr entryPoint) + unsigned int numsnapshots, unsigned int nummemoryregions, + unsigned int numheappages) { if (!fork_snap) createSharedMemory(); - void *base_model_snapshot_space = malloc((numheappages + 1) * PAGESIZE); - void *pagealignedbase = PageAlignAddressUpward(base_model_snapshot_space); - model_snapshot_space = create_mspace_with_base(pagealignedbase, numheappages * PAGESIZE, 1); + model_snapshot_space = create_mspace(numheappages * PAGESIZE, 1); +} - /* setup an "exiting" context */ - char stack[128]; - create_context(&exit_ctxt, stack, sizeof(stack), fork_exit); - - /* setup the shared-stack context */ - create_context(&fork_snap->shared_ctxt, fork_snap->mStackBase, - STACK_SIZE_DEFAULT, entryPoint); - /* switch to a new entryPoint context, on a new stack */ - model_swapcontext(&private_ctxt, &fork_snap->shared_ctxt); +volatile int modellock = 0; +static void fork_loop() { /* switch back here when takesnapshot is called */ snapshotid = fork_snap->currSnapShotID; + if (model->params.nofork) { + setcontext(&shared_ctxt); + _Exit(EXIT_SUCCESS); + } while (true) { pid_t forkedID; fork_snap->currSnapShotID = snapshotid + 1; + + modellock = 1; forkedID = fork(); + modellock = 0; if (0 == forkedID) { - setcontext(&fork_snap->shared_ctxt); + setcontext(&shared_ctxt); } else { DEBUG("parent PID: %d, child PID: %d, snapshot ID: %d\n", - getpid(), forkedID, snapshotid); + getpid(), forkedID, snapshotid); while (waitpid(forkedID, NULL, 0) < 0) { /* waitpid() may be interrupted */ @@ -404,14 +403,24 @@ static void fork_snapshot_init(unsigned int numbackingpages, } if (fork_snap->mIDToRollback != snapshotid) - exit(EXIT_SUCCESS); + _Exit(EXIT_SUCCESS); } } } -static snapshot_id fork_take_snapshot() -{ - model_swapcontext(&fork_snap->shared_ctxt, &private_ctxt); +static void fork_startExecution(ucontext_t *context, VoidFuncPtr entryPoint) { + /* setup an "exiting" context */ + int exit_stack_size = 256; + create_context(&exit_ctxt, snapshot_calloc(exit_stack_size, 1), exit_stack_size, fork_exit); + + /* setup the system context */ + create_context(context, fork_snap->mStackBase, STACK_SIZE_DEFAULT, entryPoint); + /* switch to a new entryPoint context, on a new stack */ + create_context(&private_ctxt, snapshot_calloc(STACK_SIZE_DEFAULT, 1), STACK_SIZE_DEFAULT, fork_loop); +} + +static snapshot_id fork_take_snapshot() { + model_swapcontext(&shared_ctxt, &private_ctxt); DEBUG("TAKESNAPSHOT RETURN\n"); return snapshotid; } @@ -420,24 +429,33 @@ static void fork_roll_back(snapshot_id theID) { DEBUG("Rollback\n"); fork_snap->mIDToRollback = theID; - model_swapcontext(&fork_snap->shared_ctxt, &exit_ctxt); + model_swapcontext(model->get_system_context(), &exit_ctxt); fork_snap->mIDToRollback = -1; } -#endif /* !USE_MPROTECT_SNAPSHOT */ +#endif /* !USE_MPROTECT_SNAPSHOT */ /** * @brief Initializes the snapshot system * @param entryPoint the function that should run the program. */ void snapshot_system_init(unsigned int numbackingpages, - unsigned int numsnapshots, unsigned int nummemoryregions, - unsigned int numheappages, VoidFuncPtr entryPoint) + unsigned int numsnapshots, unsigned int nummemoryregions, + unsigned int numheappages) +{ +#if USE_MPROTECT_SNAPSHOT + mprot_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages); +#else + fork_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages); +#endif +} + +void startExecution(ucontext_t *context, VoidFuncPtr entryPoint) { #if USE_MPROTECT_SNAPSHOT - mprot_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages, entryPoint); + mprot_startExecution(context, entryPoint); #else - fork_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages, entryPoint); + fork_startExecution(context, entryPoint); #endif }