Dear Marc,
Below A B C D are Scheme procedures and f g h are C procedures.
In case of nested Scheme->C calls, i.e. if A calls f which calls B which calls g which calls C which calls h which calls D etc., then for the application not to enter an undefined state, returning the C calls _MUST_ be done in the exact reverse order in order, right? I.e., D must return to h which must return to C which must return to g which must return to B which must return to f which must return to A. If any mixing of this order is done - i.e. D returns to g, or B returns to h, etc., then the application enters an undefined state, right, or how is it?
That is, * Gambit in itself does not implement any blocking feature such that while g and h are still on the stack, a return from f to A would block until D returned to h and C returned to G * Gambit does not implement any exception handling for trying to return in the wrong order, but if returning in the wrong order the application simply terminates at some point * Gambit uses one ordinary C stack for all Scheme->C and C->Scheme calling, so it does not allocate a new C stack dynamically on the heap, or alike, for any Scheme->C call.
I experimented a bit with returning C->Scheme calls in the wrong order, and what happened was that at the LAST return I made, the application terminated. I suppose this is consistent with how it should be - the Gambit app may behave just about any way if you returned C->Scheme calls in the wrong order, as this messed up the C stack and the app is about to 'blow' just about any second. (I had A call f which called B which called g which called C which called h which called D, then D returned to g which returned to B which returned to h - and at h's return to Scheme the app terminated)
Also I suppose this is in line with the "19.7 Continuations and the C-interface" manual section and your paper http:/www.iro.umontreal.ca/~feeley/papers/FeeleySW00.pdfhttp://www.iro.umontreal.ca/~feeley/papers/FeeleySW00.pdf , which I suppose Gambit implements.
Looking forward to get clear on this one :-)
Kind regards, Mikael
test_c_stack_rewinding.scm :
(c-define (c-run thunk) (scheme-object) void "c_run" "" (print "c-run entered for " thunk ".\n") (thunk) (print "c-run returned for " thunk ".\n"))
(define run-through-c (c-lambda (scheme-object) void "c_run(___arg1);"))
(define (thread-go id sleep-seconds) (thread-start! (make-thread (lambda () (print "thread " id " entered.\n") (run-through-c (lambda () (print "thread " id "'s c thunk entered.\n") (thread-sleep! sleep-seconds) (print "thread " id "'s c thunk returning.\n"))) (print "thread " id " returned.\n")))))
REPL interaction: $ gsc Gambit v4.5.3
(compile-file "test_c_stack_rewinding.scm") (load "test_c_stack_rewinding")
;; Test one simultaneous Scheme->C->Scheme call:
(thread-go 1 5)
#<thread #2>
thread 1 entered.
c-run entered for #<procedure #3>. thread 1's c thunk entered. 1 1
thread 1's c thunk returning.
c-run returned for #<procedure #3>. thread 1 returned.
;; Scheme->C->Scheme calls can be made many at a time, as long as the last one made returns first:
(thread-go 3 10) (thread-sleep! 1) (thread-go 4 5)
#<thread #8>
thread 3 entered.
c-run entered for #<procedure #9>. thread 3's c thunk entered.
#<thread #10> thread 4 entered.
c-run entered for #<procedure #11>. thread 4's c thunk entered. thread 4's c thunk returning. c-run returned for #<procedure #11>. thread 4 returned.
thread 3's c thunk returning. c-run returned for #<procedure #9>. thread 3 returned.
(thread-go 8 15) (thread-sleep! 1) (thread-go 9 10) (thread-sleep! 1)
(thread-go 10 5) #<thread #2>
thread 8 entered.
c-run entered for #<procedure #3>. thread 8's c thunk entered.
#<thread #4> thread 9 entered.
c-run entered for #<procedure #5>. thread 9's c thunk entered.
#<thread #6> thread 10 entered.
c-run entered for #<procedure #7>. thread 10's c thunk entered. thread 10's c thunk returning. c-run returned for #<procedure #7>. thread 10 returned. thread 9's c thunk returning. c-run returned for #<procedure #5>. thread 9 returned. thread 8's c thunk returning. c-run returned for #<procedure #3>. thread 8 returned.
;; If C->Scheme calls return in another order then the app terminates
(thread-go 5 5) (thread-sleep! 1) (thread-go 6 10)
#<thread #12>
thread 5 entered.
c-run entered for #<procedure #13>. thread 5's c thunk entered.
#<thread #14>
thread 6 entered. c-run entered for #<procedure #15>. thread 6's c thunk entered. 1 1
thread 5's c thunk returning.
c-run returned for #<procedure #13>. thread 5 returned.
0 0
thread 6's c thunk returning.
c-run returned for #<procedure #15>. $
(thread-go 1 6) (thread-sleep! 1) (thread-go 2 12) (thread-sleep! 1)
(thread-go 3 9) (thread-sleep! 1) (thread-go 4 5) #<thread #2>
thread 1 entered.
c-run entered for #<procedure #3>. thread 1's c thunk entered.
#<thread #4> thread 2 entered.
c-run entered for #<procedure #5>. thread 2's c thunk entered.
#<thread #6> thread 3 entered.
c-run entered for #<procedure #7>. thread 3's c thunk entered.
#<thread #8> thread 4 entered.
c-run entered for #<procedure #9>. thread 4's c thunk entered. thread 1's c thunk returning. c-run returned for #<procedure #3>. thread 1 returned. thread 4's c thunk returning. c-run returned for #<procedure #9>. $