123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- {
- Copyright (c) 2024- by Michael Van Canneyt
- This unit handles the compiler tasks.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit ctask;
- {$mode ObjFPC}
- { $DEFINE DEBUG_CTASK}
- interface
- uses
- fmodule, cclasses, globstat;
- type
- { ttask_list }
- ttask_list = class(tlinkedlistitem)
- module : tmodule;
- state : tglobalstate;
- constructor create(_m : tmodule);
- destructor destroy; override;
- procedure SaveState;
- Procedure RestoreState;
- procedure DiscardState;
- function nexttask : ttask_list; inline;
- end;
- ttasklinkedlist = class(tlinkedlist)
- function firsttask : ttask_list; inline;
- end;
- { ttask_handler }
- ttask_handler = class
- private
- list : ttasklinkedlist;
- hash : TFPHashList;
- main : tmodule;
- procedure rebuild_hash;
- public
- constructor create;
- destructor destroy; override;
- // Find the task for module m
- function findtask(m : tmodule) : ttask_list;
- // Can we continue processing this module ? If not, firstwaiting contains first module that m is waiting for.
- function cancontinue(m : tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
- // Overload of cancontinue, based on task.
- function cancontinue(t: ttask_list; out firstwaiting: tmodule): boolean; inline;
- // Continue processing this module. Return true if the module is done and can be removed.
- function continue(t : ttask_list): Boolean;
- // process the queue. Note that while processing the queue, elements will be added.
- procedure processqueue;
- // add a module to the queue. If a module is already in the queue, we do not add it again.
- procedure addmodule(m : tmodule);
- end;
- var
- task_handler : TTask_handler;
- procedure InitTaskHandler;
- procedure DoneTaskHandler;
- implementation
- uses verbose, fppu, finput, globtype, sysutils, scanner, parser, pmodules;
- procedure InitTaskHandler;
- begin
- task_handler:=ttask_handler.create;
- end;
- procedure DoneTaskHandler;
- begin
- freeandnil(task_handler);
- end;
- { ttasklinkedlist }
- function ttasklinkedlist.firsttask: ttask_list;
- begin
- Result:=ttask_list(first);
- end;
- { ttask_list }
- constructor ttask_list.create(_m: tmodule);
- begin
- inherited create;
- module:=_m;
- state:=nil;
- end;
- destructor ttask_list.destroy;
- begin
- DiscardState;
- Inherited;
- end;
- procedure ttask_list.DiscardState;
- begin
- FreeAndNil(state);
- end;
- function ttask_list.nexttask: ttask_list;
- begin
- Result:=ttask_list(next);
- end;
- procedure ttask_list.SaveState;
- begin
- if State=Nil then
- State:=tglobalstate.Create(true)
- else
- State.save(true);
- end;
- procedure ttask_list.RestoreState;
- begin
- if not module.is_reset then
- state.restore(true);
- if assigned(current_scanner) and assigned(current_scanner.inputfile) then
- if current_scanner.inputfile.closed then
- begin
- current_scanner.tempopeninputfile;
- current_scanner.gettokenpos;
- end;
- end;
- { ttask_handler }
- constructor ttask_handler.create;
- begin
- list:=ttasklinkedlist.Create;
- hash:=TFPHashList.Create;
- end;
- destructor ttask_handler.destroy;
- begin
- hash.free;
- List.Clear;
- FreeAndNil(list);
- inherited destroy;
- end;
- function ttask_handler.findtask(m: tmodule): ttask_list;
- begin
- result:=list.FirstTask;
- while result<>nil do
- begin
- if result.module=m then
- exit;
- result:=result.nexttask;
- end;
- {$IFDEF DEBUG_CTASK}Writeln('No task found for '+m.ToString);{$ENDIF}
- end;
- function ttask_handler.cancontinue(m: tmodule; checksub : boolean; out firstwaiting: tmodule): boolean;
- procedure CheckUsed(out acandidate : tmodule);
- var
- itm : TLinkedListItem;
- iscandidate : boolean;
- m2 : tmodule;
- begin
- acandidate:=nil;
- itm:=m.used_units.First;
- while (acandidate=Nil) and assigned(itm) do
- begin
- iscandidate:=Not (tused_unit(itm).u.state in [ms_processed,ms_compiled]);
- if iscandidate then
- begin
- acandidate:=tused_unit(itm).u;
- if not cancontinue(acandidate,false,m2) then
- acandidate:=nil;
- end;
- itm:=itm.Next;
- end;
- end;
- var
- m2 : tmodule;
- begin
- firstwaiting:=nil;
- // We do not need to consider the program as long as there are units that need to be treated.
- if (m.is_initial and not m.is_unit) and (list.count>1) then
- exit(False);
- case m.state of
- ms_unknown : cancontinue:=true;
- ms_registered : cancontinue:=true;
- ms_compile : cancontinue:=true;
- ms_compiling_waitimpl : cancontinue:=m.usedunitsloaded(false,firstwaiting);
- ms_compiling_waitfinish : cancontinue:=m.nowaitingforunits(firstwaiting);
- ms_compiling_waitintf : cancontinue:=m.usedunitsloaded(true,firstwaiting);
- ms_compiling_wait : cancontinue:=m.usedunitsloaded(true,firstwaiting);
- ms_compiled : cancontinue:=true;
- ms_processed : cancontinue:=true;
- ms_moduleerror : cancontinue:=true;
- else
- InternalError(2024011802);
- end;
- if (not cancontinue) and checksub then
- begin
- checkused(m2);
- if m2<>nil then
- firstwaiting:=m2;
- end;
- {$IFDEF DEBUG_CTASK}
- Write(m.ToString,' state: ',m.state,', can continue: ',Result);
- if result then
- Writeln
- else
- begin
- Write(' (First waiting: ');
- If Assigned(FirstWaiting) then
- Writeln(FirstWaiting.ToString,' )')
- else
- Writeln('<none>)');
- end;
- {$ENDIF}
- end;
- function ttask_handler.cancontinue(t : ttask_list; out firstwaiting : tmodule): boolean;
- begin
- Result:=cancontinue(t.module,true,firstwaiting);
- end;
- function ttask_handler.continue(t : ttask_list) : Boolean;
- var
- m : tmodule;
- orgname : shortstring;
- begin
- m:=t.module;
- orgname:=m.modulename^;
- {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' Continues. State: ',m.state);{$ENDIF}
- if Assigned(t.state) then
- t.RestoreState;
- case m.state of
- ms_registered : parser.compile_module(m);
- ms_compile : parser.compile_module(m);
- ms_compiled : if (not m.is_initial) or m.is_unit then
- (m as tppumodule).post_load_or_compile(m,m.compilecount>1);
- ms_compiling_waitintf : pmodules.parse_unit_interface_declarations(m);
- ms_compiling_waitimpl : pmodules.proc_unit_implementation(m);
- ms_compiling_waitfinish : pmodules.finish_unit(m);
- ms_compiling_wait : pmodules.proc_program_declarations(m,m.islibrary);
- ms_processed : ;
- else
- InternalError(2024011801);
- end;
- if m.state=ms_compiled then
- begin
- parsing_done(m);
- if m.is_initial and not m.is_unit then
- m.state:=ms_processed;
- end;
- Result:=m.state=ms_processed;
- {$IFDEF DEBUG_CTASK}
- Write(m.ToString,' done: ',Result);
- if Result then
- Writeln
- else
- Writeln(', state is now: ',m.state);
- {$ENDIF}
- if not result then
- // Not done, save state
- t.SaveState;
- {
- the name can change as a result of processing, e.g. PROGRAM -> TB0406
- Normally only for the initial module, but we'll do a generic check.
- }
- if m.modulename^<>orgname then
- rebuild_hash;
- end;
- procedure ttask_handler.rebuild_hash;
- var
- t : ttask_list;
- begin
- Hash.Clear;
- t:=list.firsttask;
- While assigned(t) do
- begin
- Hash.Add(t.module.modulename^,t);
- t:=t.nexttask;
- end;
- end;
- procedure ttask_handler.processqueue;
- var
- t,t2 : ttask_list;
- process : boolean;
- dummy,firstwaiting : tmodule;
- begin
- t:=list.firsttask;
- While t<>nil do
- begin
- process:=cancontinue(t,firstwaiting);
- if process then
- begin
- if continue(t) then
- begin
- {$IFDEF DEBUG_CTASK}Writeln(t.module.ToString,' is finished, removing from task list');{$ENDIF}
- hash.Remove(t.module);
- list.Remove(t);
- end;
- // maybe the strategy can be improved.
- t:=list.firsttask;
- end
- else if assigned(firstwaiting) and cancontinue(firstwaiting,true, dummy) then
- begin
- t2:=findtask(firstwaiting);
- if t2=nil then
- t2:=t.nexttask;
- t:=t2;
- end
- else
- begin
- t:=t.nexttask;
- end;
- if t=nil then
- t:=list.firsttask;
- end;
- end;
- procedure ttask_handler.addmodule(m: tmodule);
- var
- n : TSymStr;
- e, t : ttask_list;
- begin
- {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' added to task scheduler. State: ',m.state);{$ENDIF}
- n:=m.modulename^;
- e:=ttask_list(Hash.Find(n));
- if e=nil then
- begin
- // Clear reset flag.
- // This can happen when during load, reset is done and unit is added to task list.
- m.is_reset:=false;
- t:=ttask_list.create(m);
- list.insert(t);
- hash.Add(n,t);
- if list.count=1 then
- main:=m;
- end
- else
- begin
- // We have a task, if it was reset, then clear the state and move the task to the start.
- if m.is_reset then
- begin
- {$IFDEF DEBUG_CTASK}Writeln(m.ToString,' was reset, resetting flag. State: ',m.state);{$ENDIF}
- m.is_reset:=false;
- t:=findtask(m);
- if assigned(t) then
- begin
- t.DiscardState;
- list.Remove(t);
- list.insertbefore(t,list.First);
- end;
- end;
- end;
- end;
- end.
|