+
+ //Setup snapshot record at top of free region
+ fork_snap = (struct fork_snapshotter *)memMapBase;
+ fork_snap->mSharedMemoryBase = (void *)((uintptr_t)memMapBase + sizeof(*fork_snap));
+ fork_snap->mStackBase = (void *)((uintptr_t)memMapBase + SHARED_MEMORY_DEFAULT);
+ fork_snap->mStackSize = STACK_SIZE_DEFAULT;
+ fork_snap->mIDToRollback = -1;
+ fork_snap->currSnapShotID = 0;
+}
+
+/**
+ * Create a new mspace pointer for the non-snapshotting (i.e., inter-process
+ * shared) memory region. Only for fork-based snapshotting.
+ *
+ * @return The shared memory mspace
+ */
+mspace create_shared_mspace()
+{
+ if (!fork_snap)
+ createSharedMemory();
+ 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)
+{
+ if (!fork_snap)
+ createSharedMemory();
+
+ model_snapshot_space = create_mspace(numheappages * PAGESIZE, 1);
+}
+
+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(&shared_ctxt);
+ } else {
+ DEBUG("parent PID: %d, child PID: %d, snapshot ID: %d\n",
+ getpid(), forkedID, snapshotid);
+
+ while (waitpid(forkedID, NULL, 0) < 0) {
+ /* waitpid() may be interrupted */
+ if (errno != EINTR) {
+ perror("waitpid");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (fork_snap->mIDToRollback != snapshotid)
+ _Exit(EXIT_SUCCESS);
+ }
+ }
+}
+
+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;
+}
+
+static void fork_roll_back(snapshot_id theID)
+{
+ DEBUG("Rollback\n");
+ fork_snap->mIDToRollback = theID;
+ model_swapcontext(model->get_system_context(), &exit_ctxt);
+ fork_snap->mIDToRollback = -1;
+}
+
+#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)
+{
+#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_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
+}
+
+/** Takes a snapshot of memory.
+ * @return The snapshot identifier.
+ */
+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.
+ * @param theID is the snapshot identifier to rollback to.
+ */
+void snapshot_roll_back(snapshot_id theID)
+{
+#if USE_MPROTECT_SNAPSHOT
+ mprot_roll_back(theID);
+#else
+ fork_roll_back(theID);