Recent

Author Topic: Solved: Calling application.run for thttpapplicat doesn't return for finally par  (Read 1299 times)

vangli

  • New Member
  • *
  • Posts: 46
Hi, I am running Ubuntu 22.04 with Lazarus version 3.0RC1 and FPC 3.2.2. I am playing around with creating a webserver application for myself. I am doing this for fun and to keep my brain active as a pensioner. The following code is an shortened extract of my code to pinpoint my question. Its a command line application I start in a terminal window. It runs perfectly, and I am able to terminate with Ctrl-C from terminal. I am aware that Application.Run is a blocking call, which in my case is perfect. What I do expect in my confused thinking, is that after pressing Ctrl-C, the application should write the text in the finally section after returning from the Application.Run call. But No. Where am I wrong (I know, it could probably be me??  %) )?
Code: Pascal  [Select][+][-]
  1. program aWebServer;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$ifdef UNIX}
  7.   cthreads, cmem,
  8.   {$endif}
  9.   fphttpapp, httpdefs, httproute, sysutils;
  10.  
  11. begin
  12.   try
  13.     Application.Port := 8081; // Service port for webserver.
  14.     Application.Threaded := true;
  15.     Application.Initialize;
  16.     Application.Run;
  17.   finally
  18.     writeln('Ending application!');
  19.   end;
  20. end.

« Last Edit: August 24, 2023, 09:24:21 pm by vangli »
Regards Bent

Чебурашка

  • Hero Member
  • *****
  • Posts: 579
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
Run must be terminated calling Application.Terminate method.

Since the thread where Run is called is blocked inside the Run call, you need to have another thread, that you will use to do the Terminate call. Probably it is enough to create callback for CTRL+C, and call Terminate from it, without creating explicitely an extra thread for that.

Something like this should work (I did not test).

Code: Pascal  [Select][+][-]
  1. program aWebServer;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$ifdef UNIX}
  7.   cthreads, cmem,
  8.   {$endif}
  9.  
  10.   BaseUnix,
  11.  
  12.   fphttpapp, httpdefs, httproute, sysutils;
  13.  
  14. procedure HandleSigInt(aSignal: LongInt); cdecl;
  15. begin
  16.   Writeln('Calling terminate after SIGINT');
  17.   Application.Terminate();
  18. end;
  19.  
  20. begin
  21.   if FpSignal(SigInt, @HandleSigInt) = signalhandler(SIG_ERR) then
  22.   begin
  23.     Writeln('Failed to install signal error: ', fpGetErrno);
  24.     Halt(1);
  25.   end;
  26.  
  27.   Writeln('Starting application, press CTRL+C to terminate...');
  28.  
  29.   try
  30.     Application.Port := 8081; // Service port for webserver.
  31.     Application.Threaded := true;
  32.     Application.Initialize;
  33.     Application.Run;
  34.   finally
  35.     writeln('Ending application!');
  36.   end;
  37. end.
  38.  
« Last Edit: August 24, 2023, 01:28:52 pm by Чебурашка »
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

vangli

  • New Member
  • *
  • Posts: 46
Thks. I will test this. Your explanation looks logical. I will follow up after testing.

Edit after testing: Still not work 100%. However, I certainly catch the Ctrl+C keypress and enter the HandleSigInt procedure. Then it hangs on Application.Terminate statement. Replacing with a Halt() function do terminate, but the finally statement isn't reached then, naturally. It looks like I have to move sigint functionality into the THtppApplication class through a user defined inherited class.

Anyway, thks a lot for the help, Чебурашка. I will explore more, and when I found a way update this thread.
« Last Edit: August 24, 2023, 02:22:22 pm by vangli »
Regards Bent

ojz0r

  • Jr. Member
  • **
  • Posts: 63
Another option is to include a simple button in the webpage that calls terminate and launch the app as nohup (no hang up).
That way the app will run as a daemon and not block the shell.
I like big endians and i can not lie.

Чебурашка

  • Hero Member
  • *****
  • Posts: 579
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
Thks. I will test this. Your explanation looks logical. I will follow up after testing.

Edit after testing: Still not work 100%. However, I certainly catch the Ctrl+C keypress and enter the HandleSigInt procedure. Then it hangs on Application.Terminate statement. Replacing with a Halt() function do terminate, but the finally statement isn't reached then, naturally. It looks like I have to move sigint functionality into the THtppApplication class through a user defined inherited class.

Anyway, thks a lot for the help, Чебурашка. I will explore more, and when I found a way update this thread.

I checked where I use this class and for me the described approach works, except that I have also

Code: Pascal  [Select][+][-]
  1. procedure HandleSigInt(aSignal: LongInt); cdecl;
  2. begin
  3.   Writeln('Calling terminate after SIGINT');
  4.   Application.Terminate();
  5.  
  6.   while (not Application.Terminated) do Sleep(1); // WAS MISSING, SORRY!!!
  7. end;
  8.  

but I also have to say that I have wrapped the http app into a thread separated by the main thread. And I Terminate the http app like showed before.

Maybe this is why it does not work for you.

FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

vangli

  • New Member
  • *
  • Posts: 46
Yes Чебурашка. It look like I has to create a separate thread like you describe. The while statement has no effect. Application.Terminate doesn't work because Application.Run is blocking, I think, in my oversimplified approach.  ::)
Regards Bent

vangli

  • New Member
  • *
  • Posts: 46
Found a workable way. Basically moved the exit information to the HandleSigInt procedure, and there calling Application.Terminate, which set Application.Terminated to True. Wait for the flag to be set, and then free the hole application Instance. And then write some exit information before Halt, and I am back to command line. Wonder if this method introduce some kind of Memory leakage.

Thks Чебурашка for your kind help.

Code: Pascal  [Select][+][-]
  1. program aWebServer;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$ifdef UNIX}
  7.   cthreads, cmem,
  8.   {$endif}
  9.   fphttpapp, httpdefs, httproute, sysutils, BaseUnix;
  10.  
  11. procedure HandleSigInt(aSignal: LongInt); cdecl;
  12. begin
  13.   Writeln(LineEnding,'Calling terminate after SIGINT');
  14.   Application.Terminate;
  15.   while not Application.Terminated do Sleep(10);
  16.   Application.FreeInstance;
  17.   writeln('Write some information when application ends....');
  18.   Halt(0);
  19. end;        
  20.  
  21. begin
  22.   if FpSignal(SigInt, @HandleSigInt) = signalhandler(SIG_ERR) then
  23.   begin
  24.     Writeln('Failed to install signal error: ', fpGetErrno);
  25.     Halt(1);
  26.   end;
  27.   Writeln('Starting application, press CTRL+C to terminate...');
  28.   try
  29.     Application.Port := 8081;
  30.     Application.Threaded := true;
  31.     Application.Initialize;
  32.     Application.Run;
  33.   finally
  34.     writeln('Error!');
  35.   end;
  36. end.          
Regards Bent

zen010101

  • Newbie
  • Posts: 4
It is a bug mentioned here:

https://gitlab.com/freepascal.org/fpc/source/-/issues/36741#original-reporter-info-from-mantis-luca-olivlucareporter-name-luca-olivetti

There is an ugly workaround:

Code: Pascal  [Select][+][-]
  1. procedure signalHandler(signum: cint); cdecl;
  2. begin
  3.     Raise Exception.Create('EXIT THE APPLICATION');
  4. end;
  5.  

Everything is working fine, but you might see an exception message pop up, no need to worry about any memory leaks.
« Last Edit: July 17, 2024, 08:43:14 pm by zen010101 »

 

TinyPortal © 2005-2018