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:
parent
8159d8b1a7
commit
06252617b2
2 changed files with 21 additions and 4 deletions
22
src/alloc.c
22
src/alloc.c
|
@ -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 &&
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue