transfer.e 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #
  2. ;
  3. ; (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
  4. ; See the copyright notice in the ACK home directory, in the file "Copyright".
  5. ;
  6. ;
  7. ; Module: implementation of coroutines
  8. ; Author: Ceriel J.H. Jacobs
  9. ; Version: $Header$
  10. ;
  11. ; This version works for EM implementations that have a contiguous downwards
  12. ; growing stack, on which data below the stack-pointer is not destroyed.
  13. ;
  14. #include <em_mes.h>
  15. #include <m2_traps.h>
  16. mes 2, EM_WSIZE, EM_PSIZE
  17. ; This file contains the implementation of the following routines from
  18. ; the SYSTEM module:
  19. ; TRANSFER, NEWPROCESS
  20. ; The NEWPROCESS routine creates a new coroutine stack frame.
  21. ; The TRANSFER routine implements transfers from one coroutine to another.
  22. ; The memory organization for coroutines is rather complicated.
  23. ; One problem is caused by the fact that the user must allocate the
  24. ; stackspace. So, this stackspace can be located anywhere, including on
  25. ; the heap. This means that we cannot use this space as a stack, because
  26. ; in EM, the stack-pointer may never point below the heap-pointer.
  27. ; So, this space is only used to save the stack when the coroutine isn't
  28. ; running.
  29. ; It also contains information about the size of the frame, the
  30. ; address of the procedure that forms the coroutine body, the offset
  31. ; of the LB from the start of the frame, and the offset of the SP from
  32. ; the start of the frame.
  33. ; So, is looks like this:
  34. ; |-----------------------------|
  35. ; | |
  36. ; | |
  37. ; | |
  38. ; .
  39. ; .
  40. ; .
  41. ; | |
  42. ; | |
  43. ; | | <--- coroutine ident
  44. ; |-----------------------------|
  45. ; | saved SP |
  46. ; |-----------------------------|
  47. ; | saved LB |
  48. ; |-----------------------------|
  49. ; | procedure address or 0 |
  50. ; |-----------------------------|
  51. ; | size |
  52. ; |-----------------------------|
  53. ;
  54. ; Another problem is that the coroutines must always run at the same
  55. ; place in the stack. Therefore, in the runtime startoff a piece of the
  56. ; stack is allocated for coroutines.
  57. exp $_SYSTEM__NEWPROCESS
  58. exp $_SYSTEM__TRANSFER
  59. inp $ChkSize
  60. pro $_SYSTEM__NEWPROCESS, 0
  61. ; This procedure only initializes the area used for saving the stack.
  62. ; Its definition is:
  63. ; PROCEDURE NEWPROCESS(P:PROC; A:ADDRESS; n:CARDINAL; VAR p1:ADDRESS);
  64. lol 2*EM_PSIZE ; size of frame (n)
  65. cal $ChkSize
  66. asp EM_WSIZE
  67. lfr EM_WSIZE
  68. sil EM_PSIZE ; store size in area (indicated by A)
  69. lal EM_PSIZE
  70. loi EM_PSIZE ; address of area (A)
  71. lal 0
  72. loi EM_PSIZE ; address of coroutine body (P)
  73. lal EM_PSIZE
  74. loi EM_PSIZE
  75. adp EM_WSIZE
  76. sti EM_PSIZE ; store it in area
  77. lal EM_PSIZE
  78. loi EM_PSIZE
  79. adp 3*EM_PSIZE + EM_WSIZE ; this becomes the coroutine identifier
  80. lal 2*EM_PSIZE+EM_WSIZE
  81. loi EM_PSIZE
  82. sti EM_PSIZE
  83. ret 0
  84. end 0
  85. target
  86. bss EM_PSIZE, 0, 0
  87. pro $_SYSTEM__TRANSFER, 0
  88. ; This procedure does all the hard work.
  89. ; It must save the current environment, and restore the one to which the
  90. ; transfer is done. It must also make it look like the return is done
  91. ; from ITS invocation of transfer.
  92. ; Definition is:
  93. ; PROCEDURE TRANSFER(VAR p1, p2 : ADDRESS);
  94. mes ms_gto ; This is a dangerous procedure
  95. lal EM_PSIZE
  96. loi EM_PSIZE
  97. loi EM_PSIZE ; address of target coroutine
  98. dup EM_PSIZE
  99. lae CurrentProcess
  100. loi EM_PSIZE
  101. dup EM_PSIZE
  102. lal 0
  103. loi EM_PSIZE ; address of place where to store address of current coroutine
  104. sti EM_PSIZE ; store
  105. cmp ; compare with current process
  106. zne *1
  107. ; Here, no real transfer needs to be done
  108. asp EM_PSIZE
  109. ret 0 ; just return
  110. 1
  111. lae target
  112. sti EM_PSIZE ; store it in target
  113. ; Now, we save the current stack
  114. ; Use local base from main program
  115. lor 0 ; load LB
  116. lae CurrentProcess
  117. loi EM_PSIZE
  118. adp -2*EM_PSIZE
  119. sti EM_PSIZE ; save it
  120. lor 1 ; load SP
  121. lae CurrentProcess
  122. loi EM_PSIZE
  123. adp -EM_PSIZE
  124. sti EM_PSIZE ; save it
  125. ; Now, we must find a stack we can temporarily use.
  126. ; Just take the one from the main program.
  127. lae MainProcess
  128. loi EM_PSIZE
  129. adp -EM_PSIZE
  130. loi EM_PSIZE
  131. str 1 ; temporary stackpointer
  132. lae MainLB
  133. loi EM_PSIZE
  134. str 0
  135. lae CurrentProcess
  136. loi EM_PSIZE
  137. lae MainProcess
  138. loi EM_PSIZE
  139. cmp
  140. zeq *2
  141. lae StackBase
  142. loi EM_PSIZE
  143. lae CurrentProcess
  144. loi EM_PSIZE
  145. adp -3*EM_PSIZE-EM_WSIZE
  146. loi EM_WSIZE ; get size
  147. ngi EM_WSIZE
  148. ads EM_WSIZE ; gives source address
  149. lae CurrentProcess
  150. loi EM_PSIZE ; destination address
  151. lae CurrentProcess
  152. loi EM_PSIZE
  153. adp -3*EM_PSIZE-EM_WSIZE
  154. loi EM_WSIZE
  155. bls EM_WSIZE ; copy
  156. 2
  157. lae target
  158. loi EM_PSIZE
  159. dup EM_PSIZE
  160. lae CurrentProcess
  161. sti EM_PSIZE ; store target process descriptor in _CurrentProcess
  162. lae MainProcess
  163. loi EM_PSIZE
  164. cmp
  165. zeq *4
  166. ; Now check if the coroutine was called before
  167. lae target
  168. loi EM_PSIZE
  169. adp -3*EM_PSIZE
  170. loi EM_PSIZE
  171. zer EM_PSIZE
  172. cmp
  173. zeq *5
  174. ; No, it was'nt
  175. lae StackBase
  176. loi EM_PSIZE
  177. str 1 ; new stack pointer
  178. lae target
  179. loi EM_PSIZE
  180. adp -3*EM_PSIZE
  181. loi EM_PSIZE
  182. zer EM_PSIZE
  183. lae target
  184. loi EM_PSIZE
  185. adp -3*EM_PSIZE
  186. sti EM_PSIZE
  187. cai
  188. loc 0
  189. cal $exit
  190. ret 0
  191. 5
  192. lae target
  193. loi EM_PSIZE ; push source address
  194. lae StackBase
  195. loi EM_PSIZE ; subtract size from this and we have the destination address
  196. lae target
  197. loi EM_PSIZE
  198. adp -3*EM_PSIZE-EM_WSIZE
  199. loi EM_WSIZE
  200. ngi EM_WSIZE
  201. ads EM_WSIZE ; got it
  202. lae target
  203. loi EM_PSIZE
  204. adp -3*EM_PSIZE-EM_WSIZE
  205. loi EM_WSIZE
  206. bls EM_WSIZE
  207. 4
  208. lae target
  209. loi EM_PSIZE
  210. adp -2*EM_PSIZE
  211. loi EM_PSIZE
  212. str 0 ; restore LB
  213. lae target
  214. loi EM_PSIZE
  215. adp -EM_PSIZE
  216. loi EM_PSIZE
  217. str 1 ; restore SP
  218. ret 0
  219. end 0
  220. pro $ChkSize, 0
  221. lol 0
  222. loc 3*EM_PSIZE+EM_WSIZE
  223. sbi EM_WSIZE
  224. dup EM_WSIZE
  225. stl 0
  226. loe StackSize
  227. cmu EM_WSIZE
  228. zle *1
  229. loc M2_TOOLARGE ; trap number for "stack size too large"
  230. trp
  231. 1
  232. lol 0
  233. loc EM_WSIZE-1
  234. adi EM_WSIZE
  235. loc EM_WSIZE
  236. dvi EM_WSIZE
  237. loc EM_WSIZE
  238. mli EM_WSIZE
  239. ret EM_WSIZE
  240. end 0