home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 1 / RISC_DISC_1.iso / pd_share / code / desklib / OtherSrc / c / TaskSlice < prev   
Encoding:
Text File  |  1993-04-29  |  5.7 KB  |  141 lines

  1. /*
  2.     ####             #    #     # #
  3.     #   #            #    #       #          The FreeWare C library for 
  4.     #   #  ##   ###  #  # #     # ###             RISC OS machines
  5.     #   # #  # #     # #  #     # #  #   ___________________________________
  6.     #   # ####  ###  ##   #     # #  #                                      
  7.     #   # #        # # #  #     # #  #    Please refer to the accompanying
  8.     ####   ### ####  #  # ##### # ###    documentation for conditions of use
  9.     ________________________________________________________________________
  10.  
  11.     File:    TaskSlice.c
  12.     Author:  Copyright © 1992 Jason Williams
  13.     Version: 1.00 (11 Apr 1992)
  14.     Purpose: Easy and accurate way of allocating time to a "subtask"
  15.  
  16.  *  NOTES:
  17.  *
  18.  *  This is the subtask timeslice "manager" used by DSEdit II. It works
  19.  *  extremely well in practice.
  20.  *
  21.  *  My definition of a "subtask" is a function within a main program that is
  22.  *  run in a multitasking manner so several such functions may be executing
  23.  *  alongside each other (e.g. A sound echo generator operating on a sound
  24.  *  sample can be left to do it's job in the background while the user
  25.  *  selects and edits another portion of the sound sample)
  26.  *  Several echo functions could be applied to several sound samples, in
  27.  *  which case, each time a NULL poll is received by the program, ONE of
  28.  *  subtasks will be called and allowed to execute for a small (5cs)
  29.  *  timeslice.
  30.  *  A subtask CANNOT and DOES NOT EVER call Wimp_Poll{Idle}. It should
  31.  *  never do anything that might page out the CallAfter code!
  32.  *
  33.  *  This code provides a method for running a cooperative subtask for a
  34.  *  timeslice. It is not preemptive, but so long as the subtask is "good"
  35.  *  it will exit very close to the desired time.
  36.  *
  37.  *  It operates along the following lines:
  38.  *  When you start the subtask running, you place some ARM code on the
  39.  *  OS_CallAfter event, where the CallAfter is set to the time that you want
  40.  *  to give to the subtask (e.g. 5 centiseconds)
  41.  *  Simply put, you generate some code that will be called when it's time
  42.  *  for the subtask to stop processing, and the code sets a flag to indicate
  43.  *  to the subtask that it's time is up.
  44.  *
  45.  *  You then call the subtask routine, which should check the passed in
  46.  *  variable reasonably often: when the variable becomes non-zero, it should
  47.  *  stop processing, and return. (It can set the variable inside itself to
  48.  *  force termination if it wishes)
  49.  *
  50.  *  i.e. the code should be something like:
  51.  *    BOOL SubTask(int *endflag)
  52.  *    {
  53.  *      while (!*endflag)
  54.  *      {
  55.  *        ...process...
  56.  *      }
  57.  *      return(error_flag);
  58.  *    }
  59.  *
  60.  *  Your function (and Task_Slice) return a boolean value. This is intended
  61.  *  as a method for errors to be passed back, or as a "task completed" flag.
  62.  *
  63.  *  Anyway, you will need to modify Task_Slice in order to pass in any
  64.  *  information that is necessary to the subtask, so I have included this
  65.  *  routine as SOURCE CODE ONLY. It is not part of the DeskLib Library.
  66.  *  It is basically a working example of how to cleanly timeslice subtasks.
  67.  *
  68.  *  The main-program code is therefore something like:
  69.  *    When we get a NULL event
  70.  *      get the next task to be run
  71.  *      Call Task_Slice();
  72.  *
  73.  *
  74.  *  CallAfter code currently used:
  75.  *    STR R12, [R12]     ; set flag to non-zero value
  76.  *    MOV PC, R14        ; return
  77.  *
  78.  *  Note that this code took a humungous effort on the part of a dedicated
  79.  *  team of 1 people, and took over 20 seconds to develop (including poking
  80.  *  at SWI OS_CallAfter in order to find out how it worked). Just remember
  81.  *  that when you go to use it, sitting back in your easy-chair, and think
  82.  *  how lucky you are that you didn't have to go to all that bother ;-)
  83.  */
  84.  
  85. #include "DeskLib:Core.h"
  86. #include "DeskLib:SWI.h"
  87.  
  88.  
  89. static int CallAfterCode[2] = {0xe58cc000, 0xe1a0f00e};
  90. static int CallAfterFlag    = 0;
  91.  
  92. #define XOS_CallAfter         0x0002003b
  93. #define XOS_RemoveTickerEvent 0x0002003d
  94.  
  95. typedef BOOL (*taskfunction)(int *)
  96.  
  97.  
  98.  
  99. extern BOOL Task_Slice(taskfunction taskfn, int slicetime)
  100. /* Timeslices the given function for "slicetime" centiseconds. It is up to
  101.  * the function itself to check the timeslice termination flag, and therefore
  102.  * the function itself determines how accurately it cooperates with us...
  103.  *
  104.  * Timeslices of less than 1 cs or greater than 100cs (1 second) are not
  105.  * allowed (To multitask nicely, a timeslice should be between 1cs and 20cs)
  106.  * A value of 10cs is recommended, though in some cases you will find other
  107.  * values work better.
  108.  *
  109.  * The interesting thing to note is this:
  110.  * - Under about 5cs slices, the overhead for polling and your task
  111.  *   management tends to soak up a lot of the time, so it is very
  112.  *   inefficient.
  113.  * - Over about 20cs, the overhead for polling is minimal, and very little
  114.  *   advantage can be gained by increasing the timeslice - The processing
  115.  *   operation does not become noticably faster, but the number of polls per
  116.  *   second becomes low enough for normal desktop operation to be disturbed
  117.  *
  118.  * IMPORTANT
  119.  * If your subtask takes LESS time than it's allocated slice, then it is very
  120.  * dangerous to Wimp_Poll, as after your task has been switched out, the
  121.  * CallAfter comes around...
  122.  * Thus, after calling the task function, the event is removed to ensure your
  123.  * computer's continued good health (using RemoveTickerEvent)
  124.  */
  125. {                                   
  126.   BOOL result;
  127.  
  128.   if (slicetime < 1) slicetime = 1;
  129.   if (slicetime > 100) slicetime = 100;
  130.  
  131.   CallAfterFlag = 0;
  132.   SWI(3, 0, XOS_CallAfter, slicetime, &(CallAfterCode[0]), &CallAfterFlag);
  133.  
  134.   result = taskfn(&CallAfterFlag);
  135.  
  136.   if (!CallAfterFlag)
  137.     SWI(2, 0, XOS_RemoveTickerEvent, &(CallAfterCode[0]), &CallAfterFlag);
  138.  
  139.   return(result);
  140. }
  141.