home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / suplib.lzh / SUPLIB / DOC / LWP.AUTODOC < prev    next >
Text File  |  1991-08-16  |  14KB  |  357 lines

  1.  
  2.                  LWP.AUTODOC V1.02
  3.                   26 December 1988
  4.  
  5.                LIGHT WEIGHT PROCESSES
  6.  
  7.                    CALL SUMMARY
  8.  
  9.  
  10.  
  11.  
  12.     extern APTR ThisLWP;       Global Variable
  13.  
  14.     This variable is the descriptor for the 'current' LWP running, or
  15.     NULL if accessed from outside the LWP domain (i.e. if accessed
  16.     from main()).
  17.  
  18.     extern long LastLWPMem;        Global Variable
  19.  
  20.     This variable is set by ForkLWP() and holds the number of bytes
  21.     that were allocated for the LWP descriptor + stack.  Used mainly
  22.     for debugging.
  23.  
  24.     extern long CoreLWPStack;        Global Variable
  25.  
  26.     This holds the minimum stack size.  This value is added to the
  27.     stack specified in ForkLWP() as well as the calculated stack
  28.     already used by the subroutine being converted.
  29.  
  30.     This value must be at least 92+8+3 = 103.  The 92 is for EXEC,
  31.     which pushes registers and other things on the user stack when
  32.     in task-switches.  The 8 is so user programs specifying a stack
  33.     size of 0 are still able to make calls in LWP routines, and the 3
  34.     is used for long word alignment.
  35.  
  36.     When using 68881 or other instructions a certain amount of state
  37.     might be pushed onto the user stack when EXEC switches between
  38.     tasks, requiring some programs to increase CoreLWPStack to
  39.     accomodate the extra data.
  40.  
  41. RunLWP()                                                             RunLWP()
  42.  
  43.     ransomelwps = RunLWP();
  44.  
  45.     This routine runs active Light Weight Processes (LWPs) until there are
  46.     no LWPs ready to run.  This end condition occurs either when all are
  47.     waiting for an event via WaitLWP() or when there are no LWPs in the
  48.     system (all have been deleted).
  49.  
  50.     1 is returned if there were indeed some LWPs run, 0 otherwise.  This
  51.     call cannot be made from within an LWP.
  52.  
  53.     This call must be made with at least 512 bytes of stack available.    Since
  54.     the call is normally made from main() or equivalent, this is not
  55.     normally a problem.
  56.  
  57.  
  58.  
  59. ForkLWP()                                                           ForkLWP()
  60.  
  61.     LWPDescriptor = ForkLWP(extrastack, sizeofargs)
  62.  
  63.     APTR LWPDescriptor;
  64.     long extrastack;
  65.     long sizeofargs;
  66.  
  67.     ForkLWP() duplicates the calling subroutine's stack context, allocating
  68.     a new context for the duplicate with 'extrastack' accessable stack.
  69.     ForkLWP() cannot determine the number of bytes that contain the arguments
  70.     passed to the subroutine so this must be specified to (see example below).
  71.     A non-0 LWP descriptor is returned to the 'parent' immediately and the
  72.     child is queued for execution in the LWP system.  When the child gets
  73.     run, it will return a 0 (so you can discern who is who).
  74.  
  75.     ForkLWP() will DUPLICATE the C SUBROUTINE that called it into an LWP
  76.     by allocating an LWP descriptor and stack, and copying the subroutine's
  77.     current stack frame and arguments into the new stack.  The new stack's
  78.     size is sizeofargs+extrastack+N bytes long, where N is the amount
  79.     already taken up by the subroutine (that is, you do not have to take
  80.     into account local variables when specifying your stack size).  In
  81.     otherwords, 'extrastack' is how much stack you want free for calls
  82.     this subroutine might make.  The available stack is actually larger
  83.     than what you specify to take into account what EXEC might push onto
  84.     it when EXEC does a normal amiga context switch.
  85.  
  86.     NOTE:   The C compiler must generate 'link A5,#<whatever>' at the
  87.     beginning of its subroutines as ForkLWP() uses this register to
  88.     determine the calling subroutine's stack context size.  Both Aztec
  89.     and Lattice do this but be careful about specifying optimization
  90.     options.
  91.  
  92.     * When assigning stack size, note that if you use task exceptions all
  93.       LWP stacks will have to be big enough to handle an exception.  Most
  94.       programs do not use task exceptions (though Lattice C appears to
  95.       use them for ^C handling ... it is better to disable ^C and handle
  96.       checking for it yourself).  Either that or use small stacks and
  97.       ensure exception handling is disabled while LWP processes are running.
  98.  
  99.     If called with (0,0), only enough stack for the C subroutine will exist
  100.     and none of the arguments to the C subroutine will be accessable.  That
  101.     is, only the local variables will be accessable and you will not have
  102.     enough stack to make further subroutine calls EXCEPT for LWP calls
  103.     such as ForkLWP(), WaitLWP(), SwitchLWP(), and AlertLWP(), which may
  104.     be called.
  105.  
  106.     The contents of the local variables and arguments as specified by
  107.     arglen will be copied to the new stack and the registers as of the
  108.     call to ForkLWP() will be copied to the new context.  ForkLWP() then
  109.     returns the LWP descriptor (a non-0 longword) to the parent process
  110.     (the subroutine that just called it), and 0 to the child (that same
  111.     subroutine later on when LWPs are running).
  112.  
  113.  
  114.     main()
  115.     {
  116.         xx("hi");    /*  start one LWP   */
  117.         xx("there"); /*  start another   */
  118.         RunLWP();
  119.     }
  120.  
  121.     xx(str)
  122.     char *str;
  123.     {
  124.         /*
  125.          *    2K stack because we use stdio, one argument (str) which is
  126.          *    4 bytes storage on the stack
  127.          */
  128.  
  129.         if (ForkLWP(2048L, 4L)) {
  130.         /* this is the parent thread in the original stack context */
  131.         /* thus we are returning to main() here                    */
  132.         return;
  133.         }
  134.         /*
  135.          * This is the child thread in the new (2K) stack context.
  136.          */
  137.         puts(str);
  138.         /*
  139.          * when this baby returns, it returns to the void (gets deleted)
  140.          */
  141.     }
  142.  
  143.     The LWP is automatically deleted when it returns.  The exact executing
  144.     sequence of the above example is this:
  145.  
  146.     main() calls xx() which calls ForkLWP() which allocates a copy
  147.          of the context, queues the child, then returns a non-zero
  148.          value.
  149.     xx() returns to main via the if.
  150.  
  151.     main() calls xx() with a different argument and the sequence is
  152.     repeated.
  153.  
  154.     main() calls RunLWP() which runs one of the two children (that is,
  155.     either "hi" or "there" will be printed, the order is INDETERMINANT).
  156.     The child exits and gets deleted.  the second child is run and
  157.     the other string is printed.  that child returns and gets
  158.     deleted.  There being no more LWPs ready to run, RunLWP() returns
  159.     to main.
  160.  
  161.     NOTE:    The sizeof integers determines the size of integer arguments
  162.     passed to a subroutine.  That is, if you are using 32 bit ints,
  163.     4 bytes will be passed for an integer even if declared a short.
  164.  
  165.     xx(a,b,c)
  166.     long a;
  167.     short b,c;            N is 4+4+4 = 12 if using 32 bit ints
  168.     {                N is 4+2+2 = 8 if using 16 bit ints
  169.         if (ForkLWP(2048L, (long)N))
  170.         return;
  171.         ...
  172.     }
  173.  
  174.  
  175.      -----------------------------------------------------------
  176.  
  177.                Calling ForkLWP() from an LWP
  178.  
  179.     Operations works much like the UNIX fork() except only the current
  180.     subroutine's stack context is duplicated, and the 'processes' are
  181.     run synchronously (CPU does not get stolen, they give it away).  You
  182.     can use ForkLWP() to dynamically change the available stack for your
  183.     subroutine as well as to fork off a second running process:
  184.  
  185.     xx()
  186.     {
  187.         short i = 0;
  188.         if (ForkLWP(2048L, 0L)) /* need stack to say hello      */
  189.         return;
  190.         puts("hello");
  191.         if (ForkLWP(0L,0L)) {   /* don't need stack for loop    */
  192.         puts("fork returned");
  193.         return;
  194.         }
  195.         while (i < 10)
  196.         ++i;
  197.         if (ForkLWP(4096L, 0L)) /* need stack to say goodbye    */
  198.         return;
  199.         puts("goodbye");
  200.     }
  201.  
  202.     In the above case, the first ForkLWP() sets up a new LWP context and
  203.     returns to main().  When main() finally starts the LWPs running, it
  204.     will have a 2K stack, say hello, and then call ForkLWP() again.
  205.  
  206.     Now the tricky part:  This call to ForkLWP() sets up a new context with
  207.     no extra stack, then returns non-zero to the parent (which is still
  208.     running under the old context).  Thus, we can puts("fork returned");
  209.     because we have enough stack.  But we then return, deleting the parent.
  210.     The child, however, will then run and the procedure will be non the
  211.     wizer... all the local variables will be the same.
  212.  
  213.     But watch out!  The ADDRESSES of all the local variables have now
  214.     changed ... to the new stack, so don't keep around addresses of
  215.     variables (variables which are pointers are ok, just not the address
  216.     of a local variable).  E.G.  If you declare a list:
  217.  
  218.     xx()
  219.     {
  220.         struct List List;
  221.         ...
  222.     }
  223.  
  224.     Which contain pointers to itself (as well as nodes which will contain
  225.     pointers to the list), it becomes invalid to the child of a ForkLWP()
  226.     because the addresses are all wrong.  (that is, the list structure
  227.     itself is ok, but the pointers it setup to itself or nodes which have
  228.     pointers to it are all wrong now).
  229.  
  230.  
  231. SwitchLWP()                                                       SwitchLWP()
  232.  
  233.     SwitchLWP()
  234.  
  235.     This routine gives up CPU to the next ready LWP.  If no other LWPs
  236.     are ready, it is a quick nop.  This does NOT unlink the current LWP
  237.     so it will eventually get CPU back again.
  238.  
  239.     This is useful to give CPU to other LWPs when in a tight loop to
  240.     simulate multitasking.
  241.  
  242.     That is, the LWP system is SYNCHRONOUS and NOT PREEMPTIVE.    This means
  243.     that, if you have enough stack, you may call any LINK LIBRARY FUNCTION
  244.     as if you all were just one process... because in actual fact there IS
  245.     just one process.  I.E. the LWPs can call STDIO functions.
  246.  
  247.     SwitchLWP() returns 1 if there were no other LWPs ready to run, 0
  248.     if other LWPs were run.
  249.  
  250.  
  251. WaitLWP()                                                           WaitLWP()
  252.  
  253.     (void) WaitLWP()
  254.  
  255.     A singular Wait/Alert mechanism is provided.  WaitLWP() unlinks the
  256.     LWP from the ready list (this might cause RunLWP() to return if no
  257.     other LWPs are ready to run) until somebody, either main() or some
  258.     other LWP, alerts it.
  259.  
  260.     If the LWP has already been alerted, this function simply clears
  261.     the alert flag and returns without unlinking (actually, it just
  262.     calls SwitchLWP()).
  263.  
  264. AlertLWP()                                                         AlertLWP()
  265.  
  266.     (void) AlertLWP(LWPDescriptor)
  267.  
  268.     APTR LWPDescriptor;
  269.  
  270.     This may be called from anybody and causes the LWP in question to
  271.     be placed on the ready list (if not already on it), and alerted.
  272.  
  273.     This routine alerts an LWP.  If the LWP is waiting, it is linked back
  274.     into the ready list.  If not (it is already in the read list), a flag
  275.     is set that will cause the next WaitLWP() from that LWP to return
  276.     rather than wait (actually, it calls SwitchLWP()).  No signals are
  277.     ever effected.
  278.  
  279. AutoAlertLWP()                                                 AutoAlertLWP()
  280.  
  281.     (void) AutoAlertLWP(port, LWPDescriptor)
  282.  
  283.     MSGPORT *port;
  284.     APTR LWPDescriptor;
  285.  
  286.     When given a valid LWPDescriptor, this call sets the port mp_Flags to
  287.     3 (undocumented mode) and mp_SigTask to a special function.  This
  288.     causes any messages sent or replied to the port to
  289.     AlertLWP(LWPDescriptor).  Note that only one LWPDescriptor slot exists
  290.     for each of the 32 signal bits, so you cannot AutoAlert() multiple ports
  291.     which have the same signal bit to different LWPDescriptors.  You can
  292.     do just about anything else though.
  293.  
  294.     While installed, operations depends on whether the program is within
  295.     a RunLWP() call or not.  If not, operation is to Signal() the current
  296.     task as of the last AutoAlertLWP() call AND to AutoAlert() the
  297.     descriptor.  If the program IS within a RunLWP(), then operation is
  298.     to just AutoAlert() it... the LWP is guarenteed to run before RunLWP()
  299.     returns.
  300.  
  301.     Note that NO signal is generated in the latter case.  Note that if
  302.     messages exist on the port when AutoAlertLWP() was called, an
  303.     immediate signal+alert or alert will take place.
  304.  
  305.     When given a NULL LWPDescriptor, this call sets the port mp_Flags to
  306.     0 (PA_SIGNAL) and mp_SigTask to the calling task.  Note that if messages
  307.     exist on the port when AutoAlertLWP() is called in this case, an
  308.     immediate signal will occur.
  309.  
  310.  
  311.     This is a synchronous call which may not be called from a foreign
  312.     task or interrupt.
  313.  
  314.  
  315. CallBigStack()                                                 CallBigStack()
  316.  
  317.     (any) CallBigStack(function, bytesofargs, args....)
  318.     (any)(*func)();
  319.     long bytesofargs;
  320.  
  321.     This routine may only be called from an LWP.  This allows one to
  322.     give LWPs very little stack and still allow them to make function or
  323.     library calls which require lots of stack.    Specifically, this
  324.     routine will change the stack pointer back to the stack RunLWP() was
  325.     called with (usually the task's original stack), then make the
  326.     function call specified.
  327.  
  328.     WARNING:    You cannot CallBigStack() a routine which will call any
  329.     other LWP function as LWP functions will also try to use the MasterStack
  330.     thus overwriting the routine's temporary stack.
  331.  
  332.     bytesofargs is the # of bytes of arguments being passed, which must
  333.     be EVEN.  For example:
  334.  
  335.     lwp()
  336.     {
  337.     long Open();
  338.  
  339.     if (ForkLWP(32,0))  /*  enough stack for CallBigStack() call */
  340.         return;
  341.     CallBigStack(Open, 8, "Charlie", 1005);
  342.     }
  343.  
  344.     bytesofargs is 8 here because Open() takes two arguments .. a string
  345.     pointer (4 bytes) and an integer (4 bytes).  Here I am assuming 32 bit
  346.     int compilation.  The LWP need have only enough stack to accomodate
  347.     the arguments to CallBigStack() since they are pushed on its stack.
  348.  
  349.     CallBigStack() proceedes to change the sp, copy the arguments, and
  350.     make the specified call, returning D0.
  351.  
  352.     Warning: 16 bit compilation: The 'bytesofargs' argument is a longword,
  353.     for example, 8L, rather than 8.
  354.  
  355.  
  356.  
  357.