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.h | |
| 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.h')
| -rw-r--r-- | src/itree.h | 46 |
1 files changed, 25 insertions, 21 deletions
diff --git a/src/itree.h b/src/itree.h index dc448233224..37cd423d34a 100644 --- a/src/itree.h +++ b/src/itree.h | |||
| @@ -107,10 +107,6 @@ enum itree_order | |||
| 107 | ITREE_POST_ORDER, | 107 | ITREE_POST_ORDER, |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | extern void init_itree (void); | ||
| 111 | #ifdef HAVE_UNEXEC | ||
| 112 | extern void forget_itree (void); | ||
| 113 | #endif | ||
| 114 | extern void itree_node_init (struct itree_node *, bool, bool, Lisp_Object); | 110 | extern void itree_node_init (struct itree_node *, bool, bool, Lisp_Object); |
| 115 | extern ptrdiff_t itree_node_begin (struct itree_tree *, struct itree_node *); | 111 | extern ptrdiff_t itree_node_begin (struct itree_tree *, struct itree_node *); |
| 116 | extern ptrdiff_t itree_node_end (struct itree_tree *, struct itree_node *); | 112 | extern ptrdiff_t itree_node_end (struct itree_tree *, struct itree_node *); |
| @@ -129,17 +125,28 @@ extern void itree_delete_gap (struct itree_tree *, ptrdiff_t, ptrdiff_t); | |||
| 129 | 125 | ||
| 130 | /* Iteration functions. Almost all code should use ITREE_FOREACH | 126 | /* Iteration functions. Almost all code should use ITREE_FOREACH |
| 131 | instead. */ | 127 | instead. */ |
| 132 | extern bool itree_iterator_busy_p (void); | 128 | extern struct itree_iterator *itree_iterator_start (struct itree_iterator *, |
| 133 | extern struct itree_iterator *itree_iterator_start (struct itree_tree *, | 129 | struct itree_tree *, |
| 134 | ptrdiff_t, | 130 | ptrdiff_t, |
| 135 | ptrdiff_t, | 131 | ptrdiff_t, |
| 136 | enum itree_order, | 132 | enum itree_order); |
| 137 | const char *, int); | ||
| 138 | extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t, | 133 | extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t, |
| 139 | ptrdiff_t); | 134 | ptrdiff_t); |
| 140 | extern void itree_iterator_finish (struct itree_iterator *); | 135 | extern void itree_iterator_finish (struct itree_iterator *); |
| 141 | extern struct itree_node *itree_iterator_next (struct itree_iterator *); | 136 | extern struct itree_node *itree_iterator_next (struct itree_iterator *); |
| 142 | 137 | ||
| 138 | /* State used when iterating interval. */ | ||
| 139 | struct itree_iterator | ||
| 140 | { | ||
| 141 | struct itree_node *node; /* FIXME: It should be either `node` or `stack`. */ | ||
| 142 | struct itree_stack *stack; | ||
| 143 | ptrdiff_t begin; | ||
| 144 | ptrdiff_t end; | ||
| 145 | uintmax_t otick; /* A copy of the tree's `otick`. */ | ||
| 146 | enum itree_order order; | ||
| 147 | bool running; | ||
| 148 | }; | ||
| 149 | |||
| 143 | /* Iterate over the intervals between BEG and END in the tree T. | 150 | /* Iterate over the intervals between BEG and END in the tree T. |
| 144 | N will hold successive nodes. ORDER can be one of : `ASCENDING`, | 151 | N will hold successive nodes. ORDER can be one of : `ASCENDING`, |
| 145 | `DESCENDING`, or `PRE_ORDER`. | 152 | `DESCENDING`, or `PRE_ORDER`. |
| @@ -153,29 +160,26 @@ extern struct itree_node *itree_iterator_next (struct itree_iterator *); | |||
| 153 | BEWARE: | 160 | BEWARE: |
| 154 | - The expression T may be evaluated more than once, so make sure | 161 | - The expression T may be evaluated more than once, so make sure |
| 155 | it is cheap and pure. | 162 | it is cheap and pure. |
| 156 | - Only a single iteration can happen at a time, so make sure none of the | ||
| 157 | code within the loop can start another tree iteration, i.e. it shouldn't | ||
| 158 | be able to run ELisp code, nor GC since GC can run ELisp by way | ||
| 159 | of `post-gc-hook`. | ||
| 160 | - If you need to exit the loop early, you *have* to call `ITREE_ABORT` | 163 | - If you need to exit the loop early, you *have* to call `ITREE_ABORT` |
| 161 | just before exiting (e.g. with `break` or `return`). | 164 | just before exiting (e.g. with `break` or `return`). |
| 162 | - Non-local exits are not supported within the body of the loop. | 165 | - Non-local exits are not supported within the body of the loop. |
| 163 | - Don't modify the tree during the iteration. | 166 | - Don't modify the tree during the iteration. |
| 164 | */ | 167 | */ |
| 165 | #define ITREE_FOREACH(n, t, beg, end, order) \ | 168 | #define ITREE_FOREACH(n, t, beg, end, order) \ |
| 166 | /* FIXME: We'd want to declare `x` right here, but I can't figure out | 169 | /* FIXME: We'd want to declare `n` right here, but I can't figure out |
| 167 | how to make that work here: the `for` syntax only allows a single | 170 | how to make that work here: the `for` syntax only allows a single |
| 168 | clause for the var declarations where we need 2 different types. | 171 | clause for the var declarations where we need 2 different types. |
| 169 | We could use the `struct {foo x; bar y; } p;` trick to declare two | 172 | We could use the `struct {foo x; bar y; } p;` trick to declare two |
| 170 | vars `p.x` and `p.y` of unrelated types, but then none of the names | 173 | vars `p.x` and `p.y` of unrelated types, but then none of the names |
| 171 | of the vars matches the `n` we receive :-(. */ \ | 174 | of the vars matches the `n` we receive :-(. */ \ |
| 172 | if (!t) \ | 175 | if (!t) \ |
| 173 | { } \ | 176 | { } \ |
| 174 | else \ | 177 | else \ |
| 175 | for (struct itree_iterator *itree_iter_ \ | 178 | for (struct itree_iterator itree_local_iter_, \ |
| 176 | = itree_iterator_start (t, beg, end, ITREE_##order, \ | 179 | *itree_iter_ \ |
| 177 | __FILE__, __LINE__); \ | 180 | = itree_iterator_start (&itree_local_iter_, \ |
| 178 | ((n = itree_iterator_next (itree_iter_)) \ | 181 | t, beg, end, ITREE_##order); \ |
| 182 | ((n = itree_iterator_next (itree_iter_)) \ | ||
| 179 | || (itree_iterator_finish (itree_iter_), false));) | 183 | || (itree_iterator_finish (itree_iter_), false));) |
| 180 | 184 | ||
| 181 | #define ITREE_FOREACH_ABORT() \ | 185 | #define ITREE_FOREACH_ABORT() \ |