aboutsummaryrefslogtreecommitdiffstats
path: root/src/itree.c
diff options
context:
space:
mode:
authorStefan Monnier2022-11-17 17:00:22 -0500
committerStefan Monnier2022-11-17 17:00:22 -0500
commitfb7f1864da4aa4c09756cfe47db6c56b4e87bd14 (patch)
tree4ccd8ca7e29c5609fa437884c739106a4f1b2cc2 /src/itree.c
parent13003105a8edf746a8e8819122bd1bcdf7f9ecdd (diff)
downloademacs-fb7f1864da4aa4c09756cfe47db6c56b4e87bd14.tar.gz
emacs-fb7f1864da4aa4c09756cfe47db6c56b4e87bd14.zip
itree.c: Make the iterator reentrant (bug#59183)
Get rid of the global iterator object and instead allocate a separate iterator for every loop. This still uses the "duplicate iterator" code, including the old iterator which needs a stack, make ITREE_FOREACH a bit more expensive than we'd like. * src/itree.h (init_itree, forget_itree, itree_iterator_busy_p): Delete declarations. (itree_iterator_start): Add iterator arg and remove `line` and `file` args. (struct itree_iterator): Move from `itree.c`. Remove `line` and `file` fields. (ITREE_FOREACH): Stack allocate an iterator object and pass it to `itree_iterator_start`. * src/itree.c (struct itree_iterator): Move to itree.h. (iter): Delete global variable. (itree_iterator_create, init_itree, forget_itree, itree_iterator_busy_p): Delete functions. (itree_contains): Adjust assertion. (itree_iterator_finish): Deallocate the iterator's stack. (itree_iterator_start): Take the (uninitialized) iterator as argument. Allocate a fresh new stack. Remove `file` and `line` arguments. Don't check `running` any more since the iterator is not expected to be initialized at all. * src/eval.c (signal_or_quit): * src/alloc.c (garbage_collect): Don't check `itree_iterator_busy_p` any more. * src/emacs.c (main): No need to `init_itree` any more. (Fdump_emacs): No need to `forget_itree` any more.
Diffstat (limited to 'src/itree.c')
-rw-r--r--src/itree.c91
1 files changed, 12 insertions, 79 deletions
diff --git a/src/itree.c b/src/itree.c
index 4f25a924b40..9e60071980d 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -238,72 +238,12 @@ itree_stack_pop (struct itree_stack *stack)
238 238
239/* +-----------------------------------------------------------------------+ */ 239/* +-----------------------------------------------------------------------+ */
240 240
241/* State used when iterating interval. */
242struct itree_iterator
243{
244 struct itree_stack *stack;
245 struct itree_node *node;
246 ptrdiff_t begin;
247 ptrdiff_t end;
248
249 /* A copy of the tree's `otick`. */
250 uintmax_t otick;
251 enum itree_order order;
252 bool running;
253 const char *file;
254 int line;
255};
256
257/* Ideally, every iteration would use its own `iter` object, so we could
258 have several iterations active at the same time. In practice, iterations
259 are limited by the fact we don't allow modifying the tree at the same
260 time, making the use of nested iterations quite rare anyway.
261 So we just use a single global iterator instead for now. */
262static struct itree_iterator *iter = NULL;
263
264static int 241static int
265itree_max_height (const struct itree_tree *tree) 242itree_max_height (const struct itree_tree *tree)
266{ 243{
267 return 2 * log (tree->size + 1) / log (2) + 0.5; 244 return 2 * log (tree->size + 1) / log (2) + 0.5;
268} 245}
269 246
270/* Allocate a new iterator for TREE. */
271
272static struct itree_iterator *
273itree_iterator_create (struct itree_tree *tree)
274{
275 struct itree_iterator *g = xmalloc (sizeof *g);
276 /* 19 here just avoids starting with a silly-small stack.
277 FIXME: Since this stack only needs to be about 2*max_depth
278 in the worst case, we could completely pre-allocate it to something
279 like word-bit-size * 2 and then never worry about growing it. */
280 const int size = (tree ? itree_max_height (tree) : 19) + 1;
281
282 g->stack = itree_stack_create (size);
283 g->node = NULL;
284 g->running = false;
285 g->begin = 0;
286 g->end = 0;
287 g->file = NULL;
288 g->line = 0;
289 return g;
290}
291
292void
293init_itree (void)
294{
295 eassert (!iter);
296 iter = itree_iterator_create (NULL);
297}
298
299#ifdef HAVE_UNEXEC
300void
301forget_itree (void)
302{
303 iter = NULL;
304}
305#endif
306
307struct check_subtree_result 247struct check_subtree_result
308{ 248{
309 /* Node count of the tree. */ 249 /* Node count of the tree. */
@@ -871,7 +811,7 @@ itree_node_set_region (struct itree_tree *tree,
871static bool 811static bool
872itree_contains (struct itree_tree *tree, struct itree_node *node) 812itree_contains (struct itree_tree *tree, struct itree_node *node)
873{ 813{
874 eassert (iter && node); 814 eassert (node);
875 struct itree_node *other; 815 struct itree_node *other;
876 ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING) 816 ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING)
877 if (other == node) 817 if (other == node)
@@ -1304,18 +1244,13 @@ itree_delete_gap (struct itree_tree *tree,
1304 * | Iterator 1244 * | Iterator
1305 * +=======================================================================+ */ 1245 * +=======================================================================+ */
1306 1246
1307bool
1308itree_iterator_busy_p (void)
1309{
1310 return (iter && iter->running);
1311}
1312
1313/* Stop using the iterator. */ 1247/* Stop using the iterator. */
1314 1248
1315void 1249void
1316itree_iterator_finish (struct itree_iterator *iter) 1250itree_iterator_finish (struct itree_iterator *iter)
1317{ 1251{
1318 eassert (iter && iter->running); 1252 eassert (iter && iter->running);
1253 itree_stack_destroy (iter->stack);
1319 iter->running = false; 1254 iter->running = false;
1320} 1255}
1321 1256
@@ -1504,18 +1439,18 @@ itree_iterator_first_node (struct itree_tree *tree,
1504 given ORDER. Only one iterator per tree can be running at any time. */ 1439 given ORDER. Only one iterator per tree can be running at any time. */
1505 1440
1506struct itree_iterator * 1441struct itree_iterator *
1507itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin, 1442itree_iterator_start (struct itree_iterator *iter,
1508 ptrdiff_t end, enum itree_order order, 1443 struct itree_tree *tree,
1509 const char *file, int line) 1444 ptrdiff_t begin, ptrdiff_t end, enum itree_order order)
1510{ 1445{
1511 eassert (iter); 1446 eassert (iter);
1512 if (iter->running) 1447 /* eassert (!iter->running); */
1513 { 1448 /* 19 here just avoids starting with a silly-small stack.
1514 fprintf (stderr, 1449 FIXME: Since this stack only needs to be about 2*max_depth
1515 "Detected nested iteration!\nOuter: %s:%d\nInner: %s:%d\n", 1450 in the worst case, we could completely pre-allocate it to something
1516 iter->file, iter->line, file, line); 1451 like word-bit-size * 2 and then never worry about growing it. */
1517 emacs_abort (); 1452 const int size = (tree ? itree_max_height (tree) : 19) + 1;
1518 } 1453 iter->stack = itree_stack_create (size);
1519 uintmax_t otick= tree->otick; 1454 uintmax_t otick= tree->otick;
1520 iter->begin = begin; 1455 iter->begin = begin;
1521 iter->end = end; 1456 iter->end = end;
@@ -1524,8 +1459,6 @@ itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin,
1524 itree_stack_clear (iter->stack); 1459 itree_stack_clear (iter->stack);
1525 if (begin <= end && tree->root != NULL) 1460 if (begin <= end && tree->root != NULL)
1526 itree_stack_push_flagged (iter->stack, tree->root, false); 1461 itree_stack_push_flagged (iter->stack, tree->root, false);
1527 iter->file = file;
1528 iter->line = line;
1529 iter->running = true; 1462 iter->running = true;
1530 /* itree_stack_ensure_space (iter->stack, 1463 /* itree_stack_ensure_space (iter->stack,
1531 2 * itree_max_height (tree)); */ 1464 2 * itree_max_height (tree)); */