diff src/gc.c @ 3263:d674024a8674

[xemacs-hg @ 2006-02-27 16:29:00 by crestani] - Introduce a fancy asynchronous finalization strategy on C level. - Merge the code conditioned on MC_ALLOC into the code conditioned on NEW_GC. - Remove the possibility to free objects manually outside garbage collections when the new collector is enabled.
author crestani
date Mon, 27 Feb 2006 16:29:29 +0000
parents 141c2920ea48
children a0de8be91f1b
line wrap: on
line diff
--- a/src/gc.c	Sun Feb 26 22:51:04 2006 +0000
+++ b/src/gc.c	Mon Feb 27 16:29:29 2006 +0000
@@ -632,15 +632,15 @@
 }
 #endif /* defined (USE_KKCC) || defined (PDUMP) */
 
-#ifdef MC_ALLOC
+#ifdef NEW_GC
 #define GC_CHECK_NOT_FREE(lheader)			\
       gc_checking_assert (! LRECORD_FREE_P (lheader));
-#else /* MC_ALLOC */
+#else /* not NEW_GC */
 #define GC_CHECK_NOT_FREE(lheader)					\
       gc_checking_assert (! LRECORD_FREE_P (lheader));			\
       gc_checking_assert (LHEADER_IMPLEMENTATION (lheader)->basic_p ||	\
 			  ! ((struct old_lcrecord_header *) lheader)->free)
-#endif /* MC_ALLOC */
+#endif /* not NEW_GC */
 
 #ifdef USE_KKCC
 /* The following functions implement the new mark algorithm. 
@@ -1147,13 +1147,13 @@
 		   though. */
 		if (EQ (*stored_obj, Qnull_pointer))
 		  break;
-#ifdef MC_ALLOC
+#ifdef NEW_GC
 		mark_object_maybe_checking_free (*stored_obj, 0, level, pos);
-#else /* not MC_ALLOC */
+#else /* not NEW_GC */
 		mark_object_maybe_checking_free
 		  (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT,
 		   level, pos);
-#endif /* not MC_ALLOC */
+#endif /* not NEW_GC */
 		break;
 	      }
 	    case XD_LISP_OBJECT_ARRAY:
@@ -1169,14 +1169,14 @@
 
 		    if (EQ (*stored_obj, Qnull_pointer))
 		      break;
-#ifdef MC_ALLOC
+#ifdef NEW_GC
 		    mark_object_maybe_checking_free 
 		      (*stored_obj, 0, level, pos);
-#else /* not MC_ALLOC */
+#else /* not NEW_GC */
 		    mark_object_maybe_checking_free
 		      (*stored_obj, (desc1->flags) & XD_FLAG_FREE_LISP_OBJECT,
 		       level, pos);
-#endif /* not MC_ALLOC */
+#endif /* not NEW_GC */
 		  }
 		break;
 	      }
@@ -1392,6 +1392,76 @@
     }
 }
 
