
/*
 *  This routine test the light-weight process system.
 *
 *  This ought to work compiled with 16 or 32 bit ints
 *
 *  Note:
 *	The link register, A5, MUST be setup C-Style if you are using LWPs
 *	from assembly.	The LWP procedure should NOT modify ANY registers
 *	A2-A6/D2-D7 before calling ForkLWP() BECAUSE ForkLWP() will use
 *	A5 to skip the procedure's normal return function and do a double
 *	return to its parent.
 *
 *	Aztec does this.  I am sure Lattice does this too.  The only
 *	allowed register for the data base pointer is A4.
 *
 *  Operation: Initializing a LWP.  Read the LWP docs. Essentially, you
 *  create a subroutine which is to be the LWP:
 *
 *  long
 *  xx(arg, arg ...) {
 *	<local variable declarations>
 *	ForkLWP(stacksize, argsize)
 *
 *  }
 *
 *  And then call xx().  Calling xx() 'forks' off an LWP.  xx() will call
 *  which returns directly to main() (i.e. the caller of xx()) after copying
 *  xx()'s local variables and arguments to a new stack which is large
 *  enough to hold them.  This new stack will be allocated.  Additional
 *  space may be specified by specifying a stacksize in ForkLWP().  If the
 *  subroutine makes no calls, 0 may be specified (unless the compiler
 *  uses the stack for temporaries).  The 'argsize' is the number of bytes
 *  taken up by arguments to xx(), which ForkLWP() cannot figure out on
 *  its own.
 *
 *  So, ForkLWP() copies the stack areas and sets up a run context for the
 *  subroutine.  When light weight processing is begun by a RunLWP() command,
 *  the initial context is just after a 'return' from ForkLWP() so the rest
 *  of the subroutine is run under the new stack as a light weight process.
 *
 */

#include <exec/types.h>

extern APTR ThisLWP;
extern APTR ForkLWP();

#define INTSIZE sizeof(int)

main()
{
    int x = 43;

    puts("testing run ability");
    xx("abc4", 4);
    xx("def8", 8);
    xx("ghi6", 6);
    RunLWP();
    puts("successful run test");
    puts("");
    puts("now testing waiting ability");
    master(4);
    RunLWP();
    puts("Successfull signal test");
    puts("");
    puts("Now testing inter-subroutine stack-resize");
    TestForkLWP("Awesome");
    RunLWP();
    puts("inter-subroutine stack-resize test done");
}

xx(str, n)
char *str;
int n;
{
    short i;

    if (ForkLWP(4096L, (long)(4+INTSIZE))) {
	printf("nonzero return");
	return;
    }
    puts("zero go");
    for (i = 0; i <= n; ++i) {
	printf("%s %d\n", str, i);
	SwitchLWP();
    }
}

master(n)
int n;
{
    char quit = 0;
    short i;
    short j;
    APTR slave();
    APTR slave_lwp;

    if (ForkLWP(4096L, (long)INTSIZE)) {
	puts("non zero return");
	return;
    }
    puts("zero go");
    slave_lwp = slave(ThisLWP, &quit);
    for (i = 0; i < n; ++i) {
	printf("Signal slave %d %08lx\n", i, slave_lwp);
	AlertLWP(slave_lwp);
	WaitLWP();
	puts("slave should not run START");
	for (j = 0; j < 10; ++j)
	    SwitchLWP();        /*  make sure slave doesn't run */
	puts("slave should not run END");
    }
    quit = 1;
    puts("Signal slave, which should now exit");
    AlertLWP(slave_lwp);
    puts("Master waits");
    WaitLWP();
    puts("Master exits");
}

APTR
slave(master_lwp, quit)
APTR master_lwp;
char *quit;
{
    short j;
    APTR lwp;

    if (lwp = ForkLWP(4096L, 8L)) {
	puts("nonzero ret");
	return(lwp);
    }
    puts("zero go");

    for (;;) {
	puts("slave: wait");
	WaitLWP();
	puts("master should not run START");
	for (j = 0; j < 10; ++j)
	    SwitchLWP();        /*  make sure slave doesn't run */
	puts("master should not run END");
	if (*quit)
	    break;
	printf("slave alerts master %08lx\n", master_lwp);
	AlertLWP(master_lwp);
    }
    puts("Slave flagged to quit, slave alerting master and exiting");
    AlertLWP(master_lwp);
}

TestForkLWP(str)
char *str;
{
    long i = 1000000L;
    register long j;	    /*	cannot init. reg vars before ForkLWP()  */

    if (ForkLWP(2048L, 4L)) /*  initial stack big enough for stdio  */
	return;
    j = 0;
    printf("string %s\n", str);
    printf("LWP %08lx local i @ %08lx,  1000000 == %ld\n", ThisLWP, &i, i);
    if (ForkLWP(2048L, 4L)) /*  prove locals are not destroyed      */
	return;
    printf("string %s\n", str);
    printf("LWP %08lx local i @ %08lx,  1000000 == %ld\n", ThisLWP, &i, i);
    puts("long wait...");
    if (ForkLWP(0L, 0L))      /*  passed argument 'str' now invalid   */
	return;

    while (i--)
	++j;

    if (ForkLWP(2048L, 0L)) /* NOTE: 'str' WOULD STILL BE INVALID HERE  */
	return; 	    /* even if you specified '4'                */

    printf("LWP %08lx local i @ %08lx,  -1 == %ld\n", ThisLWP, &i, i);
    printf("j == 1000000: %d\n", j);
}

