diff options
| author | Stefan Monnier | 2022-11-17 17:00:22 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2022-11-17 17:00:22 -0500 |
| commit | fb7f1864da4aa4c09756cfe47db6c56b4e87bd14 (patch) | |
| tree | 4ccd8ca7e29c5609fa437884c739106a4f1b2cc2 /src/itree.c | |
| parent | 13003105a8edf746a8e8819122bd1bcdf7f9ecdd (diff) | |
| download | emacs-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.c | 91 |
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. */ | ||
| 242 | struct 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. */ | ||
| 262 | static struct itree_iterator *iter = NULL; | ||
| 263 | |||
| 264 | static int | 241 | static int |
| 265 | itree_max_height (const struct itree_tree *tree) | 242 | itree_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 | |||
| 272 | static struct itree_iterator * | ||
| 273 | itree_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 | |||
| 292 | void | ||
| 293 | init_itree (void) | ||
| 294 | { | ||
| 295 | eassert (!iter); | ||
| 296 | iter = itree_iterator_create (NULL); | ||
| 297 | } | ||
| 298 | |||
| 299 | #ifdef HAVE_UNEXEC | ||
| 300 | void | ||
| 301 | forget_itree (void) | ||
| 302 | { | ||
| 303 | iter = NULL; | ||
| 304 | } | ||
| 305 | #endif | ||
| 306 | |||
| 307 | struct check_subtree_result | 247 | struct 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, | |||
| 871 | static bool | 811 | static bool |
| 872 | itree_contains (struct itree_tree *tree, struct itree_node *node) | 812 | itree_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 | ||
| 1307 | bool | ||
| 1308 | itree_iterator_busy_p (void) | ||
| 1309 | { | ||
| 1310 | return (iter && iter->running); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | /* Stop using the iterator. */ | 1247 | /* Stop using the iterator. */ |
| 1314 | 1248 | ||
| 1315 | void | 1249 | void |
| 1316 | itree_iterator_finish (struct itree_iterator *iter) | 1250 | itree_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 | ||
| 1506 | struct itree_iterator * | 1441 | struct itree_iterator * |
| 1507 | itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin, | 1442 | itree_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)); */ |