ctask.pas 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. {
  2. Copyright (c) 2024- by Michael Van Canneyt
  3. This unit handles the compiler tasks.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ctask;
  18. {$mode ObjFPC}
  19. interface
  20. uses
  21. fmodule, cclasses, globstat;
  22. type
  23. { ttask_list }
  24. ttask_list = class(tlinkedlistitem)
  25. module : tmodule;
  26. state : tglobalstate;
  27. constructor create(_m : tmodule);
  28. destructor destroy; override;
  29. procedure SaveState;
  30. Procedure RestoreState;
  31. procedure DiscardState;
  32. function nexttask : ttask_list; inline;
  33. end;
  34. ttasklinkedlist = class(tlinkedlist)
  35. function firsttask : ttask_list; inline;
  36. end;
  37. { ttask_handler }
  38. ttask_handler = class
  39. private
  40. list : ttasklinkedlist;
  41. hash : TFPHashList;
  42. main : tmodule;
  43. public
  44. constructor create;
  45. destructor destroy; override;
  46. // Find the task for module m
  47. function findtask(m : tmodule) : ttask_list;
  48. // Can we continue processing this module ? If not, firstwaiting contains first module that m is waiting for.
  49. function cancontinue(m : tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
  50. // Overload of cancontinue, based on task.
  51. function cancontinue(t: ttask_list; out firstwaiting: tmodule): boolean; inline;
  52. // Continue processing this module. Return true if the module is done and can be removed.
  53. function continue(t : ttask_list): Boolean;
  54. // process the queue. Note that while processing the queue, elements will be added.
  55. procedure processqueue;
  56. // add a module to the queue. If a module is already in the queue, we do not add it again.
  57. procedure addmodule(m : tmodule);
  58. end;
  59. var
  60. task_handler : TTask_handler;
  61. procedure InitTaskHandler;
  62. procedure DoneTaskHandler;
  63. implementation
  64. uses verbose, fppu, finput, globtype, sysutils, scanner, parser, pmodules;
  65. procedure InitTaskHandler;
  66. begin
  67. task_handler:=ttask_handler.create;
  68. end;
  69. procedure DoneTaskHandler;
  70. begin
  71. freeandnil(task_handler);
  72. end;
  73. { ttasklinkedlist }
  74. function ttasklinkedlist.firsttask: ttask_list;
  75. begin
  76. Result:=ttask_list(first);
  77. end;
  78. { ttask_list }
  79. constructor ttask_list.create(_m: tmodule);
  80. begin
  81. inherited create;
  82. module:=_m;
  83. state:=nil;
  84. end;
  85. destructor ttask_list.destroy;
  86. begin
  87. DiscardState;
  88. Inherited;
  89. end;
  90. procedure ttask_list.DiscardState;
  91. begin
  92. FreeAndNil(state);
  93. end;
  94. function ttask_list.nexttask: ttask_list;
  95. begin
  96. Result:=ttask_list(next);
  97. end;
  98. procedure ttask_list.SaveState;
  99. begin
  100. if State=Nil then
  101. State:=tglobalstate.Create(true)
  102. else
  103. State.save(true);
  104. end;
  105. procedure ttask_list.RestoreState;
  106. begin
  107. if not module.is_reset then
  108. state.restore(true);
  109. if assigned(current_scanner) and assigned(current_scanner.inputfile) then
  110. if current_scanner.inputfile.closed then
  111. begin
  112. current_scanner.tempopeninputfile;
  113. current_scanner.gettokenpos;
  114. end;
  115. end;
  116. { ttask_handler }
  117. constructor ttask_handler.create;
  118. begin
  119. list:=ttasklinkedlist.Create;
  120. hash:=TFPHashList.Create;
  121. end;
  122. destructor ttask_handler.destroy;
  123. begin
  124. hash.free;
  125. List.Clear;
  126. FreeAndNil(list);
  127. inherited destroy;
  128. end;
  129. function ttask_handler.findtask(m: tmodule): ttask_list;
  130. begin
  131. result:=list.FirstTask;
  132. while result<>nil do
  133. begin
  134. if result.module=m then
  135. exit;
  136. result:=result.nexttask;
  137. end;
  138. end;
  139. function ttask_handler.cancontinue(m: tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
  140. procedure CheckUsed(out acandidate : tmodule);
  141. var
  142. itm : TLinkedListItem;
  143. iscandidate : boolean;
  144. m2 : tmodule;
  145. begin
  146. acandidate:=nil;
  147. itm:=m.used_units.First;
  148. while (acandidate=Nil) and assigned(itm) do
  149. begin
  150. iscandidate:=Not (tused_unit(itm).u.state in [ms_compiled]);
  151. if iscandidate then
  152. begin
  153. acandidate:=tused_unit(itm).u;
  154. if not cancontinue(acandidate,false,m2) then
  155. acandidate:=nil;
  156. end;
  157. itm:=itm.Next;
  158. end;
  159. end;
  160. var
  161. m2 : tmodule;
  162. begin
  163. firstwaiting:=nil;
  164. if m.is_initial and (list.count>1) then
  165. exit(False);
  166. case m.state of
  167. ms_unknown : cancontinue:=true;
  168. ms_registered : cancontinue:=true;
  169. ms_compile : cancontinue:=true;
  170. ms_compiling_waitimpl : cancontinue:=m.usedunitsloaded(false,firstwaiting);
  171. ms_compiling_waitfinish : cancontinue:=m.nowaitingforunits;
  172. ms_compiling_waitintf : cancontinue:=m.usedunitsloaded(true,firstwaiting);
  173. ms_compiling_wait : cancontinue:=m.usedunitsloaded(true,firstwaiting);
  174. ms_compiled : cancontinue:=true;
  175. ms_processed : cancontinue:=true;
  176. ms_moduleerror : cancontinue:=true;
  177. else
  178. InternalError(2024011802);
  179. end;
  180. if (not cancontinue) and checksub then
  181. begin
  182. checkused(m2);
  183. if m2<>nil then
  184. firstwaiting:=m2;
  185. end;
  186. end;
  187. function ttask_handler.cancontinue(t : ttask_list; out firstwaiting : tmodule): boolean;
  188. begin
  189. Result:=cancontinue(t.module,true,firstwaiting);
  190. end;
  191. function ttask_handler.continue(t : ttask_list) : Boolean;
  192. var
  193. m : tmodule;
  194. begin
  195. m:=t.module;
  196. if Assigned(t.state) then
  197. t.RestoreState;
  198. case m.state of
  199. ms_registered : parser.compile_module(m);
  200. ms_compile : parser.compile_module(m);
  201. ms_compiled : if (not m.is_initial) or m.is_unit then
  202. (m as tppumodule).post_load_or_compile(m.compilecount>1);
  203. ms_compiling_waitintf : pmodules.parse_unit_interface_declarations(m);
  204. ms_compiling_waitimpl : pmodules.proc_unit_implementation(m);
  205. ms_compiling_waitfinish : pmodules.proc_unit_implementation(m);
  206. ms_compiling_wait : pmodules.proc_program_declarations(m,m.islibrary);
  207. ms_processed : ;
  208. else
  209. InternalError(2024011801);
  210. end;
  211. if m.state=ms_compiled then
  212. begin
  213. parsing_done(m);
  214. if m.is_initial and not m.is_unit then
  215. m.state:=ms_processed;
  216. end;
  217. Result:=m.state=ms_processed;
  218. if not result then
  219. // Not done, save state
  220. t.SaveState;
  221. end;
  222. procedure ttask_handler.processqueue;
  223. var
  224. t,t2 : ttask_list;
  225. process : boolean;
  226. m,firstwaiting : tmodule;
  227. begin
  228. t:=list.firsttask;
  229. While t<>nil do
  230. begin
  231. process:=cancontinue(t,firstwaiting);
  232. if process then
  233. begin
  234. if continue(t) then
  235. begin
  236. hash.Remove(t.module);
  237. list.Remove(t);
  238. end;
  239. // maybe the strategy can be improved.
  240. t:=list.firsttask;
  241. end
  242. else if assigned(firstwaiting) and cancontinue(firstwaiting,true, m) then
  243. begin
  244. t2:=findtask(firstwaiting);
  245. if t2=nil then
  246. t2:=t.nexttask;
  247. t:=t2;
  248. end
  249. else
  250. begin
  251. t:=t.nexttask;
  252. end;
  253. end;
  254. end;
  255. procedure ttask_handler.addmodule(m: tmodule);
  256. var
  257. n : TSymStr;
  258. e : tmodule;
  259. t : ttask_list;
  260. begin
  261. n:=m.modulename^;
  262. e:=tmodule(Hash.Find(n));
  263. if e=nil then
  264. begin
  265. t:=ttask_list.create(m);
  266. list.insert(t);
  267. hash.Add(n,t);
  268. if list.count=1 then
  269. main:=m;
  270. end
  271. else
  272. begin
  273. // We have a task, if it was reset, then clear the state and move the task to the start.
  274. if m.is_reset then
  275. begin
  276. m.is_reset:=false;
  277. t:=findtask(m);
  278. if assigned(t) then
  279. begin
  280. t.DiscardState;
  281. list.Remove(t);
  282. list.insertbefore(t,list.First);
  283. end;
  284. end;
  285. end;
  286. end;
  287. end.