Aros/Developer/Docs/Examples/StackSwap

From Wikibooks, open books for an open world
Jump to navigation Jump to search

The AmigaOS StackSwap function isn't designed to be reliably used from C code. This is why AmigaOS 4 has the NewStackRun function f.e.

Here's a solution that uses CreateNewProc:

#include <exec/exec.h> 
#include <dos/dos.h> 
#include <proto/exec.h> 
#include <proto/dos.h> 
#include <stdio.h>

/* 5 MB stack */ 
#define REQUIRED_STACK_SIZE (5L << 20)

struct StartMessage { 
    struct Message msg; 
    int argc; 
    char **argv; 
    int rc; 
};

void proc_entry (); 
int real_main (int argc, char *argv[]);

int main (int argc, char *argv[]) { 
    struct Process *myproc = (struct Process *)FindTask(NULL); 
    IPTR stacksize = (IPTR)myproc->pr_Task.tc_SPUpper - (IPTR)myproc->pr_Task.tc_SPLower; 
    int rc; 
     
    printf("stack size: %dn", (int)stacksize); 
    if (stacksize >= REQUIRED_STACK_SIZE) { 
        printf("no stack adjustment was needed.n"); 
        rc = real_main(argc, argv); 
    } else { 
        struct StartMessage msg; 
        struct Process *child_proc; 
        struct MsgPort *my_mp; 
        struct MsgPort *child_mp; 
        struct StartMessage *my_msg; 
         
        printf("stack was too small. creating a child process with required stack amount.n"); 
        child_proc = CreateNewProcTags( 
            NP_Entry, proc_entry, 
            NP_StackSize, REQUIRED_STACK_SIZE, 
            TAG_END); 
        if (!child_proc) { 
            printf("failed to create child procn"); 
            return RETURN_FAIL; 
        } 
         
        my_mp = &myproc->pr_MsgPort; 
        child_mp = &child_proc->pr_MsgPort; 
         
        msg.msg.mn_Node.ln_Type = NT_MESSAGE; 
        msg.msg.mn_Length = sizeof(msg); 
        msg.msg.mn_ReplyPort = my_mp; 
        msg.argc = argc; 
        msg.argv = argv; 
         
        PutMsg(child_mp, &msg.msg); 
        while (!(my_msg = (struct StartMessage *)GetMsg(my_mp))) { 
            WaitPort(my_mp); 
        } 
        rc = my_msg->rc; 
    } 
     
    return rc; 
}

void proc_entry () { 
    struct Process *myproc = (struct Process *)FindTask(NULL); 
    IPTR stacksize = (IPTR)myproc->pr_Task.tc_SPUpper - (IPTR)myproc->pr_Task.tc_SPLower; 
    struct MsgPort *my_mp = &myproc->pr_MsgPort; 
    struct StartMessage *my_msg; 
     
    while (!(my_msg = (struct StartMessage *)GetMsg(my_mp))) { 
        WaitPort(my_mp); 
    } 
     
    printf("stack size: %dn", (int)stacksize); 
     
    my_msg->rc = real_main(my_msg->argc, my_msg->argv); 
     
    Forbid(); 
    ReplyMsg(&my_msg->msg); 
}

int real_main (int argc, char *argv[]) { 
    printf("Hello AROS World!n"); 
    return RETURN_OK; 
}