+
+static void
+zero_all_free_pages()
+{
+ page_index_t i;
+
+ for (i = 0; i < last_free_page; i++) {
+ if (page_free_p(i)) {
+#ifdef READ_PROTECT_FREE_PAGES
+ os_protect(page_address(i),
+ GENCGC_CARD_BYTES,
+ OS_VM_PROT_ALL);
+#endif
+ zero_pages(i, i);
+ }
+ }
+}
+
+/* Things to do before doing a final GC before saving a core (without
+ * purify).
+ *
+ * + Pages in large_object pages aren't moved by the GC, so we need to
+ * unset that flag from all pages.
+ * + The pseudo-static generation isn't normally collected, but it seems
+ * reasonable to collect it at least when saving a core. So move the
+ * pages to a normal generation.
+ */
+static void
+prepare_for_final_gc ()
+{
+ page_index_t i;
+ for (i = 0; i < last_free_page; i++) {
+ page_table[i].large_object = 0;
+ if (page_table[i].gen == PSEUDO_STATIC_GENERATION) {
+ int used = page_table[i].bytes_used;
+ page_table[i].gen = HIGHEST_NORMAL_GENERATION;
+ generations[PSEUDO_STATIC_GENERATION].bytes_allocated -= used;
+ generations[HIGHEST_NORMAL_GENERATION].bytes_allocated += used;
+ }
+ }
+}
+
+
+/* Do a non-conservative GC, and then save a core with the initial
+ * function being set to the value of the static symbol
+ * SB!VM:RESTART-LISP-FUNCTION */
+void
+gc_and_save(char *filename, boolean prepend_runtime,
+ boolean save_runtime_options,
+ boolean compressed, int compression_level)
+{
+ FILE *file;
+ void *runtime_bytes = NULL;
+ size_t runtime_size;
+
+ file = prepare_to_save(filename, prepend_runtime, &runtime_bytes,
+ &runtime_size);
+ if (file == NULL)
+ return;
+
+ conservative_stack = 0;
+
+ /* The filename might come from Lisp, and be moved by the now
+ * non-conservative GC. */
+ filename = strdup(filename);
+
+ /* Collect twice: once into relatively high memory, and then back
+ * into low memory. This compacts the retained data into the lower
+ * pages, minimizing the size of the core file.
+ */
+ prepare_for_final_gc();
+ gencgc_alloc_start_page = last_free_page;
+ collect_garbage(HIGHEST_NORMAL_GENERATION+1);
+
+ prepare_for_final_gc();
+ gencgc_alloc_start_page = -1;
+ collect_garbage(HIGHEST_NORMAL_GENERATION+1);
+
+ if (prepend_runtime)
+ save_runtime_to_filehandle(file, runtime_bytes, runtime_size);
+
+ /* The dumper doesn't know that pages need to be zeroed before use. */
+ zero_all_free_pages();
+ save_to_filehandle(file, filename, SymbolValue(RESTART_LISP_FUNCTION,0),
+ prepend_runtime, save_runtime_options,
+ compressed ? compression_level : COMPRESSION_LEVEL_NONE);
+ /* Oops. Save still managed to fail. Since we've mangled the stack
+ * beyond hope, there's not much we can do.
+ * (beyond FUNCALLing RESTART_LISP_FUNCTION, but I suspect that's
+ * going to be rather unsatisfactory too... */
+ lose("Attempt to save core after non-conservative GC failed.\n");
+}