<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 10pt;
font-family:Tahoma
}
--></style>
</head>
<body class='hmmessage'>
Stack must be contiguous on NT.<br>Some platforms -- NT -- actually know how big the current stack is -- and won't let you<br>alloca past it. Best way to let the target handle making stacks is with Posix makecontext,<br>for the many-but-not-all platforms that have it, or CreateFiber on NT.<br>(OpenBSD and I think Darwin/amd64 lack makecontext. It is in Posix, but deprecated;<br>heck Darwin doesn't even have Posix semaphores seemingly..)<br><br>To avoid the assembly you could use a hack like:<br>void* Unsafe__alloca(size_t n) { return alloca(n); }<br><br>Beware.<br>Dangerous platform/compiler-specific stuff here.<br><br> - Jay<br><br>> To: m3devel@elegosoft.com<br>> Date: Wed, 23 Feb 2011 08:42:06 -0800<br>> From: mika@async.caltech.edu<br>> Subject: [M3devel] Avoding thread-stack overflow,   proof of concept of "leapfrog stacks"<br>> <br>> Notes:<br>> <br>> 1. the Modula-3 garbage collector gets confused (shoulda thought of that),<br>>    so I have to turn it off<br>> <br>> 2. however if the GC were fixed, there's no need to "fix up" the stack<br>>    after the return---you can just allocate the new stacks as GC-traced:<br>>    even though the collector is compacting they are "pinned" because<br>>    they are referenced from the thread stack!<br>> <br>> 3. alloca is built into gcc nowadays, so I had to track down an assembly<br>>    version: I suspect that the compiler front-end could be modified to<br>>    emit a call to alloca and thus get gcc to generate the same code, <br>>    obviating the need for any assembly code at all.<br>> <br>> <br>> (* Unsafe interface ***************************************************)<br>> <br>> INTERFACE Unsafe;<br>> FROM Ctypes IMPORT int;<br>> <br>> PROCEDURE DoIt();<br>> <br>> <*EXTERNAL alloca*><br>> PROCEDURE alloca(size : int) : INTEGER;<br>> <br>> END Unsafe.<br>> <br>> (* Unsafe implementation **********************************************)<br>> <br>> UNSAFE MODULE Unsafe;<br>> <br>> IMPORT Thread, IO, Fmt;<br>> IMPORT RTCollector, Random;<br>> <br>> EXCEPTION Quit;<br>> <br>> VAR rand := NEW(Random.Default).init();<br>> <br>> PROCEDURE P(cl : Closure; arg : ARRAY[0..100] OF INTEGER) RAISES { Quit } = <br>>   CONST Fudge = 1024;<br>>   VAR stack : REF ARRAY OF INTEGER := NIL;<br>>   BEGIN <br>>     IO.Put(Fmt.F("Thread %s GetSP()=0x%s\n",<br>>                  Fmt.Int(cl.id),<br>>                  Fmt.Int(GetSP(), base := 16)) <br>>           ); <br>>     (*Thread.Pause(0.1d0);*)<br>> <br>>     IF GetSP() < cl.lo + Fudge THEN<br>>       IF cl.stacks >= rand.integer(3,10) THEN <br>>         IO.Put(Fmt.F("Thread %s quitting after %s stacks\n",<br>>                      Fmt.Int(cl.id), Fmt.Int(cl.stacks)));<br>>         RAISE Quit<br>>       END;<br>> <br>>       stack := NEW(REF ARRAY OF INTEGER, 8*1024);<br>>       WITH lo = LOOPHOLE(ADR(stack[0]),INTEGER),<br>>            hi = LOOPHOLE(ADR(stack[LAST(stack^)]),INTEGER),<br>>            sp = GetSP() DO<br>>         IO.Put(Fmt.F("Thread %s sp %s new stack lo %s hi %s\n",<br>>                      Fmt.Int(cl.id), <br>>                      Fmt.Int(sp, base := 16),<br>>                      Fmt.Int(lo, base := 16), <br>>                      Fmt.Int(hi, base:= 16)));<br>> <br>>         (* new stack starts sp - hi away *)<br>>         EVAL alloca(sp-hi);<br>>         IO.Put(Fmt.F("After alloca, sp %s\n",<br>>                      Fmt.Int(GetSP(),base := 16)));<br>>         cl.lo := lo;<br>>         INC(cl.stacks)<br>>       END<br>>     END;<br>> <br>>     P(cl, arg) <br>>   END P;<br>> <br>> TYPE <br>>   Closure = Thread.Closure OBJECT <br>>     id : CARDINAL;<br>>     lo : INTEGER;<br>>     stacks : CARDINAL;<br>>   OVERRIDES <br>>     apply := Apply <br>>   END;<br>> <br>> PROCEDURE Apply(cl : Closure) : REFANY =<br>>   BEGIN <br>>     Thread.Pause(1.0d0); <br>> <br>>     LOOP<br>>       TRY<br>>         cl.lo := GetSP() - 1024*8; (* pretend we have 8k left *)<br>>         cl.stacks := 0;<br>>         P(cl, ARRAY [0..100] OF INTEGER { 0, .. }); <br>>       EXCEPT<br>>         Quit => (* start over *)<br>>       END<br>>     END<br>>   END Apply;<br>> <br>> PROCEDURE DoIt() =<br>>   BEGIN<br>>     RTCollector.Disable();<br>> <br>>     FOR i := 1 TO 2 DO<br>>       EVAL Thread.Fork(NEW(Closure, id := i)) <br>>     END;<br>>     <br>>     LOOP Thread.Pause(1.0d0) END<br>>   END DoIt;<br>> <br>> PROCEDURE GetSP() : INTEGER = BEGIN RETURN alloca(1) END GetSP;<br>> <br>> BEGIN END Unsafe.<br>> <br>> (* Main can't be UNSAFE in Modula-3 ***********************************)<br>> <br>> MODULE Main;<br>> IMPORT Unsafe;<br>> <br>> BEGIN Unsafe.DoIt() END Main.<br>> <br>> (* alloca.s from FreeBSD (old code from BSD/386) **********************)<br>> <br>> /*-<br>>  * Copyright (c) 1990 The Regents of the University of California.<br>>  * All rights reserved.<br>>  *<br>>  * This code is derived from software contributed to Berkeley by<br>>  * William Jolitz.<br>>  *<br>>  * Redistribution and use in source and binary forms, with or without<br>>  * modification, are permitted provided that the following conditions<br>>  * are met:<br>>  * 1. Redistributions of source code must retain the above copyright<br>>  *    notice, this list of conditions and the following disclaimer.<br>>  * 2. Redistributions in binary form must reproduce the above copyright<br>>  *    notice, this list of conditions and the following disclaimer in the<br>>  *    documentation and/or other materials provided with the distribution.<br>>  * 3. All advertising materials mentioning features or use of this software<br>>  *    must display the following acknowledgement:<br>>  *  This product includes software developed by the University of<br>>  *  California, Berkeley and its contributors.<br>>  * 4. Neither the name of the University nor the names of its contributors<br>>  *    may be used to endorse or promote products derived from this software<br>>  *    without specific prior written permission.<br>>  *<br>>  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND<br>>  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>>  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>>  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE<br>>  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>>  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>>  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>>  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>>  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>>  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>>  * SUCH DAMAGE.<br>>  */<br>> <br>>     .asciz "@(#)alloca.s       5.2 (Berkeley) 5/14/90"<br>> #include <machine/asm.h><br>> <br>> <br>> /* like alloc, but automatic automatic free in return */<br>> <br>> .globl alloca<br>>         .type   alloca, @function<br>> alloca:<br>>   popl    %edx            /*  pop return addr */<br>>    popl    %eax            /*  pop amount to allocate */<br>>     movl    %esp,%ecx<br>>         addl    $3,%eax         /*  round up to next word */<br>>      andl    $0xfffffffc,%eax<br>>  subl    %eax,%esp<br>>         movl    %esp,%eax       /* base of newly allocated space */<br>>       pushl   8(%ecx)         /* copy possible saved registers */<br>>       pushl   4(%ecx)<br>>   pushl   0(%ecx)<br>>   pushl   %eax            /* dummy to pop at callsite */<br>>    jmp     *%edx           /* "return" */<br>> <br>                                         </body>
</html>