Revert "mark_overlays: Use the normal ITREE_FOREACH"

This reverts commit b8fbd42f0a,
with edits.

* src/alloc.c (mark_overlays): restore function.
(mark_buffer): Call it, not ITREE_FOREACH.
(garbage_collect): eassert (!itree_busy_p ()).
* src/itree.h: Comment tweak: explain why GC is considered risky.  It
isn't that GC itself is risky, it is that GC can call ELisp by way of
a hook, and running ELisp during iteration is risks nested iteration.
This commit is contained in:
Matt Armstrong 2022-10-19 13:42:35 -07:00 committed by Stefan Monnier
parent 8159d8b1a7
commit 06252617b2
2 changed files with 21 additions and 4 deletions

View file

@ -6279,6 +6279,11 @@ garbage_collect (void)
image_prune_animation_caches (false);
#endif
/* ELisp code run by `gc-post-hook' could result in itree iteration,
which must not happen while the itree is already busy. See
bug#58639. */
eassert (!itree_iterator_busy_p ());
if (!NILP (Vpost_gc_hook))
{
specpdl_ref gc_count = inhibit_garbage_collection ();
@ -6510,6 +6515,18 @@ mark_overlay (struct Lisp_Overlay *ov)
mark_object (ov->plist);
}
/* Mark the overlay subtree rooted at NODE. */
static void
mark_overlays (struct interval_node *node)
{
if (node == NULL)
return;
mark_object (node->data);
mark_overlays (node->left);
mark_overlays (node->right);
}
/* Mark Lisp_Objects and special pointers in BUFFER. */
static void
@ -6531,9 +6548,8 @@ mark_buffer (struct buffer *buffer)
if (!BUFFER_LIVE_P (buffer))
mark_object (BVAR (buffer, undo_list));
struct interval_node *node;
ITREE_FOREACH (node, buffer->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
mark_object (node->data);
if (buffer->overlays)
mark_overlays (buffer->overlays->root);
/* If this is an indirect buffer, mark its base buffer. */
if (buffer->base_buffer &&

View file

@ -149,7 +149,8 @@ struct interval_node *itree_iterator_next (struct itree_iterator *);
it is cheap a pure.
- Only a single iteration can happen at a time, so make sure none of the
code within the loop can start another tree iteration, i.e. it shouldn't
be able to run ELisp code (or GC for that matter).
be able to run ELisp code, nor GC since GC can run ELisp by way
of `post-gc-hook`.
- If you need to exit the loop early, you *have* to call `ITREE_ABORT`
just before exiting (e.g. with `break` or `return`).
- Non-local exits are not supported within the body of the loop.