Hi Dmitris,<div><br></div><div>Indeed it is a kind of limitation, though limitation is an aspect of the nature of any technology solution.</div><div><br></div><div><div>Find below some reflections about the design area your example code regards and a suggestion for best practice.</div>



<div><br></div><div><br></div><div><br></div><div>I checked your code closer now; basically the c-lambda is a part of the application logics that could as well have been implemented in Scheme.</div><div><br></div><div>Whenever you can implement application logics in Scheme, do it, because the C stack model is as you have found out limited to "direct style" i.e. each step up must be balanced with one step down and there are *no* shortcuts. This is the C stack, and how it's delivered to you in the FFI.</div>



<div><br></div><div>Of course it follows that if you attempt to do maneuvers on the C stack that are not possible from Scheme, something breaks.</div><div><br></div><div>Using extraordinarily fancy stack manipulation techniques, this could be worked around, though that would not be based on completely standard features found in any computing environment and thus not end up as crossplatform as Gambit is today, and, it'd take a bit of performance.</div>



<div><br></div><div>When Gambit gets SMP support in some months from now, you'll have one C stack per OS thread you launched, so you could do a bit more of this then.</div><div><br></div><div>Now back to the problem -</div>



<div><br></div><div><br></div><div>So your c-lambda is:</div><div><br></div><div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><br></div><div>(define do-read</div><div>  (c-lambda (scheme-object) int</div>



<div>       #<<END-C</div><div>char buf[4096];</div><div>___SCMOBJ ctx = ___EXT(___make_vector)(2, ___FAL, ___STILL);</div><div>___VECTORSET (ctx, ___FIX(0), ___arg1);</div><div><br></div><div>for (;;) {</div><div>


  if (do_read ((void*)ctx, buf, sizeof(buf)) < 0) break;</div>
<div>}</div><div>END-C</div><div>))</div></div></blockquote></div><div><br></div><div>To solve your issue, rewrite it to Scheme i.e.</div><div><br></div><div><blockquote style="margin:0 0 0 40px;border:none;padding:0px">


<div>
<font face="courier new, monospace">(lambda (v)</font></div><div><font face="courier new, monospace">  (let ((buf (make-u8vector 4096))</font></div><div><font face="courier new, monospace">        (ctx (make-still-vector 2 #f)))</font></div>



<div><font face="courier new, monospace">    (vector-set! ctx 0 1)</font></div><div><font face="courier new, monospace">    (let loop ()</font></div><div><font face="courier new, monospace">      (if (< 0 (do-read ctx buf (u8vector-length buf)) (loop)))</font></div>



</blockquote></div><div><br></div><div>Again, what you are wanting to get is an extremely high level functionality, namely using a IO multiplexer, in this case the one of Gambit's scheduler, to return to different places in code in essentially different stacks - this would generally never be done in C, and this remains the case also here.</div>



<div><br></div><div><br></div><div>Generally, never make a Scheme-to-C call with a C-to-Scheme call that may block in any way, except for if such use is done once in parallell within the OS thread. C's stack model does not deliver for other than exactly this. Instead, make your C call return back to Scheme with some kind of status value that instructs your Scheme code how to proceed. Such an approach will always end up being 'good code'.</div>



<div><br></div><div>If you need to pass complex result data back from the C call to Scheme, you can do this as C-to-Scheme calls though then keep the thread system off during those calls as to keep your code safe from the possibility of other code compromising the C stack in relation with the task you're performing and thus crashing your program.</div>

<div><br></div><div>If you would really need multiple C stacks, then, presuming they do C logics only and do not directly invoke any C code beyond your control (such as OS routines), you could use a C cooperate multithreading library to get the functionality you look for. That would be sufficiently crossplatform.</div>

<div><br></div><div><br></div><div>What are you trying to do?</div>

<div><br></div><div>Brgds,</div><div>Mikael</div><div><br><div class="gmail_quote">2013/2/24 Dimitris Vyzovitis <span dir="ltr"><<a href="mailto:vyzo@hackzen.org" target="_blank">vyzo@hackzen.org</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">



Switching threads off is not an option because of I/O.<br>
<br>
So basically you are saying that ffi scheme upcalls (through<br>
c-define'd lambdas) are not thread safe (scheme threads always).<br>
I would expect each thread to maintain its own c stack, but apparently<br>
it is not so and C-stacks cannot be safely interleaved with multiple<br>
threads.<br>
<br>
If this is the case, it is a pretty serious limitation in the ffi.<br>
<br>
PS: wiki seems down again<br>
<div><div><br>
On Sat, Feb 23, 2013 at 1:14 AM, Mikael <<a href="mailto:mikael.rcv@gmail.com" target="_blank">mikael.rcv@gmail.com</a>> wrote:<br>
> Dimitris,<br>
><br>
> (From only looking very generally at your code,)<br>
><br>
> May this be a stack unwinding problem?<br>
><br>
> If you unwind a stack other than in the same order it was wound in the first<br>
> place, your Gambit process will terminate or at least crash.<br>
><br>
> Example:<br>
><br>
> You have a lambda A that invokes C-lambda B that invokes lambda C.<br>
><br>
> Also, a lambda D that invokes C-lambda E that invokes lambda F.<br>
><br>
> If you invoke A and A invokes B and B invokes C,<br>
><br>
> and then say, Gambit switches thread, and that Gambit thread invokes D which<br>
> invokes E which invokes F,<br>
><br>
> and then, say, Gambit switches thread again, and that Gambit thread returns<br>
> from C to B.<br>
><br>
> Then your Gambit process is toast.<br>
><br>
> To handle this you can switch off Gambit's threading system when you're in B<br>
> or E for the course of your C and F calls respectively. Note that switching<br>
> off Gambit's threading system means that some or several of Gambit's<br>
> built-in IO primitives would block forever.<br>
><br>
> See the "How to work with external libraries" Wiki page for how to switch it<br>
> off.<br>
><br>
> Was this of help?<br>
><br>
> Mikael<br>
><br>
> 2013/2/23 Dimitris Vyzovitis <<a href="mailto:vyzo@hackzen.org" target="_blank">vyzo@hackzen.org</a>><br>
>><br>
>> I am running into an abrupt exit with error code 71 (OSError) when<br>
>> multiple (scheme) threads are making ffi calls that upcall to scheme.<br>
>><br>
>> A simplified scenario (see attached file) is as follows:<br>
>> 2 or more threads make an ffi call.<br>
>> The ffi call is a longer running procedure, that makes upcalls into<br>
>> scheme procedures that do I/O.<br>
>> This results in the program exiting abruptly with error code 71, and<br>
>> no context information regarding the error (even when compiled and<br>
>> running with full debugging).<br>
>><br>
>> For an illustration of the problem, see the attached file.<br>
>><br>
>> The following should print dots indefinitely, but instead quickly<br>
>> terminates with 71.<br>
>><br>
>> $ gsc exit71.scm<br>
>> $  gsi -e "(begin (load \"exit71\") (main))"<br>
>> ....<plenty of dots>.... $ echo $?<br>
>> 71<br>
>><br>
>> This is with gambit-4.6.6, system is GNU/Linux x86-64.<br>
>><br>
>> -- vyzo<br>
>><br>
>> _______________________________________________<br>
>> Gambit-list mailing list<br>
>> <a href="mailto:Gambit-list@iro.umontreal.ca" target="_blank">Gambit-list@iro.umontreal.ca</a><br>
>> <a href="https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list" target="_blank">https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list</a><br>
>><br>
><br>
</div></div></blockquote></div><br></div></div>