MudkipTheEpic

Coroutine Management [WIP]

May 13th, 2013
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.52 KB | None | 0 0
  1. --[[
  2. Author: NeverCast
  3. Last Edited: 2/11/12
  4. You're welcome to use this code however you like, but please leave my credit at the top. Thanks
  5. --]]
  6.  
  7. -- Prior code writing hypothosis:
  8. -- How to become top level,
  9.  
  10. -- Climb stack, Find single shell instance
  11. -- Kill shell instance, override pullEvent
  12. -- Override os.shutdown
  13. -- Exit code
  14. -- Wait for Bios to quit and hook that to fire up your own functions
  15.  
  16. -- Add the functions here that you want to run once the environment has been overridden
  17. -- In this bios this was shell and rednet.run, I've removed rednet.run as an example
  18. -- Any functions here will be top level and recieve all the events!
  19. --[[local loadPool = {
  20. function()
  21. os.run( {}, "rom/programs/shell" )
  22. end
  23. }
  24. --]]
  25.  
  26. -- Feel free to set this to false if you don't want the text printed
  27. local showMessages = false
  28.  
  29. if background then return end
  30. term.clear()
  31. term.setCursorPos(1,1)
  32. local function sort(table)
  33. local max=getfenv(2).table.maxn
  34. if #table==max(table) then return table end
  35. local i=1
  36. for j=1,max(table) do
  37. if table[j] and j~=i then
  38. table[i]=table[j]
  39. table[j]=nil
  40. i=i+1
  41. elseif table[j] then
  42. i=i+1
  43. end
  44. end
  45. return table
  46. end
  47.  
  48. local function coroutineManage()
  49. local bgCo={}
  50. local bgW={}
  51. local bgP={}
  52. _G.background={}
  53. function _G.background.addCo(f,...)
  54. local argsy={...}
  55. if not type(f)=="function" then error("function expected, got "..type(f),2) end
  56. local i=#bgCo+1
  57. bgCo[i]=coroutine.create(function() f(unpack(argsy)) end)
  58. os.queueEvent("coroutine_create",i)
  59. return i
  60. end
  61. function _G.background.killCo(id)
  62. if not type(id)=="number" then error("number expected, got "..type(id),2) end
  63. if id==1 then error("Cannot kill shell",2) end
  64. if not bgCo[id] then return false, "No such coroutine" end
  65. local l= table.remove(bgCo,id)
  66. os.queueEvent("coroutine_kill",id)
  67. return l
  68. end
  69. function _G.background.pauseCo(id)
  70. if not type(id)=="number" then error("number expected, got "..type(id),2) end
  71. if not bgCo[id] then return false, "No such coroutine" end
  72. if not bgP[i] then os.queueEvent("coroutine_pause",id) end
  73. bgP[id]=true
  74. return true
  75. end
  76. function _G.background.resumeCo(id)
  77. if not type(id)==number then error("number expected, got "..type(id),2) end
  78. if not bgCo[id] then return false, "No such coroutine" end
  79. if bgP[id] then os.queueEvent("coroutine_resume",id) end
  80. bgP[id]=false
  81. return true
  82. end
  83. function _G.background.getCoroutines()
  84. return {unpack(bgCo)}
  85. end
  86. function _G.background.isPaused(i)
  87. return not bgCo[i] and nil or (bgP[i] or false)
  88. end
  89. _G.background.addCo(dofile,"rom/programs/shell")
  90. --print("test")
  91. local e={}
  92. while true do
  93. bgCo=sort(bgCo)
  94. bgW=sort(bgW)
  95. if #bgCo==0 then os.shutdown() end
  96. for i=1,#bgCo do
  97. local n=bgCo[i]
  98. --print(n)
  99. --print(i)
  100. if n then
  101. if (not (bgW[i] and bgW[i]~=e[1]) or e[1]=="terminate") and not bgP[i] then
  102. --print("Passing event to coroutine.")
  103. local ok,param=coroutine.resume(bgCo[i],unpack(e))
  104. --print(ok,":",param)
  105. --print(table.concat(e,":"))
  106. if not ok or coroutine.status(bgCo[i])=="dead" then
  107. if not ok then os.queueEvent("coroutine_error",i,err) else os.queueEvent("coroutine_death",i) end
  108. --print("Oh noes, coroutine #"..i.." has crashed!")
  109. --print(param)
  110. bgCo[i]=nil
  111. bgW[i]=nil
  112. bgP[i]=nil
  113. if i==1 then os.shutdown() end
  114. else
  115. bgW[i]=param or false
  116. --print(param)
  117. end
  118. end
  119. end
  120. end
  121. if #bgCo<#bgP+1 then for k,v in pairs(bgP) do if v then os.queueEvent("coroutine_resume",k) end end bgP={} end
  122. e={os.pullEventRaw()}
  123. --print("Recieved event")
  124. end
  125. end
  126.  
  127. if os.myEnv then
  128. if showMessages then
  129. print"Injection completed successfully"
  130. end
  131. return
  132. end
  133.  
  134. local prevState = {}
  135.  
  136. table.size = function(tbl)
  137. local count = 0
  138. for _,__ in pairs(tbl) do
  139. count = count + 1
  140. end
  141. return count
  142. end
  143.  
  144. local function getParentShell()
  145. for i = 0, 5 do
  146. local env = getfenv(i)
  147. if table.size(env) == 1 then
  148. local i,v = next(env) -- Grab first
  149. if i == "shell" then
  150. return v
  151. end
  152. end
  153. end
  154. return nil
  155. end
  156.  
  157. local function recover()
  158. -- Set flag
  159. os.myEnv = true
  160. -- Put back the trampled environment
  161. os.startTimer = prevState.startTimer
  162. os.shutdown = prevState.shutdown
  163. os.pullEvent = prevState.pullEvent
  164. -- Launch shell like nothing happened
  165.  
  166. prevState = nil
  167.  
  168. term.setCursorPos(1,1)
  169. term.clear()
  170.  
  171. background={}
  172. _G.background=background
  173.  
  174. if showMessages then
  175. -- Feel free to remove this line, It's just a proof thing
  176. print"Look at me, I load before shell does"
  177. end
  178.  
  179. local ok, err = pcall(coroutineManage)
  180. os.shutdown()
  181. end
  182.  
  183. os.stage = {}
  184.  
  185. -- Stages:
  186. -- injected: Overriding os functions
  187. -- shutdown: Shutdown program has been called
  188. -- jstincse: Shell is doing it's just-in-case
  189. -- bioswait: Bios is waiting for a key press
  190. -- biosexit: Bios has quit
  191. -- complete: fully injected
  192.  
  193.  
  194. local function setStage(stage)
  195. os.stage.currentStage = stage
  196. end
  197.  
  198. local function getStage()
  199. return os.stage.currentStage
  200. end
  201.  
  202. local function _os_pullEvent(_filter)
  203. _filter = _filter or ""
  204. if _filter == "key" then
  205. setStage("bioswait")
  206. return "key", 0
  207. elseif _filter == "timer" then
  208. setStage("shutdown")
  209. return "timer", 0
  210. end
  211. end
  212.  
  213. local function _replSleep(dur)
  214. local timer = prevState.startTimer( dur )
  215. repeat
  216. local sEvent, param = prevState.pullEvent( "timer" )
  217. until param == timer
  218. end
  219.  
  220. local function _os_shutdown()
  221. if getStage() == "shutdown" then
  222. setStage("jstincse")
  223. elseif getStage() == "bioswait" then
  224. setStage("biosexit")
  225. end
  226. if getStage() == "biosexit" then
  227. recover()
  228. end
  229. end
  230.  
  231. local function _os_startTimer(seconds)
  232. return 0
  233. end
  234.  
  235. local function inject()
  236. prevState.startTimer = os.startTimer
  237. prevState.shutdown = os.shutdown
  238. prevState.pullEvent = os.pullEvent
  239. os.shutdown = _os_shutdown
  240. os.pullEvent = _os_pullEvent
  241. os.startTimer = _os_startTimer
  242. setStage("injected")
  243. local shellImpl = getParentShell()
  244. shellImpl.exit()
  245. end
  246.  
  247. -- Start everything
  248. inject()
Advertisement
Add Comment
Please, Sign In to add comment