+#ifdef NEW_GC
+/* Asynchronous finalization. */
+typedef struct finalize_elem
+{
+  Lisp_Object obj;
+  struct finalize_elem *next;
+} finalize_elem;
+
+finalize_elem *Vall_finalizable_objs;
+Lisp_Object Vfinalizers_to_run;
+
+void
+add_finalizable_obj (Lisp_Object obj)
+{
+  finalize_elem *next = Vall_finalizable_objs;
+  Vall_finalizable_objs =
+    (finalize_elem *) xmalloc_and_zero (sizeof (finalize_elem));
+  Vall_finalizable_objs->obj = obj;
+  Vall_finalizable_objs->next = next;
+}
+
+void
+register_for_finalization (void)
+{
+  finalize_elem *rest = Vall_finalizable_objs;
+
+  if (!rest) 
+    return;
+
+  while (!marked_p (rest->obj))
+    {
+      finalize_elem *temp = rest;
+      Vfinalizers_to_run = Fcons (rest->obj, Vfinalizers_to_run);
+      Vall_finalizable_objs = rest->next;
+      xfree (temp, finalize_elem *);
+      rest = Vall_finalizable_objs;
+    }
+
+  while (rest->next)
+    {
+      if (LRECORDP (rest->next->obj)
+	  && !marked_p (rest->next->obj))
+	{
+	  finalize_elem *temp = rest->next;
+	  Vfinalizers_to_run = Fcons (rest->next->obj, Vfinalizers_to_run);
+	  rest->next = rest->next->next;
+	  xfree (temp, finalize_elem *);
+	}
+      else
+	{
+	  rest = rest->next;
+	}
+    }
+  /* Keep objects alive that need to be finalized by marking
+     Vfinalizers_to_run transitively. */
+  kkcc_gc_stack_push_lisp_object (Vfinalizers_to_run, 0, -1);
+  kkcc_marking (0);
+}
+
+void
+run_finalizers (void)
+{
+  Lisp_Object rest;
+  for (rest = Vfinalizers_to_run; !NILP (rest); rest = XCDR (rest))
+    {
+      MC_ALLOC_CALL_FINALIZER (XPNTR (XCAR (rest)));
+    }
+  Vfinalizers_to_run = Qnil;
+}
+#endif /* not NEW_GC */
 
 
 /************************************************************************/
@@ -1514,7 +1584,7 @@
   gc_in_progress = 1;
 #ifndef NEW_GC
   inhibit_non_essential_conversion_operations = 1;
-#endif /* NEW_GC */
+#endif /* not NEW_GC */
 
 #if MAX_SAVE_STACK > 0
 
@@ -1596,14 +1666,14 @@
 	**p++;
   }
 
-#ifdef MC_ALLOC
+#ifdef NEW_GC
   { /* mcpro () */
     Lisp_Object *p = Dynarr_begin (mcpros);
     Elemcount count;
     for (count = Dynarr_length (mcpros); count; count--)
       mark_object (*p++);
   }
-#endif /* MC_ALLOC */
+#endif /* NEW_GC */
 
   { /* GCPRO() */
     struct gcpro *tail;
@@ -1708,7 +1778,7 @@
 gc_finalize (void)
 {
   GC_SET_PHASE (FINALIZE);
-  mc_finalize ();
+  register_for_finalization ();
 }
 
 void
@@ -1769,12 +1839,12 @@
 	}
     }
 
-#ifndef MC_ALLOC
+#ifndef NEW_GC
   if (!breathing_space)
     {
       breathing_space = malloc (4096 - MALLOC_OVERHEAD);
     }
-#endif /* not MC_ALLOC */
+#endif /* not NEW_GC */
 
   need_to_signal_post_gc = 1;
   funcall_allocation_flag = 1;
@@ -1887,12 +1957,12 @@
 	if (!gc_resume_mark (incremental))
 	  return; /* suspend gc */
       gc_finish_mark ();
+    case FINISH_MARK:
+      gc_finalize ();
       kkcc_gc_stack_free ();
 #ifdef DEBUG_XEMACS
       kkcc_bt_free ();
 #endif
-    case FINISH_MARK:
-      gc_finalize ();
     case FINALIZE:
       gc_sweep ();
     case SWEEP:
@@ -2023,12 +2093,16 @@
 #ifdef NEW_GC
   gc_cons_incremental_threshold = GC_CONS_INCREMENTAL_THRESHOLD;
   gc_incremental_traversal_threshold = GC_INCREMENTAL_TRAVERSAL_THRESHOLD;
-#endif /* not NEW_GC */
+#endif /* NEW_GC */
 }
 
 void
 init_gc_early (void)
 {
+#ifdef NEW_GC
+  /* Reset the finalizers_to_run list after pdump_load. */
+  Vfinalizers_to_run = Qnil;
+#endif /* NEW_GC */
 }
 
 void
@@ -2174,6 +2248,9 @@
 *incremental garbage collection, the garbage collector then only does
 *full collects (even if (gc-incremental) is called).
 */ );
+
+  Vfinalizers_to_run = Qnil;
+  staticpro_nodump (&Vfinalizers_to_run);
 #endif /* NEW_GC */
 }