unit initialization

Discussion and questions about programming with Ultibo.
Koen
Posts: 31
Joined: Sat Apr 29, 2017 10:41 am

unit initialization

Postby Koen » Tue Jun 19, 2018 9:22 am

If I add a startup-code to the end of a unit like e.g.

begin
HTTPListener:=THTTPListener.Create;
HTTPListener.Active:=True;
WebStatusRegister(HTTPListener,'','',True);
end.

should I add a
ThreadHalt(0);
More general: is the start-code of all the units started in one thread or single threads?
Just for interrest.
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: unit initialization

Postby Ultibo » Tue Jun 19, 2018 12:05 pm

Koen wrote:should I add a
ThreadHalt(0);

No, that would halt the system during startup, see below for more details.

Koen wrote:More general: is the start-code of all the units started in one thread or single threads?
Just for interrest.

All unit initialization code is executed by the main thread during startup, at the point this occurs all of the platform and threading initialization has already been completed and things like timer and scheduler interrupts are already running.

If you look at the MainExecute function in the Threads unit you will see that it calls PASCALMAIN which is actually the FPC internal name for the begin/end block in the main program unit.

There is no one place where you can see the code for how initialization occurs but the general concept is that at the start of PASCALMAIN (the program begin/end block) an invisible function is called that walks through an array containing the initialization point for every unit.

At the end of PASCALMAIN another invisible function calls the finalization code of each unit and that is the reason we add ThreadHalt(0) to the end of all of our examples, if the main thread ever exited the program begin/end block it could call finalization functions while the system is still running (although there are some other protections as well just in case).

Hope that makes sense.
Ultibo.org | Make something amazing
https://ultibo.org
mark
Posts: 1242
Joined: Mon Oct 03, 2016 2:12 am
Location: Indianapolis, US

Re: unit initialization

Postby mark » Tue Oct 23, 2018 4:56 am

Ultibo wrote:At the end of PASCALMAIN another invisible function calls the finalization code of each unit and that is the reason we add ThreadHalt(0) to the end of all of our examples, if the main thread ever exited the program begin/end block it could call finalization functions while the system is still running (although there are some other protections as well just in case).


Isn't the purpose of the finalization to bring everything to an end? With the ThreadHalt included at the end of the program, how does one invoke the finalization?

Also, is there a reason for BeginThread to not simply call ThreadHalt(0) if the supplied thread function returns?

Does, or could, BeginThread provide a default exception trap that logs the exception messsge? This is another common thing that gets coded inside of a thread that could be eliminated in the most common case (report and halt.)

It would be nice to eliminate coding the ThreadHalt's if possible.

Thanks, Mark
Ultibo - The Internet of Things that Just Work
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: unit initialization

Postby Ultibo » Tue Oct 23, 2018 10:58 am

mark wrote:Isn't the purpose of the finalization to bring everything to an end? With the ThreadHalt included at the end of the program, how does one invoke the finalization?

Normally yes, that would be true. In a traditional Pascal program when the begin/end block of the program exits the program ends but in the case of Ultibo the program and the system are one and the same so if the program ends then there is nothing left for the system to do.

I would argue that in an embedded application you might never normally want to invoke finalization, of course there are cases where you might want to shutdown the system (and therefore end the application) but we currently have different functions for that. It's feasible that the finalization sections of the units could be run as part of system shutdown but that would need some thought to make sure it worked reliably in all cases.

mark wrote:Also, is there a reason for BeginThread to not simply call ThreadHalt(0) if the supplied thread function returns?

So I should clarify one item, the need for ThreadHalt() only relates to the main begin/end block in the program unit which will always be executed by the main thread on startup.

The main thread is created during boot and begins at MainExecute() in the Threads unit, this calls PASCALMAIN which is the actual name of the program begin/end block.

If you disassemble an Ultibo application using arm-ultibo-objdump you will see that PASCALMAIN starts with a call to FPC_INITIALIZEUNITS and ends by calling FPC_DO_EXIT which in turn calls SYSTEM_$$_INTERNALEXIT and SYSTEM_$$_SYSTEM_EXIT.

Now the other protection I mentioned above is that SYSTEM_$$_INTERNALEXIT ends up calling SysExitProc which was registered as an exit procedure during startup (before it calls FPC_FINALIZEUNITS) and at that point we simply call ThreadHalt to prevent the termination process from proceeding.

All of this only applies to the main thread running the main begin/end block, all other threads can (and should) happily exit from their function when they are done and they will go through the termination process before being destroyed.

