tipg.clu 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. # extend
  2. # include "tidefs.clu"
  3. %
  4. % Pages are fixed-length, mutable collections of objects. The
  5. % number of different page sizes is limited. When you create
  6. % a page, you specify the minimum size that you need. Most
  7. % likely, the page you get will be the smallest size page
  8. % that meets your requirement. The actual page size can
  9. % be determined using the size operation.
  10. %
  11. % There is a single, distinguished page of size 0, called
  12. % NILPAGE. We also guarantee the existence of maximum-size
  13. % pages, of size BLOCKSIZE.
  14. %
  15. % The elements of a page are numbered starting from 0. Pages
  16. % are the lowest-level virtual storage primitive; they not
  17. % visible at the user interface.
  18. %
  19. % We imagine that the page sizes might be the powers of two
  20. % from 2 to 4096. However, this choice is not essential.
  21. %
  22. % This file describes an implementation of pages using a
  23. % two-level memory hierarchy.
  24. %
  25. % A page "object descriptor" is simply a diskpage "object
  26. % descriptor", which contains a secondary storage address.
  27. % For all pages currently in main memory, there is an entry
  28. % in a map that maps the diskpage (secondary storage address)
  29. % to the corresponding mempage (primary memory address).
  30. %
  31. % The bounds checking done by the page cluster is redundant
  32. % and could be eliminated in an actual implementation.
  33. %
  34. page = cluster is NILPAGE, create, destroy, equal, get_size, fetch, store,
  35. print, print_pagemap
  36. rep = oneof [no: null, yes: diskpage]
  37. own pm: pagemap := pagemap$create ()
  38. NILPAGE = proc () returns (cvt)
  39. return (rep$make_no (nil))
  40. end NILPAGE
  41. create = proc (minsize: word, e: any) returns (cvt)
  42. signals (negsize, toobig, full)
  43. if minsize<0 then signal negsize end
  44. if minsize>BLOCKSIZE then signal toobig end
  45. if minsize=0 then return (down (page$NILPAGE ())) end
  46. sizeno: word := findsize (minsize)
  47. d: diskpage := diskpage$allocate (sizeno)
  48. except when full: signal full end
  49. m: mempage := allocate_mem (d)
  50. for i: word in word$from_to (0, d.size - 1) do
  51. m[i] := e
  52. end
  53. return (rep$make_yes (d))
  54. end create
  55. destroy = proc (p: cvt)
  56. tagcase p
  57. tag no:
  58. tag yes (d: diskpage):
  59. free_mem (d)
  60. diskpage$free (d)
  61. end
  62. end destroy
  63. equal = proc (p1, p2: cvt) returns (bool)
  64. return (p1 = p2)
  65. end equal
  66. get_size = proc (p: cvt) returns (word)
  67. tagcase p
  68. tag no: return (0)
  69. tag yes (d: diskpage): return (d.size)
  70. end
  71. end get_size
  72. fetch = proc (p: cvt, i: word) returns (any) signals (bounds)
  73. tagcase p
  74. tag no: signal bounds
  75. tag yes (d: diskpage):
  76. if i<0 | i>=d.size then signal bounds end
  77. m: mempage := put_in_mem (d)
  78. return (m[i])
  79. end
  80. end fetch
  81. store = proc (p: cvt, i: word, e: any) signals (bounds)
  82. tagcase p
  83. tag no: signal bounds
  84. tag yes (d: diskpage):
  85. if i<0 | i>=d.size then signal bounds end
  86. m: mempage := put_in_mem (d)
  87. m[i] := e
  88. end
  89. end store
  90. %
  91. % Internal procedures for the PAGE cluster.
  92. %
  93. allocate_mem = proc (d: diskpage) returns (mempage)
  94. sizeno: word := d.sizeno
  95. while TRUE do
  96. begin
  97. m: mempage := mempage$allocate (sizeno)
  98. pagemap$enter (pm, d, m)
  99. return (m)
  100. end except when full:
  101. do_page_replacement ()
  102. % for single-process simulation purposes
  103. end
  104. % keep trying, eventually the page replacement
  105. % process will release some
  106. end
  107. end allocate_mem
  108. free_mem = proc (d: diskpage)
  109. m: mempage := pagemap$lookup (pm, d)
  110. except when not_there: return end
  111. pagemap$remove (pm, d)
  112. mempage$free (m)
  113. end free_mem
  114. put_in_mem = proc (d: diskpage) returns (mempage)
  115. m: mempage := pagemap$lookup (pm, d)
  116. except when not_there:
  117. m := allocate_mem (d)
  118. swapin (d, m)
  119. end
  120. return (m)
  121. end put_in_mem
  122. % A separate page-replacement process continually frees main
  123. % memory pages in an attempt to keep a minimum amount of
  124. % free main memory. For simulation purposes, the following
  125. % simple procedure suffices.
  126. do_page_replacement = proc ()
  127. % Flush all main memory.
  128. for d: diskpage in pagemap$elements (pm) do
  129. write_to_disk (d)
  130. end
  131. end do_page_replacement
  132. write_to_disk = proc (d: diskpage)
  133. m: mempage := pagemap$lookup (pm, d)
  134. except when not_there: return end
  135. swapout (d, m)
  136. free_mem (d)
  137. end write_to_disk
  138. swapin = proc (d: diskpage, m: mempage)
  139. v: sequence[any] := diskpage$read (d)
  140. i: word := 0
  141. for x:any in sequence[any]$elements (v) do
  142. m[i] := x
  143. i := i + 1
  144. end
  145. end swapin
  146. swapout = proc (d: diskpage, m: mempage)
  147. v: sequence[any] := sequence[any]$new ()
  148. for i:word in word$from_to (0, d.size-1) do
  149. sequence[any]$addh (v, m[i]) % Hack!
  150. end
  151. diskpage$write (d, v)
  152. end swapout
  153. %
  154. % Debugging routines for the PAGE cluster.
  155. %
  156. print = proc (p: cvt, s: stream)
  157. tagcase p
  158. tag no: stream$puts ("Null", s)
  159. tag yes (d: diskpage):
  160. diskpage$print (d, s)
  161. end
  162. end print
  163. print_pagemap = proc (s: stream)
  164. pagemap$print (pm, s)
  165. end print_pagemap
  166. end page
  167. %
  168. % The pagemap.
  169. %
  170. pagemap = cluster is create, enter, lookup, remove, elements,
  171. print
  172. info = record [name: diskpage, value: mempage]
  173. rep = array[info]
  174. create = proc () returns (cvt)
  175. return (rep$new ())
  176. end create
  177. enter = proc (pm: cvt, d: diskpage, m: mempage) signals (duplicate_entry)
  178. for x: info in rep$elements (pm) do
  179. if x.name = d then signal duplicate_entry end
  180. end
  181. rep$addh (pm, info${name: d, value: m})
  182. end enter
  183. lookup = proc (pm: cvt, d: diskpage) returns (mempage) signals (not_there)
  184. for x: info in rep$elements (pm) do
  185. if x.name = d then return (x.value) end
  186. end
  187. signal not_there
  188. end lookup
  189. remove = proc (pm: cvt, d: diskpage)
  190. for i: word in rep$indexes (pm) do
  191. if pm[i].name = d then
  192. top: info := rep$remh (pm)
  193. if top.name ~= d then
  194. pm[i] := top
  195. end
  196. return
  197. end
  198. end
  199. end remove
  200. elements = iter (pm: cvt) yields (diskpage)
  201. for x: info in rep$elements (pm) do
  202. yield (x.name)
  203. end
  204. end elements
  205. %
  206. % Debugging routines for the PAGEMAP cluster.
  207. %
  208. print = proc (pm: cvt, s: stream)
  209. stream$putl ("Pagemap:", s)
  210. for i: info in rep$elements (pm) do
  211. stream$puts (" name=", s)
  212. diskpage$print (i.name, s)
  213. stream$puts (" value=", s)
  214. mempage$print (i.value, s)
  215. stream$putl ("", s)
  216. end
  217. stream$putl ("", s)
  218. end print
  219. end pagemap
  220. %
  221. % Miscellaneous Procedures
  222. %
  223. findsize = proc (size: word) returns (word) signals (badsize)
  224. % The possible page sizes are encoded into integers in
  225. % the range 0 to MAXSIZENO. This procedure returns
  226. % the size number for the smallest page size not smaller
  227. % than the specified size.
  228. if size<0 then signal badsize end
  229. if size=0 then return (0) end
  230. for i: word in word$from_to (1, MAXSIZENO) do
  231. if size<=2**i then return (i) end
  232. end
  233. signal badsize
  234. end findsize
  235. sizetab = proc (sizeno: word) returns (word) signals (badsize)
  236. % This procedure returns a page size given its encoding.
  237. if sizeno<0 cor sizeno>MAXSIZENO then signal badsize end
  238. if sizeno=0 then return (0) end
  239. return (2**sizeno)
  240. end sizetab