74 |
Discussion |
Discussion |
75 |
========== |
========== |
76 |
|
|
77 |
|
Why bother providing this kind of facility? Because otherwise most C |
78 |
|
applications that link Guile will need to find some other way to |
79 |
|
prevent the use of continuations across callbacks if they are to avoid |
80 |
|
a source of bugs. It makes sense to provide this in libguile, where |
81 |
|
the ability to modify the internals of the continuation implementation |
82 |
|
is a significant advantage, as discussed further below. |
83 |
|
|
84 |
There are two ways that longjmp may be invoked from a Scheme callback: |
There are two ways that longjmp may be invoked from a Scheme callback: |
85 |
raising an exception or invoking a continuation. Exceptions can be |
raising an exception or invoking a continuation. Exceptions can be |
86 |
caught using scm_internal_catch, but a primitive "continuation |
caught using scm_internal_catch, but a primitive "continuation |
150 |
|
|
151 |
To implement the continuation barrier, for each thread we can have a |
To implement the continuation barrier, for each thread we can have a |
152 |
simple list representing the barrier (let's call it |
simple list representing the barrier (let's call it |
153 |
with-continuation-barrier, wcb) dynamic state. The head of the list |
with-continuation-barrier, w-c-b) dynamic state. The head of the list |
154 |
would be stored in a thread-local location. Whenever the scope of a |
would be stored in a thread-local location. Whenever the scope of a |
155 |
wcb expression is entered, a new cons cell could be inserted at the |
w-c-b expression is entered, a new cons cell could be inserted at the |
156 |
head of the list. When the scope is exited, the cell would be removed |
head of the list. When the scope is exited, the cell would be removed |
157 |
(this implies a need for an integrated exception handler, to catch |
(this implies a need for an integrated exception handler, to catch |
158 |
non-local exit. Non-local exit or entry by continuation will not be |
non-local exit. Non-local exit or entry by continuation will not be |
161 |
invoked, the stored cell pointer can be compared with the address of |
invoked, the stored cell pointer can be compared with the address of |
162 |
the cell currently at the head of the list. |
the cell currently at the head of the list. |
163 |
|
|
164 |
This wcb list comparison would also prevent cross-thread invokation, |
This w-c-b list comparison would also prevent cross-thread invokation, |
165 |
so comparison of thread-ids can be dropped. |
so comparison of thread-ids can be dropped. |
166 |
|
|
167 |
An example implementation to play with is attached below. |
An example implementation to play with is attached below. |
185 |
|
|
186 |
On the other hand, the body procedure is expected to be a Scheme |
On the other hand, the body procedure is expected to be a Scheme |
187 |
closure in most cases. This suggests implementing two C procedures, |
closure in most cases. This suggests implementing two C procedures, |
188 |
the first taking four arguments: |
the first taking four arguments. In the example implementation it's: |
|
|
|
|
scm_t_catch_body body, void *body_data, |
|
|
scm_t_catch_handler handler, void *handler_data |
|
|
|
|
|
and the second taking three arguments: |
|
|
SCM body, scm_t_catch_handler handler, void *handler_data |
|
189 |
|
|
190 |
If there is also to be a Scheme interface, then it would be implemented |
SCM |
191 |
with a third variant: |
scm_c_c_continuation_barrier (scm_t_catch_body body, void *body_data, |
192 |
SCM body, SCM handler |
scm_t_catch_handler handler, |
193 |
|
void *handler_data) |
194 |
|
|
195 |
|
The second procedure takes three arguments: |
196 |
|
|
197 |
|
SCM |
198 |
|
scm_c_continuation_barrier (SCM body, |
199 |
|
scm_t_catch_handler handler, |
200 |
|
void *handler_data) |
201 |
|
|
202 |
|
Should the facility be provide at the Scheme level too, or just in C? |
203 |
|
There's no obvious reason to restrict the application of callbacks to |
204 |
|
C, hence there is a third variant that takes two SCM arguments: |
205 |
|
|
206 |
|
SCM_DEFINE (scm_with_continuation_barrier, "with-continuation-barrier", |
207 |
|
2, 0, 0, |
208 |
|
(SCM body, SCM handler), |
209 |
|
"") |
210 |
|
#define FUNC_NAME s_scm_with_continuation_barrier |
211 |
|
|
212 |
The second and third variants would be implemented by calling the |
The second and third variants are implemented by calling the first, |
213 |
first, similar to the old scm_call_with_dynamic_root and its wrappers. |
similar to the old scm_internal_cwdr and its wrappers. |
214 |
|
|
215 |
The return value from all variants should be the result of calling |
The return value from all variants should be the result of calling |
216 |
the body, unless an exception occurred in which case it's the result |
the body, unless an exception occurred in which case it's the result |
217 |
of calling the handler. So the return type is SCM, as for |
of calling the handler. So the return type is SCM, as for |
218 |
scm_internal_catch. |
scm_internal_catch. |
219 |
|
|
220 |
|
Guile's current (version 1.6) usage of call-with-dynamic-root |
221 |
|
============================================================= |
222 |
|
|
223 |
|
There are three relevant functions exported from root.c: |
224 |
|
|
225 |
|
scm_internal_cwdr is not documented. It implements |
226 |
|
scm_call_with_dynamic_root and scm_apply_with_dynamic_root and is |
227 |
|
also called from coop-threads.c. |
228 |
|
|
229 |
|
scm_call_with_dynamic_root implements call-with-dynamic-root and is |
230 |
|
documented in the reference manual. It is not used by Guile. |
231 |
|
|
232 |
|
scm_apply_with_dynamic_root is not documented. It is not used by |
233 |
|
Guile. |
234 |
|
|
235 |
|
The usage of scm_internal_cwdr during spawning of coop threads is for |
236 |
|
two reasons: firstly to complete the initialisation of the new |
237 |
|
dynamic-root, secondly to install the exception handler. It would be |
238 |
|
easy to reimplement these using some other method, particularly since |
239 |
|
some of the dynamic-root initialisation will no longer be required if |
240 |
|
these functions are removed. |
241 |
|
|
242 |
|
Hence there should be no problem in deprecating all three exported |
243 |
|
functions. To remove them completely will require minor changes to |
244 |
|
coop thread spawning, which will benefit by simplification of the |
245 |
|
scm_root struct. |
246 |
|
|
247 |
To do |
To do |
248 |
===== |
===== |
249 |
|
|
250 |
libguile usage and threads, error handling and reporting, more on |
error handling and reporting (stack trace?), more on convenience of |
251 |
convenience of use, Scheme-level interface. |
use (e.g., try it out in Guppi). |
252 |
|
|
253 |
References |
References |
254 |
========== |
========== |