aboutsummaryrefslogtreecommitdiffstats
path: root/src/itree.h
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.h
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.h')
-rw-r--r--src/itree.h46
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
110extern void init_itree (void);
111#ifdef HAVE_UNEXEC
112extern void forget_itree (void);
113#endif
114extern void itree_node_init (struct itree_node *, bool, bool, Lisp_Object); 110extern void itree_node_init (struct itree_node *, bool, bool, Lisp_Object);
115extern ptrdiff_t itree_node_begin (struct itree_tree *, struct itree_node *); 111extern ptrdiff_t itree_node_begin (struct itree_tree *, struct itree_node *);
116extern ptrdiff_t itree_node_end (struct itree_tree *, struct itree_node *); 112extern 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. */
132extern bool itree_iterator_busy_p (void); 128extern struct itree_iterator *itree_iterator_start (struct itree_iterator *,
133extern 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);
138extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t, 133extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t,
139 ptrdiff_t); 134 ptrdiff_t);
140extern void itree_iterator_finish (struct itree_iterator *); 135extern void itree_iterator_finish (struct itree_iterator *);
141extern struct itree_node *itree_iterator_next (struct itree_iterator *); 136extern struct itree_node *itree_iterator_next (struct itree_iterator *);
142 137
138/* State used when iterating interval. */
139struct 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() \