home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / forthmacs / htmldocs / !Forthmacs / docs / html / multiarm < prev    next >
Encoding:
Text File  |  1996-02-23  |  15.5 KB  |  321 lines

  1. <!-- Forthmacs Formatter generated HTML output -->
  2. <html>
  3. <head>
  4. <title>Multitasking</title>
  5. </head>
  6. <body>
  7. <h1>Multitasking</h1>
  8. <hr>
  9. <p>
  10. This chapter describes the Risc-OS Forthmacs multitasking scheme which is 
  11. slightly different to the previous implementations.  The multitasking system has 
  12. been included into the kernel, so there is no "tasking.fth" any more (at least 
  13. you don't have to load it any more).  Also all tasks get their memory allocated 
  14. at bootup time, so in multitasking applications you just have to  <code><A href="_smal_AH#7"> start </A></code> 
  15. them.  
  16. <p>
  17. This multitasking system is cooperative, not preemptive.  A task switch occurs 
  18. only when the currently-running task explicitly gives up control not at random 
  19. times.  This works fine so long as each task is courteous and relinquishes 
  20. control every so often.  This does not preclude the use of interrupts; it just 
  21. means that when an interrupt routine finishes executing, the task that resumes 
  22. execution is always the one that was interrupted.  
  23. <p>
  24. A task relinquishes control by executing the word  <code><A href="_smal_BN#295"> pause </A>,</code> 
  25. hence from now on the act of giving up control will be called pausing.  Note 
  26. that some words like  <code><A href="_smal_BS#23a"> key </A>,</code>  <code><A href="_smal_BT#23b"> key? </A></code> 
  27. and  <code><A href="_smal_BS#1da"> emit </A></code> already call  <code><A href="_smal_BN#295"> pause </A>.</code> 
  28. <p>
  29. <p>
  30. Tasks are kept in a circular queue and are scheduled in a round-robin fashion.  
  31. When the current task pauses, the next task in the queue is given a chance to 
  32. run until it pauses, and so on.  You may of course write your own task priority 
  33. managing software.  This could be done by an interrupt driven queue-sorting or 
  34. by a  <code><A href="_smal_AK#a"> sleep </A></code>  <code><A href="_smal_AL#b"> wake </A></code> 
  35. supervisor or whatever mechanism you like.  
  36. <p>
  37. Tasks may be currently in one of three (formerly two) states: "awake", "waiting" 
  38. or "asleep".  If a task is awake, it will be given control when its turn in the 
  39. round-robin queue comes along.  
  40. <p>
  41. If a task is asleep, it will remain in the queue but will be skipped over.  
  42. <p>
  43. If it is waiting, it will be given control after a given time has elapsed.  
  44. <p>
  45. It is reasonable to let sleeping or waiting processes remain in the queue, 
  46. because skipping over them is very cheap; it takes only 4 ARM machine 
  47. instructions to skip over a sleeping task (waiting takes a little longer).  
  48. <p>
  49. All tasks share the same global address space and can execute the same code if 
  50. necessary.  Each task has its own private data stack, return stack, floating 
  51. stack and user area.  The user area is where the task-specific  <code><A href="_smal_BK#322"> user </A></code> 
  52. variables are stored.  The CPU state that defines a task is the contents of the 
  53. Data Stack Pointer  <code><A href="_smal_BB#19"> sp </A>,</code> the Return 
  54. Stack Pointer  <code><A href="_smal_BF#1d"> rp </A>,</code> the Floating Stack 
  55. Pointer  <code><A href="_smal_BC#1a"> fsp </A>,</code> the User Pointer  <code><A href="_smal_BD#31b"> up </A></code> 
  56. and the Instruction Pointer  <code><A href="_smal_BE#1c"> ip </A>.</code> 
  57. <p>
  58. The dictionary, which contains executable Forth code, is global and is shared by 
  59. all tasks.  Any  <code><A href="_smal_BN#325"> variable </A>s</code> or other 
  60. data areas within the dictionary, such as those allocated by  <code><A href="_smal_BT#14b"> allot </A>,</code> 
  61. are global and may be accessed by all tasks.  This allows tasks to communicate 
  62. using shared memory.  
  63. <p>
  64. In the initial state of the Forth system, there is only one task, called  <code><A href="_smal_BN#265"> main-task </A>.</code> 
  65. This is the task that is executing the Forth text interpreter.  Other tasks may 
  66. be subsequently created.  
  67. <p>
  68. There are several steps involved in making a new task: 
  69. <p>
  70. <p>
  71. <h2>Naming the task.</h2>
  72. <p>
  73. A task is initially created with either  <code><A href="_smal_AA#0"> "task: </A></code> 
  74. or  <code><A href="_smal_AB#1"> task: </A>.</code> The difference between the 
  75. two is that  <code><A href="_smal_AA#0"> "task: </A></code> takes the name of 
  76. the new task and the <strong>task-size</strong> from the stack, whereas  <code><A href="_smal_AB#1"> task: </A></code> 
  77. takes the name from the input stream and uses  <code><A href="_smal_AC#2"> default-task-size </A>.</code> 
  78. See the glossary for precise definitions.  
  79. <p>
  80. The new task gets it's private memory allocated in the heap, the  <code><A href="_smal_BN#265"> main-task </A>s</code> 
  81. user area will be copied to the new task's and the new task will be set to 
  82. sleeping state.  (This was formerly done by "fork"ing the task.) 
  83. <p>
  84. <strong>Note:</strong> there are now some differences to remember:  <code><A href="_smal_BK#322"> user </A></code> 
  85. variables will be copied (and so are the definitions of deferred words) when 
  86. defining the task or at bootup time, always the  <code><A href="_smal_BN#265"> main-task </A>s</code> 
  87. user area is copied.  
  88. <p>
  89. <p>
  90. <h2>Setting the program that the task is to execute.</h2>
  91. <p>
  92. The task must be told what to do.  This is done by setting the task's 
  93. Interpreter Pointer  <code><A href="_smal_BE#1c"> ip </A></code> to the address 
  94. of an appropriate bit of Forth code.  The Interpreter Pointer in Forth plays a 
  95. role in Forth that is analogous to the role that the Program Counter plays in a 
  96. machine language program.  The word that sets the Interpreter Pointer is  <code><A href="_smal_AH#7"> start </A>.</code> 
  97. For an already active task,  <code><A href="_smal_AH#7"> start </A></code> may 
  98. also be used to make the task start over or even do something entirely 
  99. different.  
  100. <p>
  101. <p>
  102. <h2>Awakening the task.</h2>
  103. <p>
  104. Now the task may be actually set to work.  Waking the task, by using the word  <code><A href="_smal_AL#b"> wake </A>,</code> 
  105. causes the task to be executed when its turn in the queue comes, instead of 
  106. being skipped.  Once awakened, a task will continue running until it pauses.  If 
  107. a task pauses, it will continue to execute each time that its turn in the queue 
  108. comes around.  If a task does not want to run any more, it may put itself to 
  109. sleep so that it will be skipped.  Tasks may also control each other, so that 
  110. one task may put another to sleep.  
  111. <p>
  112. <p>
  113. <h2>Waiting ...</h2>
  114. <p>
  115. A waiting task behaves very much like a sleeping one, it will be skipped for a 
  116. specified time.  After this time has elapsed it is awake.  
  117. <p>
  118. <p>
  119. <h2>Glossary</h2>
  120. <p>
  121.  
  122. <hr><h3><A name="0">"task:</A> ( size name --  )</h3>
  123. <br>
  124. A defining word used to create a new task.  Name is the address of a packed 
  125. string which is entered into the dictionary as the name of the new task.  Size 
  126. is the number of bytes to allocate for the task's private data areas.  Size must 
  127. be large enough to include space for a data stack, a return stack, and a user 
  128. area.   <code><A href="_smal_AC#2"> default-task-size </A></code> is a good 
  129. choice.  
  130. <p>
  131. When name is subsequently executed, the address of the new task's data area is 
  132. left on the stack.  This data area lies within the Risc-OS Forthmacs heap, it is 
  133. allocated immediately when  <code><A href="_smal_AA#0"> "task: </A></code> is 
  134. executed and when booting Risc-OS Forthmacs.  
  135.  
  136. <hr><h3><A name="1">task:</A> ( --  )</h3> <kbd>name</kbd> 
  137. <br>
  138. A defining word executed in the form: 
  139. <br><code>                 TASK: <name></code><br>
  140. Creates a dictionary entry for name which is a new task.  The size of the 
  141. private data storage area for that task is  <code><A href="_smal_AC#2"> default-task-size </A>.</code> 
  142. <p>
  143. Tasks thus created behave exactly like those created by  <code><A href="_smal_AA#0"> "task: </A></code> 
  144.  
  145. See:  <code><A href="_smal_AA#0"> "task: </A></code> 
  146.  
  147. <hr><h3><A name="2">default-task-size</A> ( -- size )</h3>
  148. <br>
  149. Size is an appropriate number to use for the size of a new task's private data 
  150. areas.  Currently it is (hex) 1800, which gives (hex) 1000 bytes for User Area, 
  151. and (hex) 200 bytes each for the Return Stack and the Data Stack plus an extra 
  152. $400.  If a task is created with a size other than  <code><A href="_smal_AC#2"> default-task-size </A>,</code> 
  153. the difference will be reflected in the size of the Data Stack.  
  154.  
  155. <hr><h3><A name="3">task-ps-size</A> ( -- u )</h3>
  156. <br>
  157. u is the number of bytes that will be allocated for the Parameter Stack from the 
  158. private data area for a task.  Currently it is (hex) 200.  
  159.  
  160. <hr><h3><A name="4">task-rs-size</A> ( -- u )</h3>
  161. <br>
  162. u is the number of bytes that will be allocated for the Return Stack from the 
  163. private data area for a task.  Currently it is (hex) 200.  
  164.  
  165. <hr><h3><A name="5">user-size</A> ( -- u )</h3>
  166. <br>
  167. u is the number of bytes that will be allocated for the User Area from the 
  168. private data area for a task.  Currently it is (hex) 1000.  
  169.  
  170. <hr><h3><A name="6">fork</A> ( task-apf --  )</h3>
  171. <br>
  172. obsolete now! 
  173.  
  174. <hr><h3><A name="7">start</A> ( acf task --  )</h3>
  175. <br>
  176. task is the address of the private data area of a task, as left by the <name> 
  177. of a task.  acf is the compilation address of a high-level Forth word that the 
  178. task is to execute.  The data and return stacks of the task are cleared, and the 
  179. task is set so that it will begin execution of that word when it is awakened and 
  180. its turn comes.  
  181. <p>
  182. The word that a task executes should never return.  It should either contain an 
  183. endless loop, or should execute  <code><A href="_smal_AO#e"> stop </A></code> 
  184. when it is done, thus putting itself to sleep.  
  185. <p>
  186.  <code><A href="_smal_AH#7"> start </A></code> should only be executed by one 
  187. task in order to initialise a different task.  A task should not try to  <code><A href="_smal_AH#7"> start </A></code> 
  188. itself (this effect may be had from within a task by explicitly clearing the 
  189. stacks and executing the desired word).  
  190. <p>
  191. A task may  <code><A href="_smal_AH#7"> start </A></code> another at any time.  
  192. STARTing an already-running task will make it immediately stop what it is doing 
  193. and instead execute the new action (acf).  
  194.  
  195. <hr><h3><A name="8">activate</A> ( task --  )</h3>
  196. <br>
  197. Starts "task" with the code that immediately follows this  <code><A href="_smal_AI#8"> activate </A>,</code> 
  198. this is the shortest way to define and run a task.  Example: 
  199. <br><code>    </code><br>
  200. <br><code>    variable demoticker</code><br>
  201. <br><code>    task: democounter</code><br>
  202. <br><code>    : counting   multi democounter activate</code><br>
  203. <br><code>                 multi begin 1 demoticker +!  1000 msec</code><br>
  204. <br><code>                 again ;</code><br>
  205. <br><code>    counting</code><br>
  206.  
  207. <hr><h3><A name="9">set-task</A> ( ip task --  )</h3>
  208. <br>
  209. Similar to  <code><A href="_smal_AH#7"> start </A>,</code> except that instead 
  210. of giving the acf of the word to execute, the actual address of the task's new 
  211. interpreter pointer is given.  This is useful as an implementation word for the 
  212. multitasking system, but it is not recommended for use by user programs.  
  213.  
  214. <hr><h3><A name="a">sleep</A> ( task --  )</h3>
  215. <br>
  216. task is the address of the private data area of a task, as left by the <name> 
  217. of a task.  The task is put to sleep, so that it will be skipped each time that 
  218. its turn in the round robin queue comes up.  This is the appropriate way to 
  219. suspend the activity of another task.  
  220.  
  221. <hr><h3><A name="b">wake</A> ( task --  )</h3>
  222. <br>
  223. task is the address of the private data area of a task, as left by the <name> 
  224. of a task.  The task is awakened, so that it will continue execution when its 
  225. turn in the round robin queue comes up.  
  226.  
  227. <hr><h3><A name="c">wait</A> ( n task --  )</h3>
  228. <br>
  229. task is the address of the private data area of a task, as left by the <name> 
  230. of a task.  The task will be waiting for n msec from now on.  
  231.  
  232. <hr><h3><A name="d">ms</A> ( n --  )</h3>
  233. <br>
  234. The currently executing task puts itself to waiting for n milli-seconds.  This 
  235. is much better than 
  236. <br><code>         begin test-flag</code><br>
  237. <br><code>         while pause</code><br>
  238. <br><code>         repeat</code><br>
  239. because the waiting primitive has been optimized in speed exactly for this 
  240. purpose.  Waiting tasks don't cost any significant time this way.  
  241.  
  242. <hr><h3><A name="e">stop</A> ( --  )</h3>
  243. <br>
  244. The currently executing task puts itself to sleep and relinquishes control.  
  245. This is the way for a task to stop itself when it is finished with its job.  It 
  246. is usually not a good idea to execute  <code><A href="_smal_AO#e"> stop </A></code> 
  247. interactively, since the interactive task will be then go to sleep and will stop 
  248. listening to the keyboard.  
  249.  
  250. <hr><h3><A name="f">(pause</A> ( --  )</h3>
  251. <br>
  252. The multitasking scheduler, installed by  <code><A href="_smal_AS#12"> multi </A></code> 
  253. in  <code><A href="_smal_BN#295"> pause </A>.</code> 
  254.  
  255. See:  <code><A href="_smal_BN#295"> pause </A></code> 
  256.  
  257. <hr><h3><A name="10">pause</A> ( --  )</h3>
  258.  Extra: Deferred
  259. <br>
  260. The currently executing task relinquishes control and the round-robin task queue 
  261. is scanned for the next task that is awake.  When other tasks have been given 
  262. their chance to run, eventually control will be returned to this task, which 
  263. will begin execution immediately following the  <code><A href="_smal_BN#295"> pause </A>.</code> 
  264. <p>
  265. Pause is deferred so that multi-tasking may be disabled by setting  <code><A href="_smal_BN#295"> pause </A></code> 
  266. to execute  <code><A href="_smal_AL#27b"> noop </A>.</code> To enable 
  267. multitasking,  <code><A href="_smal_AP#f"> (pause </A></code> is installed in  <code><A href="_smal_BN#295"> pause </A>.</code> 
  268. <p>
  269.  <code><A href="_smal_AP#f"> (pause </A></code> is itself the multitasking 
  270. scheduler.  It is only 5 ARM instructions long! 
  271.  
  272. <hr><h3><A name="11">single</A> ( --  )</h3>
  273. <br>
  274. Disables multitasking by installing  <code><A href="_smal_AL#27b"> noop </A></code> 
  275. in  <code><A href="_smal_BN#295"> pause </A>.</code> 
  276.  
  277. <hr><h3><A name="12">multi</A> ( --  )</h3>
  278. <br>
  279. Enables multitasking by installing  <code><A href="_smal_AP#f"> (pause </A></code> 
  280. in  <code><A href="_smal_BN#295"> pause </A>.</code> For safety's sake,  <code><A href="_smal_AS#12"> multi </A></code> 
  281. also ensures that the main task is awake.  
  282.  
  283. <hr><h3><A name="13">local</A> ( task user-variable -- adr )</h3>
  284. <br>
  285. task is the address of the private data area of a task, as left by the <name> 
  286. of a task.  user-variable is the address of a user variable in the currently 
  287. executing task's user area.  adr is the address of the other task's copy of that 
  288. user variable.  
  289. <p>
  290.  <code><A href="_smal_AT#13"> local </A></code> allows one task to poke around 
  291. in another task's private data space, to see what is going on there.  
  292.  
  293. <hr><h3><A name="14">up@</A> ( -- adr )</h3>
  294. <br>
  295. adr is the address of the private data area of the currently executing task, 
  296. which happens to be the starting address of its user area.  This allows a task 
  297. to refer to itself without knowing its name.  
  298.  
  299. <hr><h3><A name="15">main-task</A> ( -- task )</h3>
  300. <br>
  301. task is the address of the private data area of the only task that was around in 
  302. the beginning.  Usually this task is executing the Forth interpreter, but it 
  303. doesn't necessarily have to be.  
  304.  
  305. <hr><h3><A name="16">.task</A> ( --  )</h3>
  306. <br>
  307. Gives information about a task identified by the tasks code-field-address.  
  308.  
  309. <hr><h3><A name="17">.tasks</A> ( --  )</h3>
  310. <br>
  311. full information about all installed tasks is displayed.  
  312. <p>
  313. <h2>Implementation Notes</h2>
  314. <p>
  315. Aborting results just in aborting the currently active task, but  <code><A href="_smal_BN#265"> main-task </A></code> 
  316. will be running in any case.  Aborted tasks can be restarted only by  <code><A href="_smal_AH#7"> start </A></code> 
  317. or  <code><A href="_smal_AJ#9"> set-task </A></code> for security reasons.  
  318. <p>
  319. </body>
  320. </html>
  321.