X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=snapshot.cc;h=1f0cf352d2e214c0e5218818addb29fab2a37330;hp=a69915ebe41c6e8c7bff79f8362531735c1f2905;hb=bdb967ee6d3cdd02dda0e80f8b394f86e9753623;hpb=651e9182baf50ef1e235ad7a587730b989bb44c7 diff --git a/snapshot.cc b/snapshot.cc index a69915eb..1f0cf352 100644 --- a/snapshot.cc +++ b/snapshot.cc @@ -14,243 +14,6 @@ #include "context.h" #include "model.h" -/** PageAlignedAdressUpdate return a page aligned address for the - * address being added as a side effect the numBytes are also changed. - */ -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 { - unsigned int firstBackingPage; -}; - -/** @brief Backing store page */ -typedef unsigned char snapshot_page_t[PAGESIZE]; - -/* List the base address of the corresponding page in the backing store so we - * know where to copy it to */ -struct BackingPageRecord { - void *basePtrOfPage; -}; - -/* Struct for each memory region */ -struct MemoryRegion { - void *basePtr; // base of memory region - int sizeInPages; // size of memory region in pages -}; - -/** ReturnPageAlignedAddress returns a page aligned address for the - * address being added as a side effect the numBytes are also changed. - */ -static void * ReturnPageAlignedAddress(void *addr) -{ - return (void *)(((uintptr_t)addr) & ~(PAGESIZE - 1)); -} - -/* Primary struct for snapshotting system */ -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 - - 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 - - MEMALLOC -}; - -static struct mprot_snapshotter *mprot_snap = NULL; - -mprot_snapshotter::mprot_snapshotter(unsigned int backing_pages, unsigned int snapshots, unsigned int regions) : - lastSnapShot(0), - lastBackingPage(0), - lastRegion(0), - maxRegions(regions), - maxBackingPages(backing_pages), - maxSnapShots(snapshots) -{ - regionsToSnapShot = (struct MemoryRegion *)model_malloc(sizeof(struct MemoryRegion) * regions); - backingStoreBasePtr = (void *)model_malloc(sizeof(snapshot_page_t) * (backing_pages + 1)); - //Page align the backingstorepages - backingStore = (snapshot_page_t *)PageAlignAddressUpward(backingStoreBasePtr); - backingRecords = (struct BackingPageRecord *)model_malloc(sizeof(struct BackingPageRecord) * backing_pages); - snapShots = (struct SnapShotRecord *)model_malloc(sizeof(struct SnapShotRecord) * snapshots); -} - -mprot_snapshotter::~mprot_snapshotter() -{ - model_free(regionsToSnapShot); - model_free(backingStoreBasePtr); - model_free(backingRecords); - model_free(snapShots); -} - -/** mprot_handle_pf is the page fault handler for mprotect based snapshotting - * algorithm. - */ -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__); - // 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... - if (backingpage == mprot_snap->maxBackingPages) { - model_print("Out of backing pages at %p\n", si->si_addr); - exit(EXIT_FAILURE); - } - - //copy page - memcpy(&(mprot_snap->backingStore[backingpage]), addr, sizeof(snapshot_page_t)); - //remember where to copy page back to - mprot_snap->backingRecords[backingpage].basePtrOfPage = addr; - //set protection to read/write - if (mprotect(addr, sizeof(snapshot_page_t), PROT_READ | PROT_WRITE)) { - perror("mprotect"); - // Handle error by quitting? - } -} - -static void mprot_snapshot_init(unsigned int numbackingpages, - unsigned int numsnapshots, unsigned int nummemoryregions, - unsigned int numheappages) -{ - /* Setup a stack for our signal handler.... */ - stack_t ss; - ss.ss_sp = PageAlignAddressUpward(model_malloc(SIGSTACKSIZE + PAGESIZE - 1)); - ss.ss_size = SIGSTACKSIZE; - ss.ss_flags = 0; - sigaltstack(&ss, NULL); - - struct sigaction sa; - sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_RESTART | SA_ONSTACK; - sigemptyset(&sa.sa_mask); - sa.sa_sigaction = mprot_handle_pf; -#ifdef MAC - if (sigaction(SIGBUS, &sa, NULL) == -1) { - perror("sigaction(SIGBUS)"); - exit(EXIT_FAILURE); - } -#endif - if (sigaction(SIGSEGV, &sa, NULL) == -1) { - perror("sigaction(SIGSEGV)"); - exit(EXIT_FAILURE); - } - - mprot_snap = new mprot_snapshotter(numbackingpages, numsnapshots, nummemoryregions); - - // EVIL HACK: We need to make sure that calls into the mprot_handle_pf method don't cause dynamic links - // The problem is that we end up protecting state in the dynamic linker... - // Solution is to call our signal handler before we start protecting stuff... - - siginfo_t si; - 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 - - void *basemySpace = model_malloc((numheappages + 1) * PAGESIZE); - void *pagealignedbase = PageAlignAddressUpward(basemySpace); - user_snapshot_space = create_mspace_with_base(pagealignedbase, numheappages * PAGESIZE, 1); - snapshot_add_memory_region(pagealignedbase, numheappages); - - void *base_model_snapshot_space = model_malloc((numheappages + 1) * PAGESIZE); - pagealignedbase = PageAlignAddressUpward(base_model_snapshot_space); - model_snapshot_space = create_mspace_with_base(pagealignedbase, numheappages * PAGESIZE, 1); - snapshot_add_memory_region(pagealignedbase, numheappages); -} - -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) -{ - unsigned int memoryregion = mprot_snap->lastRegion++; - if (memoryregion == mprot_snap->maxRegions) { - model_print("Exceeded supported number of memory regions!\n"); - exit(EXIT_FAILURE); - } - - DEBUG("snapshot region %p-%p (%u page%s)\n", - 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++) { - 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"); - exit(EXIT_FAILURE); - } - } - unsigned int snapshot = mprot_snap->lastSnapShot++; - if (snapshot == mprot_snap->maxSnapShots) { - model_print("Out of snapshots\n"); - exit(EXIT_FAILURE); - } - mprot_snap->snapShots[snapshot].firstBackingPage = mprot_snap->lastBackingPage; - - return snapshot; -} - -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++) { - memcpy(mprot_snap->backingRecords[page].basePtrOfPage, &mprot_snap->backingStore[page], sizeof(snapshot_page_t)); - } - return; - } -#endif - - HashTable< void *, bool, uintptr_t, 4, model_malloc, model_calloc, model_free> duplicateMap; - 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++) { - 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)); - } - } - 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 -} - -#else /* !USE_MPROTECT_SNAPSHOT */ #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 @@ -277,20 +40,14 @@ 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 @@ -307,7 +64,6 @@ static struct fork_snapshotter *fork_snap = NULL; * 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; /** @@ -350,6 +106,7 @@ static void createSharedMemory() fork_snap->mStackSize = STACK_SIZE_DEFAULT; fork_snap->mIDToRollback = -1; fork_snap->currSnapShotID = 0; + sStaticSpace = create_shared_mspace(); } /** @@ -365,9 +122,7 @@ mspace create_shared_mspace() return create_mspace_with_base((void *)(fork_snap->mSharedMemoryBase), SHARED_MEMORY_DEFAULT - sizeof(*fork_snap), 1); } -static void fork_snapshot_init(unsigned int numbackingpages, - unsigned int numsnapshots, unsigned int nummemoryregions, - unsigned int numheappages) +static void fork_snapshot_init(unsigned int numheappages) { if (!fork_snap) createSharedMemory(); @@ -381,7 +136,7 @@ static void fork_loop() { /* switch back here when takesnapshot is called */ snapshotid = fork_snap->currSnapShotID; if (model->params.nofork) { - setcontext(&fork_snap->shared_ctxt); + setcontext(&shared_ctxt); _Exit(EXIT_SUCCESS); } @@ -394,7 +149,7 @@ static void fork_loop() { 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); @@ -413,20 +168,15 @@ static void fork_loop() { } } -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); +static void fork_startExecution() { /* 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(&fork_snap->shared_ctxt, &private_ctxt); + model_swapcontext(&shared_ctxt, &private_ctxt); DEBUG("TAKESNAPSHOT RETURN\n"); + fork_snap->mIDToRollback = -1; return snapshotid; } @@ -434,44 +184,20 @@ static void fork_roll_back(snapshot_id theID) { DEBUG("Rollback\n"); fork_snap->mIDToRollback = theID; - model_swapcontext(&fork_snap->shared_ctxt, &exit_ctxt); - fork_snap->mIDToRollback = -1; + fork_exit(); } -#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) +void snapshot_system_init(unsigned int numheappages) { -#if USE_MPROTECT_SNAPSHOT - mprot_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages); -#else - fork_snapshot_init(numbackingpages, numsnapshots, nummemoryregions, numheappages); -#endif + fork_snapshot_init(numheappages); } -void startExecution(ucontext_t *context, VoidFuncPtr entryPoint) -{ -#if USE_MPROTECT_SNAPSHOT - mprot_startExecution(context, entryPoint); -#else - fork_startExecution(context, entryPoint); -#endif -} - -/** Assumes that addr is page aligned. */ -void snapshot_add_memory_region(void *addr, unsigned int numPages) -{ -#if USE_MPROTECT_SNAPSHOT - mprot_add_to_snapshot(addr, numPages); -#else - /* not needed for fork-based snapshotting */ -#endif +void startExecution() { + fork_startExecution(); } /** Takes a snapshot of memory. @@ -479,11 +205,7 @@ void snapshot_add_memory_region(void *addr, unsigned int numPages) */ snapshot_id take_snapshot() { -#if USE_MPROTECT_SNAPSHOT - return mprot_take_snapshot(); -#else return fork_take_snapshot(); -#endif } /** Rolls the memory state back to the given snapshot identifier. @@ -491,9 +213,5 @@ snapshot_id take_snapshot() */ void snapshot_roll_back(snapshot_id theID) { -#if USE_MPROTECT_SNAPSHOT - mprot_roll_back(theID); -#else fork_roll_back(theID); -#endif }