guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Refactoring dynamic roots


From: Marius Vollmer
Subject: Refactoring dynamic roots
Date: Mon, 24 Jan 2005 21:55:24 +0100
User-agent: Gnus/5.1003 (Gnus v5.10.3) Emacs/21.3 (gnu/linux)

Hi,

I have a dim plan for redoing dynamic roots in a more useful way and I
like to test the ideas out on you.

Right now, dynamic roots are useful mainly for two things: controlling
continuations so that they don't jump past you, and isolating changes
to the 'dynamic state' (the values of all fluids and the current
ports) of Guile.  I want to separate these two functionalities since
you might want one without the other.  Also, entering a dynamic root
now unwinds the active dynamic-winds to the root and winds them back
when leaving the root.  This might not be wanted and is potentially
expensive.

Also, the roles of dynamic roots in Guile is not as clear now as it
could be, in my view, and cleaning them up will make the internals a
lot simpler, I hope.

** Controlling continuations

Controlling continuations is useful when invoking Scheme callbacks
from C code in a situation where the C code must guarantee that the
callback returns exactly once.

There is a proposal for this in workbook/extensions/dynamic-root.text,
but I want to simplify this even more by not caring about an exception
handler.  Error handling needs to be taken care of anyway, and I think
it is more flexible to not include it in these functions.  For
example, I hope that we have a way in the future to directly specify
an error handler that is called in the dynamic context of the error
and not in the dynamic context from where it was installed.  That
might mean that we have two ways to handle errors and I think it will
be easier to offer them when not too many functions deal with the
business of setting up error handlers.

 - void *scm_c_with_continuation_barrier (void *(func)(void *), void *data)

 Call FUNC on DATA and do not allow the invocation of continuations
 that would cross the invocation to scm_with_continuation_barrier.
 Such an attempt causes an error to be signaled.

 Throws (such as errors) that are not caught from within FUNC are
 caught by scm_with_continuation_barrier.  In that case, a short
 message is printed to the current error port and NULL is returned.

 Thus, scm_with_continuation_barrier returns exactly once.

 [ The docs for scm_with_guile would state that it includes an
   implicit call to scm_c_with_continuation_barrier. ]

 - with-continuation-barrier proc

 Like scm_c_with_continuation_barrier but return '#f' for uncaught
 throws.

** Controlling the dynamic state

The other thing that dynamic roots do is to isolate changes to the
dynamic state.  For example, calls to set-current-output-port or
fluid-set! have no effects outside of a dynamic root.  This might be
useful when running arbitrary code since the caller can protect itself
from unexpected changes to the dynamic state.  (This is not _that_
useful for sandboxing code since the code can of course change the
global state of Guile arbitrarily unless other measures are taken.)

Of course, when running arbitrary code, it is nice to give it its own
dynamic state and to use that dynamic state from one run to the next.
This can not be done with dynamic roots right now since each call to
call-with-dynamic-root creates a new root.  Therefore, the functions
below allow one to create a 'dynamic state' object that can be reused.
I think it would be nice to have 'eval' take such an object as its
second arg.  The dynamic state contains the current module, and in
that way the dynamic state might be a better representation of an
execution environment than just a module.

The implementation would be like this: each thread has a pointer to a
'current dynamic state object'.  The list of active dynamic-winds is
separate from this.  References to fluids and current ports, etc are
made to this current dynamic state object.  Evaluating code with a
different dynamic state object swaps this object in and out via
dynamic-wind.  It wont probably be the case i the beginning, but it
might be good to let a dynamic state object be just the values of the
fluids, nothing more, and do all dynamic state stuff such as the ports
with fluids.

 - make-dynamic-state [parent]

 Make a new dynamic state object and initialize it from PARENT.  When
 PARENT is omitted, the current dynamic state object is used.

 - current-dynamic-state

 Return the current dynamic state object.

 - set-current-dynamic-state state

 Make STATE the current dynamic state object.  Using
 with-dynamic-state is usually more appropriate.  [But since it is
 harmless to provide this function, we do anyway.]

 - with-dynamic-state state proc

 Call PROC while STATE is the current dynamic state object.  This
 behaves like dynamic-wind, swapping the current dynamic states when
 control flow crosses.

 - with-new-dynamic-state proc

 The same as (with-dynamic-state (make-dynamic-state) proc).

 - eval FORM [STATE]

 When the second argument to eval is a dynamic state object, evaluate
 FORM from within a suitable call to with-dynamic-state.

 - void scm_frame_dynamic_state (SCM state)

 Set the current dynamic state to STATE while the current frame is
 active.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]