* Stack unwinding for C code
@ 2003-12-26 21:36 Marius Vollmer
2003-12-27 9:53 ` tomas
2003-12-27 12:11 ` Neil Jerram
0 siblings, 2 replies; 16+ messages in thread
From: Marius Vollmer @ 2003-12-26 21:36 UTC (permalink / raw)
Hi,
I'm slowly making progress with replacing the gh_ interface and I
found that we first need to have good support for dealing with
non-local exits in the middle of allocating some temporary data
structures in order to prevent memory leaks.
We could either prevent non-local exits for a region of code, or allow
them and register cleanup actions. Preventing them is difficult since
since you either need to avoid calling almost all libguile functions
in that region (which is very restrictive) or make sure that no error
actually happens (which is very difficult in a multi-threaded
program).
The proposal below therefore addresses the registerin of cleanup
actions, much like dynwind but in a more C friendly way.
Comments? (I hope to implement most of it in the next days...)
Unwinding C call frames
-----------------------
Error reporting differes between C and Scheme: C functions usually
return some kind of indication to their calling function when an error
occured. Scheme functions (including functions written in C that
follow the Scheme conventions) on the other hand usually do not return
to their caller in case of an error but instead transfer control to
some handler 'up the stack'.
Such a non-local transfer of control is called "unwinding the stack"
(and is implemented with longjmp).
Sometimes, it is necessary to perform cleanups when the unwinding
happens. Frequently, dynamically allocated temporary data structures
need to be deallocated, for example.
Scheme code can use 'dynwind' to register such cleanup actions. C
code could use it as well, but it would require a lot of code that
would be unnatural for C. Therefore, Guile offers a facility that is
better suited for C code.
These frames also inhibit continuations (as explained below). Thus,
you might want to use frames even when you don't have any cleanup
actions to perform. Also, the label that appears in a backtrace is
useful on it own as well.
Here is an example. Reference documentation is below.
/* Suppose there is a function called FOO in some library that you
would like to make available to Scheme code (or to C code that
follows the Scheme conventions).
FOO takes two C strings and returns a new string. When an error
has occured in FOO, it returns NULL.
*/
char *foo (char *s1, char *s2);
/* SCM_FOO interfaces the C function FOO to the Scheme way of life.
It takes care to free up all temporary strings in the case of
non-local exits. */
SCM
scm_foo (SCM s1, SCM s2)
{
char *c_s1, *c_s2, *c_res;
scm_begin_frame ("foo");
{
c_s1 = scm_to_string (s1);
scm_on_unwind (free, s1, 1);
c_s2 = scm_to_string (s2);
scm_on_unwind (free, s2, 1);
c_res = foo (c_s1, c_s2);
if (c_res == NULL)
scm_memory_error ("foo");
}
scm_end_frame ();
return scm_from_string (res, 1);
}
- C Function: void scm_begin_frame (const char *label)
Starts a new frame and makes it the 'current' one. The frame will
be 'non-continueable', see below.
The given LABEL will appear in backtraces and error messages.
The frame is ended either implicitely when a non-local exit happens,
or explicitely with scm_end_frame.
- C Function: void scm_on_unwind (void (*func)(void *), void *data,
int explicit)
Arranges for FUNC to be called with DATA as its arguments when the
current frame ends implicitely. When EXPLICITElY is non-zero, FUNC
is also called when the frame ends explicitely.
- C Function: void scm_end_frame ()
End the current frame explicitely and make the previous frame
current.
Continuations and frames
------------------------
In addition to unwinding the stack, Scheme can also 'rewind' it. This
can happen when a continuation is called. When a stack is rewound,
call frames are added back to it. This can even happen multiple times
so that some code might find that a function returns more than once.
This is against the expections of most C code. For this reason, the
frames explained above do not allow the construction or invokation of
continuations while they are active. Thus, a frame ends exactly once,
either implicetely or explicitely.
When you do want to allow continuations, you can start a frame with
scm_begin_continuable_frame instead of with scm_begin_frame. In
addition to unwind actions, you can also register rewind actions for
such frames with scm_on_rewind.
- C Function: void scm_begin_frame (const char *label)
Starts a new frame and makes it the 'current' one. The frame will
be 'continueable', that is, it allows continuations to be created
and invoked while it is active.
- C Function: void scm_on_rewind (void (*func)(void *), void *data,
int explicit)
Arrange for FUNC to be called with DATA as its argument when the
current frame is restarted by rewinding the stack. When EXPLICIT is
non-zero, FUNC is called immediately as well.
Related stuff
-------------
- C Function: void scm_c_define_proc (const char *name,
int req, int opt, int restp,
SCM (*proc) (...))
The same as scm_c_define_gsubr but automatically begins and ends a
non-continuable frame around the call to PROC. The label of the
frame is NAME.
Implementation
--------------
The frames stuff above can and probably should be the basis for all
the dynwind business of Guile, with scm_dynwind, for example, being
implemented using scm_begin_continuable_frame, scm_on_rewind,
scm_on_unwind, etc.
Also, the frames stored by the debugging evaluator could be combined
with this.
All data for frames could ba allocated on the stack, but the above API
does not allow this. This has been done to achieve easy binary
compatibility and a very clean and simple API.
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-26 21:36 Stack unwinding for C code Marius Vollmer
@ 2003-12-27 9:53 ` tomas
2003-12-27 12:11 ` Neil Jerram
1 sibling, 0 replies; 16+ messages in thread
From: tomas @ 2003-12-27 9:53 UTC (permalink / raw)
Cc: guile-devel
On Fri, Dec 26, 2003 at 10:36:31PM +0100, Marius Vollmer wrote:
> Hi,
>
> I'm slowly making progress with replacing the gh_ [...]
> Comments? (I hope to implement most of it in the next days...)
Nice interface. I really like it. The best Christmas present
to date :-)
One typo nit: s/invokation/invocation/
Thanks
-- tomás
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-26 21:36 Stack unwinding for C code Marius Vollmer
2003-12-27 9:53 ` tomas
@ 2003-12-27 12:11 ` Neil Jerram
2003-12-27 17:37 ` Marius Vollmer
1 sibling, 1 reply; 16+ messages in thread
From: Neil Jerram @ 2003-12-27 12:11 UTC (permalink / raw)
Cc: guile-devel
>>>>> "Marius" == Marius Vollmer <mvo@zagadka.de> writes:
Marius> The proposal below therefore addresses the registerin of cleanup
Marius> actions, much like dynwind but in a more C friendly way.
Marius> Comments? (I hope to implement most of it in the next days...)
Hi Marius,
This looks nice - I'll take your word for it that we need this, and
the API looks clean as you say. A few comments and typo corrections,
though ...
Marius> Error reporting differes between C and Scheme: C functions usually
Marius> return some kind of indication to their calling function when an error
Marius> occured. Scheme functions (including functions written in C that
typo - "occurred"
Marius> These frames also inhibit continuations (as explained
Marius> below). [...]
In API terms, this feels to me like the same area as issues like
SCM_DEFER_INTS, control of signal delivery, inhibiting thread
switching, etc. I realize that these are quite different mechanisms
really, but it would be lovely if the API that you are proposing here
could also cope with and document all those other areas once and for
all.
Marius> scm_begin_frame ("foo");
Marius> {
Is this block necessary? - it looks a little ugly to me.
Marius> Starts a new frame and makes it the 'current' one. The frame will
Marius> be 'non-continueable', see below.
typo - "continuable"
Also differs - perhaps confusingly - from my use of "continuable" for
a stack in (ice-9 debugger). (My use of "continuable" is to describe
a stack at a breakpoint, where execution can continue, as opposed to
the-last-stack after an error, where execution cannot continue.
Perhaps "continuation-proof" or "continuation-protected"?
Marius> The given LABEL will appear in backtraces and error messages.
How (out of interest)?
Marius> The frame is ended either implicitely when a non-local exit happens,
Marius> or explicitely with scm_end_frame.
typos - "implicitly", "explicitly"
Marius> Arranges for FUNC to be called with DATA as its arguments when the
Marius> current frame ends implicitely. When EXPLICITElY is non-zero, FUNC
Marius> is also called when the frame ends explicitely.
"If" sounds better than "When" here, I'd say.
Marius> This is against the expections of most C code. For this reason, the
Marius> frames explained above do not allow the construction or invokation of
typos - "expectations", "invocation"
Marius> - C Function: void scm_c_define_proc (const char *name,
Marius> int req, int opt, int restp,
Marius> SCM (*proc) (...))
This is not a good name: it is not helpful to suggest that "proc" =
"framed gsubr". How about scm_c_define_framed_gsubr ?
Marius> Also, the frames stored by the debugging evaluator could be combined
Marius> with this.
Interesting. Do you propose to do this as part of your initial work?
Regards,
Neil
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-27 12:11 ` Neil Jerram
@ 2003-12-27 17:37 ` Marius Vollmer
2003-12-28 2:25 ` Tom Lord
2003-12-29 23:25 ` Neil Jerram
0 siblings, 2 replies; 16+ messages in thread
From: Marius Vollmer @ 2003-12-27 17:37 UTC (permalink / raw)
Cc: guile-devel
Neil Jerram <neil@ossau.uklinux.net> writes:
> This looks nice - I'll take your word for it that we need this, and
> the API looks clean as you say.
Don't you think we need it? Maybe I'm overlooking some obvious
alternative that would work just as well...
The example shows what I want to achieve: during a sequence of
conversions from SCM objects to C data structures, we will frequently
have the case that an earlier conversion has allocated some resources
that need to be freed later on. However a later conversion might want
to throw an error and the cleanup needs to happen then.
First, we (on #guile) tried some approaches that would prevent the
throwing of errors. For example, we could separate type checking and
conversion, ala
scm_check_string (s1);
scm_check_string (s2);
/* Now the conversion functions are guaranteed not to throw. */
c_s1 = scm_to_string (s1);
c_s2 = scm_to_string (s2);
But this leads to problems in a multi-threaded program: when you have
composite SCM types such as a list, you must make absolutely sure that
the object doesn't change from checking to conversion. You need to
stop all other guile threads during the conversion sequence, which is
at least as costly as having this unwind machinery, I think.
> A few comments and typo corrections,
> though ...
Thanks, hopefully the poor form didn't distract from the content...
> Marius> These frames also inhibit continuations (as explained
> Marius> below). [...]
>
> In API terms, this feels to me like the same area as issues like
> SCM_DEFER_INTS, control of signal delivery, inhibiting thread
> switching, etc. I realize that these are quite different mechanisms
> really, but it would be lovely if the API that you are proposing here
> could also cope with and document all those other areas once and for
> all.
Hmm. I had to change the continuation stuff already: just disallowing
all construction and invocation of continuations is too restricitve:
continuations that are only used below the frame cause no harm. Only
continuations that cause the frame to be rewound need to be prevented.
This is too restrictive as well, in a sense, since continuations that
are only used in a suspend/resume way (for threads or coroutines, say)
are OK as well. But the general continuations are too general to know
how they are going to be used, so throwing an error when such a frame
is rewound is all we can do.
> Marius> scm_begin_frame ("foo");
> Marius> {
>
> Is this block necessary? - it looks a little ugly to me.
No, scm_begin_frame is a normal function, nothing special about it.
> Marius> Starts a new frame and makes it the 'current' one.
> Marius> The frame will be 'non-continueable', see below.
>
> typo - "continuable"
Yeah, thanks. :-) I knew it was wrong, but I couldn't figure out what
was right. Ispell doesn't know about "continuable"...
> Also differs - perhaps confusingly - from my use of "continuable" for
> a stack in (ice-9 debugger). (My use of "continuable" is to describe
> a stack at a breakpoint, where execution can continue, as opposed to
> the-last-stack after an error, where execution cannot continue.
Yes, the term isn't very good for what I use it for.
> Perhaps "continuation-proof" or "continuation-protected"?
What about "rewindable"?
> Marius> The given LABEL will appear in backtraces and error messages.
>
> How (out of interest)?
Don't know yet! :-) Also, I'm no longer sure that it is a good idea to
combine the backtrace stuff with the frame stuff. I think I'll remove
the label.
(I think that ultimately, we should have a different way of reporting
error from C code: we should not include the subr name in the call to
the error reporting function but rather rely on a more general
mechanism for providing a backtrace for C code. I found it attractive
to just combine it with the frame stuff, but it probably is too
early...)
>
> Marius> The frame is ended either implicitely when a non-local
> Marius> exit happens, or explicitely with scm_end_frame.
>
> typos - "implicitly", "explicitly"
Oops, I do that all the time...
> Marius> Arranges for FUNC to be called with DATA as its
> Marius> arguments when the current frame ends implicitely.
> Marius> When EXPLICITElY is non-zero, FUNC is also called when
> Marius> the frame ends explicitely.
>
> "If" sounds better than "When" here, I'd say.
Ok.
> Marius> - C Function: void scm_c_define_proc (const char *name,
> Marius> int req, int opt,
> Marius> int restp,
> Marius> SCM (*proc) (...))
>
> This is not a good name: it is not helpful to suggest that "proc" =
> "framed gsubr". How about scm_c_define_framed_gsubr ?
Hmm. That is so technical. I wanted to imply that scm_c_define_proc
is the usual way to export C procedures to Scheme. Even if you don't
explicitly ;) ask for a frame, you still get it since it is good for
you....
But, yeah, I'm removing this together with the label stuff.
> Marius> Also, the frames stored by the debugging evaluator could
> Marius> be combined with this.
>
> Interesting. Do you propose to do this as part of your initial work?
Well, no. They are too different after all. It is very nice how
efficient the debugging frames currently are, and I wouldn't want to
destroy that.
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-27 17:37 ` Marius Vollmer
@ 2003-12-28 2:25 ` Tom Lord
2003-12-29 22:12 ` Marius Vollmer
2003-12-29 23:25 ` Neil Jerram
1 sibling, 1 reply; 16+ messages in thread
From: Tom Lord @ 2003-12-28 2:25 UTC (permalink / raw)
Cc: guile-devel, neil
> From: Marius Vollmer <mvo@zagadka.de>
> First, we (on #guile) tried some approaches that would prevent the
> throwing of errors.
Did you consider simply using error-codes as return values?
-t
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-28 2:25 ` Tom Lord
@ 2003-12-29 22:12 ` Marius Vollmer
0 siblings, 0 replies; 16+ messages in thread
From: Marius Vollmer @ 2003-12-29 22:12 UTC (permalink / raw)
Cc: neil, guile-devel
Tom Lord <lord@emf.net> writes:
> > From: Marius Vollmer <mvo@zagadka.de>
>
> > First, we (on #guile) tried some approaches that would prevent the
> > throwing of errors.
>
>
> Did you consider simply using error-codes as return values?
Yes. That would create two different styles of libguile functions,
and you wouldn't be able to use the functions that throw errors in
situations were you have cleanups pending. That would be too
restricing I think.
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-27 17:37 ` Marius Vollmer
2003-12-28 2:25 ` Tom Lord
@ 2003-12-29 23:25 ` Neil Jerram
2003-12-31 0:10 ` Marius Vollmer
1 sibling, 1 reply; 16+ messages in thread
From: Neil Jerram @ 2003-12-29 23:25 UTC (permalink / raw)
Cc: guile-devel
>>>>> "Marius" == Marius Vollmer <mvo@zagadka.de> writes:
Marius> Neil Jerram <neil@ossau.uklinux.net> writes:
>> This looks nice - I'll take your word for it that we need this, and
>> the API looks clean as you say.
Marius> Don't you think we need it? Maybe I'm overlooking some obvious
Marius> alternative that would work just as well...
Sorry - I didn't mean that at all. I meant only that I hadn't
bothered to think so carefully about the requirement as about your
proposal to meet it. I am happy that this is a real requirement.
>> In API terms, this feels to me like the same area as issues like
>> SCM_DEFER_INTS, control of signal delivery, inhibiting thread
>> switching, etc. I realize that these are quite different mechanisms
>> really, but it would be lovely if the API that you are proposing here
>> could also cope with and document all those other areas once and for
>> all.
Marius> Hmm. I had to change the continuation stuff already: just disallowing
Marius> all construction and invocation of continuations is too restricitve:
Marius> continuations that are only used below the frame cause no harm. Only
Marius> continuations that cause the frame to be rewound need to be prevented.
Marius> This is too restrictive as well, in a sense, since continuations that
Marius> are only used in a suspend/resume way (for threads or coroutines, say)
Marius> are OK as well. But the general continuations are too general to know
Marius> how they are going to be used, so throwing an error when such a frame
Marius> is rewound is all we can do.
This all sounds fine, but I think doesn't address the point that I was
trying to make. My point was that it might be nice to extend your
proposed API so that it could cover the other tricky points in writing
Guile C code, some of which I listed above.
>> Perhaps "continuation-proof" or "continuation-protected"?
Marius> What about "rewindable"?
Yes! "rewindable" is excellent.
Marius> (I think that ultimately, we should have a different way of reporting
Marius> error from C code: we should not include the subr name in the call to
Marius> the error reporting function but rather rely on a more general
Marius> mechanism for providing a backtrace for C code. I found it attractive
Marius> to just combine it with the frame stuff, but it probably is too
Marius> early...)
You're probably right, but to be sure I suspect we need more
experiences from users using Guile's debugging tools first. I doubt
it's worth playing with this until we know more about what is really
useful.
Marius> - C Function: void scm_c_define_proc (const char *name,
Marius> int req, int opt,
Marius> int restp,
Marius> SCM (*proc) (...))
>>
>> This is not a good name: it is not helpful to suggest that "proc" =
>> "framed gsubr". How about scm_c_define_framed_gsubr ?
Marius> Hmm. That is so technical. I wanted to imply that scm_c_define_proc
Marius> is the usual way to export C procedures to Scheme. Even if you don't
Marius> explicitly ;) ask for a frame, you still get it since it is good for
Marius> you....
Marius> But, yeah, I'm removing this together with the label stuff.
I don't understand. It could still be useful for C procedures to be
non-rewindable by default, even if there isn't a label associated with
the framing. Do you think there is existing C code that uses
scm_c_define_gsubr and uses rewindability, such that we couldn't just
change scm_c_define_gsubr to enforce non-rewindability?
Hoping these comments help ...
Neil
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-29 23:25 ` Neil Jerram
@ 2003-12-31 0:10 ` Marius Vollmer
2004-01-02 11:45 ` Dirk Herrmann
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Marius Vollmer @ 2003-12-31 0:10 UTC (permalink / raw)
Cc: guile-devel
Neil Jerram <neil@ossau.uklinux.net> writes:
> This all sounds fine, but I think doesn't address the point that I was
> trying to make.
Yep, I got carried away, sorry.
> My point was that it might be nice to extend your proposed API so
> that it could cover the other tricky points in writing Guile C code,
> some of which I listed above.
I see. Hmm. I have no ideas (yet) about what to do about
SCM_DEFER_INTS, etc. But you are right, we should have a plan for
bringing all things that are related to the dynamic context together.
So what about separating the API further: there would be only
scm_begin_frame and an additional function scm_prevent_rewind (or
scm_prevent_reentry?) could be used like
scm_begin_frame ();
scm_prevent_rewind ();
...
scm_end_frame ();
Additional things like a label, halting all other threads, etc, could
be done in a similar fashion, later.
This will create a new way to do dynamically scoped things from C.
For example, the scm_c_call_with_blocked_asyncs functionality could be
redone as
scm_begin_frame ();
scm_block_asyncs ();
...
scm_end_frame ();
I think we should ideally offer only one variant, for consistency.
Hmm. scm_c_call_with_blocked_asyncs is easier to use in the sense
that you can't get it wrong. scm_begin_frame, scm_end_frame is easier
since you don't need to write a callback function and funnel all your
state thru a void pointer.
I'm feeling uneasy about all this since it seems gratuitous to
flip/flop the API style around so much. But you just can't tell
people to use scm_internal_dynamic_wind to register their cleanup
actions. That's too much work and feels too heavy; users probably
wont do it by default. (I know I don't.)
(I hope I'm still addressing your point, Neil... ;-)
So, what do you all say? Do we like the frame stuff enough to make it
our new default way of handling all dynamically scoped stuff in C?
Are we sure that users will use it correctly?
I have attached an updated proposal.
I do have an implementation ready and am about to commit it, so people
can try it out. We also need to think about how to integrate it with
C++ exceptions.
> [...] Do you think there is existing C code that uses
> scm_c_define_gsubr and uses rewindability, such that we couldn't
> just change scm_c_define_gsubr to enforce non-rewindability?
Yes, I think so. Functions that only work with SCM objects should be
safe by default.
> Hoping these comments help ...
Of course they do! :-)
Frames
------
Error reporting differs between C and Scheme: C functions usually
return some kind of indication to their calling function when an error
occured. Scheme functions (including functions written in C that
follow the Scheme conventions) on the other hand usually do not return
to their caller in case of an error but instead transfer control to
some handler 'up the stack'.
Such a non-local transfer of control is called "unwinding the stack"
(and is implemented with longjmp).
Sometimes, it is necessary to perform cleanups when the unwinding
happens. Frequently, dynamically allocated temporary data structures
need to be deallocated, for example.
Scheme code can use 'dynamic-wind' to register such cleanup actions.
C code could use it as well, but it would require a lot of code that
would be unnatural for C. Therefore, Guile offers a facility that is
better suited for C code.
Guile offers the functions scm_begin_frame and scm_end_frame to
delimit a dynamic extent. Within this dynamic extent, which is calles
a 'frame', you can perform various 'frame actions' that control what
happens when the frame is entered or left. For example, you can
register a cleanup routine with scm_on_unwind that is executed when
the frame is left.
Here is an example. Reference documentation is below.
/* Suppose there is a function called FOO in some library that you
would like to make available to Scheme code (or to C code that
follows the Scheme conventions).
FOO takes two C strings and returns a new string. When an error
has occurred in FOO, it returns NULL.
*/
char *foo (char *s1, char *s2);
/* SCM_FOO interfaces the C function FOO to the Scheme way of life.
It takes care to free up all temporary strings in the case of
non-local exits. */
SCM
scm_foo (SCM s1, SCM s2)
{
char *c_s1, *c_s2, *c_res;
scm_begin_frame ();
c_s1 = scm_to_string (s1);
scm_on_unwind (free, s1, 1);
c_s2 = scm_to_string (s2);
scm_on_unwind (free, s2, 1);
c_res = foo (c_s1, c_s2);
if (c_res == NULL)
scm_memory_error ("foo");
scm_end_frame ();
return scm_from_string (res, 1);
}
- C Function: void scm_begin_frame (int flags)
Starts a new frame and makes it the 'current' one. FLAGS determines
the default behavior of the frame. For normal frames, use 0. This
will result in a frame that can not be reentered with a captured
continuation. See below.
The frame is ended either implicitly when a non-local exit happens,
or explicitly with scm_end_frame.
- C Function: void scm_on_unwind (void (*func)(void *), void *data,
int explicit)
Arranges for FUNC to be called with DATA as its arguments when the
current frame ends implicitly. If EXPLICIT is non-zero, FUNC is
also called when the frame ends explicitly.
- C Function: void scm_end_frame ()
End the current frame explicitly and make the previous frame
current.
Continuations and frames
------------------------
In addition to unwinding the stack, Scheme can also 'rewind' it. This
can happen when a continuation is called. When a stack is rewound,
call frames are added back to it. This can even happen multiple times
so that some code might find that a function returns more than once.
This is against the expectations of most C code. For this reason, the
frames explained above do not allow the invocation of continuations
that would rewind those frames.
When you do want to allow continuations, you can use the
SCM_F_REWINDABLE_FRAME flag with scm_begin_frame. In addition to
unwind actions, you can also register rewind actions for such frames
with scm_on_rewind.
- C Constant: SCM_F_REWINDABLE_FRAME
When passed as a flag to scm_begin_frame, causes the frame to be
'rewindable'. This means that a continuation that has been captured
during the frame is allowed to be called from its outside.
- C Function: void scm_on_rewind (void (*func)(void *), void *data,
int explicit)
Arrange for FUNC to be called with DATA as its argument when the
current frame is restarted by rewinding the stack. When EXPLICIT is
non-zero, FUNC is called immediately as well.
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-31 0:10 ` Marius Vollmer
@ 2004-01-02 11:45 ` Dirk Herrmann
2004-01-02 17:38 ` Marius Vollmer
2004-01-06 18:37 ` Paul Jarc
2004-01-13 17:24 ` Rob Browning
2 siblings, 1 reply; 16+ messages in thread
From: Dirk Herrmann @ 2004-01-02 11:45 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Marius Vollmer wrote:
>I see. Hmm. I have no ideas (yet) about what to do about
>SCM_DEFER_INTS, etc. But you are right, we should have a plan for
>bringing all things that are related to the dynamic context together.
>So what about separating the API further: there would be only
>scm_begin_frame and an additional function scm_prevent_rewind (or
>scm_prevent_reentry?) could be used like
>
> scm_begin_frame ();
> scm_prevent_rewind ();
> ...
> scm_end_frame ();
>
I like this style of interface for its simplicity. But, I am somewhat
confused since in your proposal below you don't suggest this style of
interface, but instead describe scm_begin_frame as receiving an
additional argument with flags. I wouldn't prefer any of the two
solutions, but I am currently not sure what you actually suggest -
especially since in the example given below you don't pass any argument
to scm_begin_frame.
>Sometimes, it is necessary to perform cleanups when the unwinding
>happens. Frequently, dynamically allocated temporary data structures
>need to be deallocated, for example.
>
If this document was to be reused in the documentation later, we should
given an example here.
>- C Function: void scm_begin_frame (int flags)
>
> Starts a new frame and makes it the 'current' one. FLAGS determines
> the default behavior of the frame. For normal frames, use 0. This
> will result in a frame that can not be reentered with a captured
> continuation. See below.
>
> The frame is ended either implicitly when a non-local exit happens,
> or explicitly with scm_end_frame.
>
If this style of API is used (that is, passing a 'flags' argument to
scm_begin_frame instead of having separate functions like
scm_prevent_rewind and similar), then I suggest to use an enumeration
type with all possible flags instead of an int type. This improves both
type safety and readability of the code using scm_begin_frame. The same
applies to the 'explicit' argument to scm_on_unwind and scm_on_rewind.
>- C Function: void scm_on_unwind (void (*func)(void *), void *data,
> int explicit)
>
> Arranges for FUNC to be called with DATA as its arguments when the
> current frame ends implicitly. If EXPLICIT is non-zero, FUNC is
> also called when the frame ends explicitly.
>
It is a nice coincidence that 'free' matches the void (*func) (void *)
signature, especially since free will probably be one of the most
frequently used functions with scm_on_unwind. fclose, however, does not
match and is another candidate that may be commonly used. Unfortunately
it wouldn't be standard conforming to just cast fclose to match the
signature. I suggest that (in addition to the generic scm_on_unwind) for
a limited set of common functions we provide specialized
scm_on_unwind_xxx functions, like:
scm_on_unwind_free (void *data, int explicit); // could simply be
#defined to scm_on_unwind
scm_on_unwind_fclose (FILE* fp, int explicit); // on some architectures
this may also safely be #defined to scm_on_unwind
// maybe there are other typical cleanup functions...
Then, scm_on_unwind_free could either simply be #defined to
scm_on_unwind, or - if it brings some performance and code size benefit
to avoid passing the additional argument - provided as a special
implementation. On some architectures it may also be an option to just
#define scm_on_unwind_fclose to scm_on_unwind.
Best regards
Dirk Herrmann
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2004-01-02 11:45 ` Dirk Herrmann
@ 2004-01-02 17:38 ` Marius Vollmer
2004-01-03 22:08 ` Marius Vollmer
2004-01-10 11:45 ` Dirk Herrmann
0 siblings, 2 replies; 16+ messages in thread
From: Marius Vollmer @ 2004-01-02 17:38 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Dirk Herrmann <dirk@dirk-herrmanns-seiten.de> writes:
> I like this style of interface for its simplicity.
Ok! Given all the feedback, I'll design/document it as the general
mechanism for dealing with dynamic extents from C.
> But, I am somewhat confused since in your proposal below you don't
> suggest this style of interface, but instead describe
> scm_begin_frame as receiving an additional argument with flags.
Yes, that was confusing, sorry.
> I wouldn't prefer any of the two solutions, but I am currently not
> sure what you actually suggest - especially since in the example
> given below you don't pass any argument to scm_begin_frame.
The first variant (with scm_prevent_rewind) would be more elegant from
an implementational point of view. The latter (with
SCM_F_REWINDABLE_FRAME) leads to a more desirable default behavior. I
think people should explicitely allow rewinding when they have unwind
handlers.
So, I prefer the latter variant.
>>- C Function: void scm_begin_frame (int flags)
>>
>> Starts a new frame and makes it the 'current' one. FLAGS determines
>> the default behavior of the frame. For normal frames, use 0. This
>> will result in a frame that can not be reentered with a captured
>> continuation. See below.
>>
>> The frame is ended either implicitly when a non-local exit happens,
>> or explicitly with scm_end_frame.
>>
> If this style of API is used (that is, passing a 'flags' argument to
> scm_begin_frame instead of having separate functions like
> scm_prevent_rewind and similar), then I suggest to use an enumeration
> type with all possible flags instead of an int type. This improves
> both type safety and readability of the code using
> scm_begin_frame. The same applies to the 'explicit' argument to
> scm_on_unwind and scm_on_rewind.
Yep, agreed.
> It is a nice coincidence that 'free' matches the void (*func) (void
> *) signature, especially since free will probably be one of the most
> frequently used functions with scm_on_unwind. fclose, however, does
> not match and is another candidate that may be commonly
> used. Unfortunately it wouldn't be standard conforming to just cast
> fclose to match the signature.
Is that a theoretical problem or do indeed platforms exist where you
can't cast fclose to (void (*)(void *))?
If it is only theoretical, I'm inclined not to worry about it...
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2004-01-02 17:38 ` Marius Vollmer
@ 2004-01-03 22:08 ` Marius Vollmer
2004-01-10 11:45 ` Dirk Herrmann
1 sibling, 0 replies; 16+ messages in thread
From: Marius Vollmer @ 2004-01-03 22:08 UTC (permalink / raw)
Cc: Neil Jerram, guile-devel
Marius Vollmer <mvo@zagadka.de> writes:
> Ok! Given all the feedback, I'll design/document it as the general
> mechanism for dealing with dynamic extents from C.
Done, please give it a try!
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-31 0:10 ` Marius Vollmer
2004-01-02 11:45 ` Dirk Herrmann
@ 2004-01-06 18:37 ` Paul Jarc
2004-01-07 20:27 ` Marius Vollmer
2004-01-13 17:24 ` Rob Browning
2 siblings, 1 reply; 16+ messages in thread
From: Paul Jarc @ 2004-01-06 18:37 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Marius Vollmer <mvo@zagadka.de> wrote:
> c_s1 = scm_to_string (s1);
> scm_on_unwind (free, s1, 1);
>
> c_s2 = scm_to_string (s2);
> scm_on_unwind (free, s2, 1);
Nit: shouldn't you be passing c_s1 and c_s2 instead of s1 and s2 to
scm_on_unwind?
paul
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2004-01-06 18:37 ` Paul Jarc
@ 2004-01-07 20:27 ` Marius Vollmer
0 siblings, 0 replies; 16+ messages in thread
From: Marius Vollmer @ 2004-01-07 20:27 UTC (permalink / raw)
Cc: guile-devel
prj@po.cwru.edu (Paul Jarc) writes:
> Nit: shouldn't you be passing c_s1 and c_s2 instead of s1 and s2 to
> scm_on_unwind?
Yes, thanks!
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2004-01-02 17:38 ` Marius Vollmer
2004-01-03 22:08 ` Marius Vollmer
@ 2004-01-10 11:45 ` Dirk Herrmann
2004-01-11 1:23 ` Marius Vollmer
1 sibling, 1 reply; 16+ messages in thread
From: Dirk Herrmann @ 2004-01-10 11:45 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Marius Vollmer wrote:
>Dirk Herrmann <dirk@dirk-herrmanns-seiten.de> writes:
>
>
>>I wouldn't prefer any of the two solutions, but I am currently not
>>sure what you actually suggest - especially since in the example
>>given below you don't pass any argument to scm_begin_frame.
>>
>>
>
>The first variant (with scm_prevent_rewind) would be more elegant from
>an implementational point of view. The latter (with
>SCM_F_REWINDABLE_FRAME) leads to a more desirable default behavior. I
>think people should explicitely allow rewinding when they have unwind
>handlers.
>
Hmm, probably I am missing something, but wouldn't it just be possible
to make the non-rewindable frame the default, and offer scm_allow_rewind
as a function then?
>>It is a nice coincidence that 'free' matches the void (*func) (void
>>*) signature, especially since free will probably be one of the most
>>frequently used functions with scm_on_unwind. fclose, however, does
>>not match and is another candidate that may be commonly
>>used. Unfortunately it wouldn't be standard conforming to just cast
>>fclose to match the signature.
>>
>>
>
>Is that a theoretical problem or do indeed platforms exist where you
>can't cast fclose to (void (*)(void *))?
>
>If it is only theoretical, I'm inclined not to worry about it...
>
>
Huh, such casts would need to be added explicitly, both in guile and in
user code. I wouldn't recommend users to use such a programming style.
What we do within guile is a different thing, but even here I am much in
favor of having our code as standard conforming as possible - or at
least encapsulate places where it isn't. Maybe we should first wait what
kinds of cleanup functions we detect to be useful within guile and then
decide about this issue.
Best regards
Dirk
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2004-01-10 11:45 ` Dirk Herrmann
@ 2004-01-11 1:23 ` Marius Vollmer
0 siblings, 0 replies; 16+ messages in thread
From: Marius Vollmer @ 2004-01-11 1:23 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Dirk Herrmann <dirk@dirk-herrmanns-seiten.de> writes:
>>The first variant (with scm_prevent_rewind) would be more elegant from
>>an implementational point of view. The latter (with
>>SCM_F_REWINDABLE_FRAME) leads to a more desirable default behavior. I
>>think people should explicitely allow rewinding when they have unwind
>>handlers.
>>
> Hmm, probably I am missing something, but wouldn't it just be possible
> to make the non-rewindable frame the default, and offer
> scm_allow_rewind as a function then?
Yes, that would be possible, but the flags variant is OK, too, no?
> [...] Maybe we should first wait what kinds of cleanup functions we
> detect to be useful within guile and then decide about this issue.
Yes.
--
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: Stack unwinding for C code
2003-12-31 0:10 ` Marius Vollmer
2004-01-02 11:45 ` Dirk Herrmann
2004-01-06 18:37 ` Paul Jarc
@ 2004-01-13 17:24 ` Rob Browning
2 siblings, 0 replies; 16+ messages in thread
From: Rob Browning @ 2004-01-13 17:24 UTC (permalink / raw)
Cc: guile-devel, Neil Jerram
Marius Vollmer <mvo@zagadka.de> writes:
> So, what do you all say? Do we like the frame stuff enough to make
> it our new default way of handling all dynamically scoped stuff in
> C?
A bit belated, I know, but it seems like a good approach to me.
--
Rob Browning
rlb @defaultvalue.org and @debian.org; previously @cs.utexas.edu
GPG starting 2002-11-03 = 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2004-01-13 17:24 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-12-26 21:36 Stack unwinding for C code Marius Vollmer
2003-12-27 9:53 ` tomas
2003-12-27 12:11 ` Neil Jerram
2003-12-27 17:37 ` Marius Vollmer
2003-12-28 2:25 ` Tom Lord
2003-12-29 22:12 ` Marius Vollmer
2003-12-29 23:25 ` Neil Jerram
2003-12-31 0:10 ` Marius Vollmer
2004-01-02 11:45 ` Dirk Herrmann
2004-01-02 17:38 ` Marius Vollmer
2004-01-03 22:08 ` Marius Vollmer
2004-01-10 11:45 ` Dirk Herrmann
2004-01-11 1:23 ` Marius Vollmer
2004-01-06 18:37 ` Paul Jarc
2004-01-07 20:27 ` Marius Vollmer
2004-01-13 17:24 ` Rob Browning
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).