mark wrote:Does, or could, BeginThread provide a default exception trap that logs the exception messsge? This is another common thing that gets coded inside of a thread that could be eliminated in the most common case (report and halt.)

Anytime an exception happens without a registered exception handler (ie no try/except block has been encountered) then the default exception handler will be called. The behavior of the default exception handler is to log the exception using the current default logging output and then halt the thread by calling ThreadHalt().

My recommendation would be to create a class (based on TThread) which contains the standard entry and exit handling for all of your threads, that way you can customize the startup and shutdown (and exception) behavior of your threads without repeating the code every time.

A simple implementation might look like this:

Code: Select all

type
  TMyThread = TThread
  protected
   procedure BeforeRun; virtual;
   procedure AfterRun; virtual;
   procedure Run; virtual;
   
   procedure Execute; override;
  end;
 
implementation
   
procedure TMyThread.BeforeRun;
begin
  //Put code here to run before your thread starts
end;

procedure TMyThread.AfterRun;
begin
  //Put code here to run after your thread finishes
end;

procedure TMyThread.Run;
begin
  //Put code here for when your thread is running
  while  not Terminated do
  begin
     //Perform some work
  end;
end;

procedure TMyThread.Execute;
begin
   try
     BeforeRun;
     try
       Run;
     finally
       AfterRun;
     end;
   except
      //Handle any exception that is not dealt with in normal operation
   end; 
end;
 
Ultibo.org | Make something amazing
https://ultibo.org
mark
Posts: 1242
Joined: Mon Oct 03, 2016 2:12 am
Location: Indianapolis, US

Re: unit initialization

Postby mark » Tue Oct 23, 2018 11:37 pm

Ok, that all makes sense. How about changing https://github.com/ultibohub/Core/blob/ ... 730-L23736 to call ThreadHalt(0) (instead of ERROR_RUNTIME_ERROR) and removing all the ThreadHalt's from the examples? The programmer can always change the system exit procedure for a different exit plan. Mark.
Ultibo - The Internet of Things that Just Work
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: unit initialization

Postby Ultibo » Wed Oct 24, 2018 11:21 am

Ultibo wrote:Now the other protection I mentioned above is that SYSTEM_$$_INTERNALEXIT ends up calling SysExitProc which was registered as an exit procedure during startup (before it calls FPC_FINALIZEUNITS) and at that point we simply call ThreadHalt to prevent the termination process from proceeding.

What I forgot to mention is that because of this extra bit of safety check it is quite ok to just leave out the ThreadHalt() call at the end of the main program, if we ever decide to change the internal behavior we will make sure to point out the change very clearly.

mark wrote:How about changing https://github.com/ultibohub/Core/blob/ ... 730-L23736 to call ThreadHalt(0) (instead of ERROR_RUNTIME_ERROR) and removing all the ThreadHalt's from the examples?

Personally I would argue that putting ThreadHalt() at the end of the examples makes it clearer what is going on, otherwise people may miss the fact that there is some hidden behavior happening to stop the system from shutting down when the main thread exits.

The purpose of the examples is to provide a resource for learning and exploring, we expect that real world usage will have many more requirements beyond what can be shown in simple example.

At this point there are a lot of people still discovering Ultibo for the first time so clarity is important, it should be clear to most what ThreadHalt does at least in a broad sense anyway.
Ultibo.org | Make something amazing
https://ultibo.org
User avatar
Ultibo
Site Admin
Posts: 2040
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: unit initialization

Postby Ultibo » Wed Oct 24, 2018 9:58 pm

I still forgot to say that instead of ThreadHalt() it is also ok to put EndThread() at the end of the main program block, this will terminate the main thread and release the stack etc instead of just halting it.

In standard FPC or Delphi programs allowing the main thread to terminate is often problematic because it has certain special functions, in Ultibo while the main thread is still referenced by some RTL internals in general it is just a normal thread and can be terminated without any real issues.
Ultibo.org | Make something amazing
https://ultibo.org
mark
Posts: 1242
Joined: Mon Oct 03, 2016 2:12 am
Location: Indianapolis, US

Re: unit initialization

Postby mark » Thu Oct 25, 2018 12:38 am

That all makes sense. You might consider moving ThreadHalt(0) to the end of the program to match the other examples:

https://github.com/ultibohub/Examples/b ... #L135-L143

Regards,
Mark
Ultibo - The Internet of Things that Just Work

Return to “General”

Who is online

Users browsing this forum: No registered users and 0 guests