home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 199.lha / GimmeLib / subtask.c < prev    next >
C/C++ Source or Header  |  1988-12-27  |  8KB  |  303 lines

  1. /*
  2.  *  FILE: subtask.c
  3.  *  Support routines for spawning subtasks (not processes).
  4.  *  This means the subtask shares the same memory space as its parent task.
  5.  *
  6.  *  Note: this "library" is re-entrant, so any task can spawn and keep track
  7.  *  of its own subtasks independantly of other users of this "library".
  8.  *
  9.  *  Public Domain, but keep my name in it as the original author.
  10.  *  31-Aug-88    Jan Sven Trabandt   first release version
  11.  *  31-Oct-88    Jan Sven Trabandt   (de)initialize routines moved to subtinit.c
  12.  *                      so that minimal routines need to be
  13.  *                      linked in when using stdstuff.c
  14.  *                    renamed getRidOfSubTask to killSubTask
  15.  */
  16.  
  17.  
  18. #define I_AM_SUBTASK
  19. #include "gimmelib/gimmefuncs.h"
  20.  
  21.  
  22. #define MIN_STACK   100L
  23.  
  24. #define MIN_COUNT   2
  25. #define MAX_EXTRA   2
  26.  
  27.  
  28. typedef struct {
  29.     struct Message msg;
  30.     ULONG flags;
  31.     APTR  ptr;
  32. } DONEMSG;
  33.  
  34. #define DONEFLAG    ((1L << 31) + 1857329L)
  35.  
  36.  
  37. /* internal use only!!
  38.  *
  39.  * NAME:    a4get, a4put
  40.  *
  41.  * SYNOPSIS:    a4value = a4get();
  42.  *        a4put( a4value );
  43.  *        LONG a4value;
  44.  *
  45.  * DESCRIPTION: Get or put a value into register A4.    MANX specific!!!!
  46.  *        These two functions are support routines for task creation.
  47.  *        BECAUSE A4 GETS CLEARED IN THE SUBTASK
  48.  *        and Manx needs it as a base pointer in small-code model.
  49.  *        Manx's geta4() won't work if its code is too far away,
  50.  *        so this ensures a4 is set up.
  51.  *        I'm not sure if this is only in small code and/or small data.
  52.  *
  53.  
  54. static LONG a4get();
  55. static VOID a4put();
  56.  
  57. #asm
  58.     cseg
  59. _a4get:
  60.     move.l    a4,d0
  61.     rts
  62.  
  63. _a4put:
  64.     move.l    4(a7),a4
  65.     rts
  66. #endasm
  67.  
  68.  
  69. struct Task *gimmeSubTask( countptr, portptr, stack_size, data_size,
  70.                 myportptr )
  71.     SHORT        *countptr;
  72.     struct MsgPort  **portptr;
  73.     LONG        stack_size, data_size;
  74.     struct MsgPort  **myportptr;
  75. {
  76.     struct Task     *task;
  77.     DONEMSG        *msg = NULL;
  78.     struct MemList  *mymemlist;
  79.     struct myneeds {
  80.     struct MemList mn_head;         /* 1 MemEntry in the head */
  81.     struct MemEntry mn_body[MIN_COUNT+MAX_EXTRA-1];
  82.     } myneeds;
  83.     UWORD        count = 0;
  84.  
  85.     myneeds.mn_head.ml_Node.ln_Type = NT_MEMORY;
  86.     myneeds.mn_head.ml_Node.ln_Pri  = 0;
  87.     myneeds.mn_head.ml_Node.ln_Name = NULL;
  88.  
  89.     if( data_size > 0L ) {
  90.     myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
  91.     myneeds.mn_head.ml_me[count].me_Length = data_size;
  92.     ++count;
  93.     }
  94.     if( myportptr && portptr ) {
  95.     myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
  96.     myneeds.mn_head.ml_me[count].me_Length = (LONG) sizeof(DONEMSG);
  97.     ++count;
  98.     }
  99.  
  100.     /* leave stack and struct Task as last two memory blocks */
  101.  
  102.     if( stack_size < MIN_STACK ) {
  103.     stack_size = MIN_STACK;
  104.     }
  105.     myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC;
  106.     myneeds.mn_head.ml_me[count].me_Length = stack_size;
  107.     ++count;
  108.     myneeds.mn_head.ml_me[count].me_Reqs = MEMF_PUBLIC | MEMF_CLEAR;
  109.     myneeds.mn_head.ml_me[count].me_Length = (LONG) sizeof(struct Task);
  110.     ++count;
  111.  
  112.     myneeds.mn_head.ml_NumEntries = count;
  113.     mymemlist = (struct MemList *) AllocEntry( &myneeds );
  114.     if( (ULONG)(mymemlist) & (1L<<31) ) {
  115.     return( NULL );
  116.     }
  117.  
  118.     --count;
  119.     task = (struct Task *) mymemlist->ml_me[count].me_Addr;
  120.     NewList( &task->tc_MemEntry );
  121.     AddTail( &task->tc_MemEntry, mymemlist );
  122.  
  123.     --count;
  124.     task->tc_SPLower = mymemlist->ml_me[count].me_Addr;     /* stack */
  125.     task->tc_SPUpper = (APTR) (stack_size + (ULONG) task->tc_SPLower);
  126.     task->tc_SPReg = task->tc_SPUpper;
  127.     task->tc_Node.ln_Type = NT_TASK;
  128.  
  129.     if( myportptr && portptr ) {
  130.     --count;
  131.     msg = (DONEMSG *) mymemlist->ml_me[count].me_Addr;
  132.     msg->msg.mn_Length = mymemlist->ml_me[count].me_Length;
  133.     msg->msg.mn_Node.ln_Type = NT_MESSAGE;
  134.     msg->ptr = (APTR) *portptr;     /* save subtask monitoring port */
  135.     msg->flags = DONEFLAG;
  136.     } /* endif */
  137.     pushTaskStack( task, msg );
  138.  
  139.     if( data_size > 0L ) {
  140.     --count;
  141.     task->tc_UserData = mymemlist->ml_me[count].me_Addr;
  142.     }
  143.     pushTaskStack( task, task->tc_UserData );
  144.     pushTaskStack( task, myportptr );
  145.     pushTaskStack( task, countptr );
  146.  
  147.     return( task );
  148. } /* gimmeSubTask */
  149.  
  150.  
  151. /* internal use only!!
  152.  *
  153.  * pushTaskStack : push a long value onto the subtask's stack
  154.  * task struct and stack must already be initialized,
  155.  * task must not have been started yet.
  156. static pushTaskStack( task, val )
  157.     struct Task *task;
  158.     LONG    val;
  159. {
  160.     --((LONG *)task->tc_SPReg);
  161.     *((LONG *)task->tc_SPReg) = val;
  162. } /* pushTaskStack */
  163.  
  164.  
  165. /* internal use only!!
  166.  *
  167.  * popTaskStack : pop a long value off the subtask's stack
  168.  * task struct and stack must already be initialized,
  169.  * task must not have been started yet.
  170. static LONG popTaskStack( task )
  171.     struct Task *task;
  172. {
  173.     return( *((LONG *)task->tc_SPReg)++ );
  174. } /* popTaskStack */
  175.  
  176.  
  177. VOID undoGimmeSubTask( task )
  178.     struct Task *task;
  179. {
  180.     if( task ) {
  181.     FreeEntry( task->tc_MemEntry.lh_Head );
  182.     }
  183. } /* undoGimmeSubTask */
  184.  
  185.  
  186. VOID killSubTask( countptr, portptr, task )
  187.     SHORT        *countptr;
  188.     struct MsgPort  **portptr;
  189.     struct Task     *task;
  190. {
  191.     struct MsgPort  *myport;
  192.  
  193.     if( portptr && (myport = *portptr) ) {
  194.     *portptr = NULL;
  195.     DeletePort( myport );
  196.     }
  197.     /*    It is permissible to do a Forbid() and RemTask(NULL) [kill myself]
  198.      *    even though the following Permit() statement would not get executed
  199.      *    since the OS will take care of things just fine.
  200.     */
  201.     Forbid();
  202.     if( countptr ) {
  203.     --(*countptr);
  204.     }
  205.     RemTask( task );
  206.     Permit();
  207. } /* killSubTask */
  208.  
  209.  
  210. /*  internal use only!!
  211.  *
  212.  *  getRidOfMyself
  213.  *  what's actually on the stack:
  214.  *    func    a4    countptr   myport   data    msg  -> see bridgeSubTask
  215.  *  what getRidOfMyself thinks is there:
  216.  *    ret-addr dum    [countptr] [myport] [data]  [msg]
  217.  *  note it doesn't actually know about data, msg and port.
  218.  *  thus countptr is 1 long past dum, etc.
  219. static VOID getRidOfMyself( dum )
  220.     LONG    dum;
  221. {
  222.     LONG        *parm;
  223.     DONEMSG        *msg;
  224.     struct MsgPort  *mp, *myport;
  225.  
  226.     parm = &dum;
  227.     msg = (DONEMSG *) *(parm + 4);
  228.     if( msg && (myport = (struct MsgPort *) *(parm + 2)) ) {
  229.     mp = (struct MsgPort *) msg->ptr;
  230.     msg->ptr = (APTR) FindTask( NULL );
  231.     msg->msg.mn_ReplyPort = myport;
  232.     PutMsg( mp, msg );
  233.     for( ;; ) {
  234.         WaitPort( myport );
  235.         while ( msg = (DONEMSG *) GetMsg(myport) ) {
  236.         if( msg->msg.mn_Node.ln_Type != NT_REPLYMSG ) {
  237.             ReplyMsg( msg );
  238.         } else if( msg->flags == DONEFLAG ) {
  239.             goto gromyself_done;
  240.         }
  241.         } /* while */
  242.     } /* for */
  243.     }
  244. gromyself_done:
  245.     killSubTask( *(parm + 1), parm + 2, NULL );
  246. } /* getRidOfMyself */
  247.  
  248.  
  249. /*  internal use only!!
  250.  *
  251.  *  bridgeSubTask
  252.  *  Used as the actual initialPC for the subtask, it gets a message port
  253.  *  if necessary and calls the real subtask routine.
  254.  *  Also increments the subtask counter!!!!
  255.  *  Also changes portptr on the stack to port (ie a pointer to a port, not
  256.  *  a pointer to a pointer) so things are kosher for getRidOfMyself.
  257.  *  startSubTask does the set-up so that the new subtask starts executing
  258.  *  with this routine.
  259. static VOID bridgeSubTask( func, a4, countptr, myportptr, data, msg )
  260.     long        (*func)();
  261.     LONG        a4;
  262.     SHORT        *countptr;
  263.     struct MsgPort  **myportptr;
  264.     APTR        data;
  265.     DONEMSG        *msg;
  266. {
  267.     a4put( a4 );
  268.     if( countptr ) {
  269.     Forbid();
  270.     ++(*countptr);
  271.     Permit();
  272.     }
  273.     if( myportptr ) {
  274.     *myportptr = CreatePort( NULL, 0L );
  275.     if( !*myportptr ) {
  276.         return;
  277.     }
  278.     *((struct MsgPort **)&myportptr) = *myportptr;
  279.     }
  280.     func( data );
  281. } /* bridgeSubTask */
  282.  
  283.  
  284. short startSubTask( task, name, pri, initialpc, finalpc )
  285.     struct Task *task;
  286.     char    *name;
  287.     BYTE    pri;
  288.     void    (*initialpc)(), (*finalpc)();
  289. {
  290.     if( !task || !initialpc ) {
  291.     return( -1 );
  292.     }
  293.     task->tc_Node.ln_Name = name;
  294.     task->tc_Node.ln_Pri  = pri;
  295.     pushTaskStack( task, a4get() );
  296.     pushTaskStack( task, initialpc );
  297.     if( !finalpc ) {
  298.     (APTR) finalpc = (APTR) getRidOfMyself;
  299.     }
  300.     AddTask( task, bridgeSubTask, finalpc );
  301.     return( 0 );
  302. } /* startSubTask */
  303.