Recent

Author Topic: Who knows function LCLIntf.AddProcessEventHandler() / get Access violation  (Read 4494 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 742
In http://wiki.freepascal.org/Main_Loop_Hooks#Pipes_and_Process_Termination I found some small infos about  function LCLIntf.AddProcessEventHandler(). There is written (abbreviated):

Quote
Pipes and Process Termination
To provide a cross-platform solution for ... processes ... additional functions have been added:

TChildExitReason = (cerExit, cerSignal);
 
TChildExitEvent = procedure(AData: PtrInt; AReason: TChildExitReason; AInfo: dword) of object;
 
function AddProcessEventHandler(AHandle: THandle; AEventHandler: TChildExitEvent; AData: PtrInt): PProcessEventHandler;

When a process terminates the event handler specified will be called. AInfo will contain the exit code if AReason is cerExit, or (on unix only) the termination signal if AReason is cerSignal. For gtk/unix, use the PID to watch as AHandle. Internally, a signal handler is installed to catch the SIGCHLD signal. On win32, AddEventHandler is used to watch process termination.

My question is: can this function be used to install an ExitProcedure which is called when my program is terminated because of the Operation System shuts down?

I use FPC 3.0.4 on Windows 7 and Ubuntu 18.04. Thanks in advance.
« Last Edit: January 19, 2019, 05:42:44 pm by Hartmut »

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #1 on: January 17, 2019, 12:50:07 pm »
This will always depend on the way an OS kills the running applications - as per the orginal thread.
E.g. Chromium on Debian has provisions for such code but never executes anyway, so next time you run it it wants to restore pages because the application was not properly closed.
So it is always a bit of hit and miss. On Windows there are less of such issues. This is not a FPC or Lazarus limitation but the OS itself.
Specialize a type, not a var.

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #2 on: January 17, 2019, 06:24:36 pm »
Thank you Thaddy for your reply. Did I understand you correctly, that:
 - whether it really works is OS dependant
 - on Windows there are less issues than other OS
 - but LCLIntf.AddProcessEventHandler() is generally able to install an ExitProcedure which is called also when my program is terminated because of the Operation System shuts down?

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #3 on: January 19, 2019, 02:57:07 pm »
I wanted to try if LCLIntf.AddProcessEventHandler() works on my Operating Systems and created that demo:
Code: Pascal  [Select][+][-]
  1. program test2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses InterfaceBase,LCLIntf; // need Package "LCLBase"
  6.  
  7. type
  8.    TMyClass = Class(TObject)
  9.    procedure ChildExitEvent(AData: PtrInt; AReason: TChildExitReason; AInfo: dword); // of object;
  10.    end;
  11.  
  12. procedure TMyClass.ChildExitEvent(AData: PtrInt; AReason: TChildExitReason; AInfo: dword);
  13.    {my Exit-Procedure: must be a method of a Class, because it's usage in
  14.     AddProcessEventHandler() is declared as "procedure ... of object"}
  15.    begin
  16.    writeln('ChildExitEvent: ', AData, ' ', AReason, ' ', AInfo);
  17.    end;
  18.  
  19. var MyClass: TMyClass;
  20.  
  21. procedure install_ExitProc;
  22.    const AData = 0;
  23.    var pPEH: PProcessEventHandler; {=pointer}
  24.        h: THandle;
  25.    begin
  26.    h:=system.GetProcessID; // gets PID of the running program
  27.    writeln('handle=', h);
  28.    pPEH:=AddProcessEventHandler(h, @MyClass.ChildExitEvent, AData);
  29.    end;
  30.  
  31. begin
  32. writeln('hello');
  33. MyClass:=TMyClass.Create;
  34. MyClass.ChildExitEvent(33,cerSignal,55); // only test if this method works
  35. install_ExitProc;
  36. readln;
  37. MyClass.Free;
  38. end.

It compiles with Lazarus 1.8.4 (FPC 3.0.4) but when I start it on Windows 7 (32 bit) I get:
Code: [Select]
An unhandled exception occurred at $00413F33:
EAccessViolation: Access violation
  $00413F33  ADDPROCESSEVENTHANDLER,  line 44 of ./include/lclintf.inc
  $0040180D  INSTALL_EXITPROC,  line 5779 of test2.pas
  $00401881  main,  line 35 of test2.pas 

On Linux (Ubuntu 18.04 64 bit) I get:
Code: [Select]
An unhandled exception occurred at $000000000043387D:
EAccessViolation: Access violation
  $000000000043387D line 44 of include/lclintf.inc
  $0000000000400DF0 line 28 of test2.pas
  $0000000000400E82 line 35 of test2.pas

Line 44 of include/lclintf.inc is:
Code: [Select]
function AddProcessEventHandler(AHandle: THandle; AEventHandler: TChildExitEvent;
  AData: PtrInt): PProcessEventHandler;
begin
  Result:=WidgetSet.AddProcessEventHandler(AHandle, AEventHandler, AData);
end;

I ran the program with the debugger, but that did not help me more. I tried older versions of Lazarus and FPC but got the same result, beside that FPC 2.6.4 says also "Runtime Error 210", which means "Object not initialized: When compiled with range checking on, a program will report this error if you call a virtual method without having called its object's constructor". But as far as I can see, the only object is MyClass and that is initialized...

I attached my little demo project. Can please anybody help to avoid the Access violation?

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #4 on: January 19, 2019, 03:25:24 pm »
Code: Pascal  [Select][+][-]
  1. begin
  2. writeln('hello');
  3. MyClass:=TMyClass.Create;
  4. install_ExitProc; //needs to be first after create!!!
  5. MyClass.ChildExitEvent(33,cerSignal,55); // otherwise there is no chance this method works
  6. readln;
  7. MyClass.Free;
  8. end.
There's more wrong, but this compiles in your *very old* Lazarus.
« Last Edit: January 19, 2019, 03:27:22 pm by Thaddy »
Specialize a type, not a var.

BeniBela

  • Hero Member
  • *****
  • Posts: 905
    • homepage
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #5 on: January 19, 2019, 03:33:03 pm »
By the way, is there some function to be notified about ending threads ?

Thaddy

  • Hero Member
  • *****
  • Posts: 14197
  • Probably until I exterminate Putin.
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #6 on: January 19, 2019, 03:35:20 pm »
WaitFor?...... <silly question> <grumpy  >:D >:D >

In the context of the original topic there are several ways to terminate a process gracefully by the OS. Usually.
Problem is Windows adheres to that, many *xes don't. The latter ones just kill....As if they were gamers..... :D :D :D
« Last Edit: January 19, 2019, 03:41:50 pm by Thaddy »
Specialize a type, not a var.

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Who knows function LCLIntf.AddProcessEventHandler() ?
« Reply #7 on: January 19, 2019, 05:41:28 pm »
Hello Thaddy, thanks for your help. I applied your correction, but at runtime I get the same Access violation (see above) than before. What do I wrong?

There's more wrong, but this compiles in your *very old* Lazarus.

If you see more mistakes, please let me know. I want this code get to work and to learn.
I use normally Lazarus 1.8.4 with FPC 3.0.4. Is this "too old" for this purpose?

jamie

  • Hero Member
  • *****
  • Posts: 6090
I am looking at the code in the Win32lclintf.inc

Code: Pascal  [Select][+][-]
  1. function TWin32WidgetSet.AddProcessEventHandler(AHandle: THandle;
  2.   AEventHandler: TChildExitEvent; AData: PtrInt): PProcessEventHandler;
  3. var
  4.   lProcessEvent: PProcessEvent;
  5. begin
  6.   if AEventHandler = nil then exit(nil);
  7.   New(lProcessEvent);
  8.   lProcessEvent^.Handle := AHandle;
  9.   lProcessEvent^.UserData := AData;
  10.   lProcessEvent^.OnEvent := AEventHandler;
  11.   lProcessEvent^.Handler := AddEventHandler(AHandle, 0,
  12.     @HandleProcessEvent, PtrInt(lProcessEvent)); // << Casting a pointer to a signed Int64 to be reference later
  13.   Result := lProcessEvent;
  14. end;                                    
  15.  
  16. Could it be the Address is getting above the 2G  for 32 bit targets?
  17. Maybe we should be using PtrUint instead which is a QWORD under the 64bit target.
  18.  

Just something I noticed.
The only true wisdom is knowing you know nothing

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Thank you jamie that you want to help me. Do you want to say this might be a bug?
I tried to check which value pointers in my program really have and extended my code a little:

Code: Pascal  [Select][+][-]
  1. var p: ^word;
  2. begin
  3. writeln('hello');
  4. new(p);
  5. writeln('p=', PtrInt(p)); // show the value of an example pointer
  6. dispose(p);
  7.  
  8. MyClass:=TMyClass.Create;
  9. install_ExitProc;
  10. MyClass.ChildExitEvent(33,cerSignal,55);
  11. readln;
  12. MyClass.Free;
  13. end.

The result with FPC 3.0.4 on Windows 7, 32 bit was:
Code: [Select]
hello
p=1776792
handle=5444
An unhandled exception occurred at $00413F83:
EAccessViolation: Access violation
  $00413F83  ADDPROCESSEVENTHANDLER,  line 44 of ./include/lclintf.inc
  $0040180D  INSTALL_EXITPROC,  line 5779 of test2.pas
  $004018C4  main,  line 42 of test2.pas

So for me it does not look like the address of pointers are > 2 GB (in my case). So even if there might be your bug, I don't believe that this can be the reason for my Access violation. What do you think?

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Who knows function LCLIntf.AddProcessEventHandler() / get Access violation
« Reply #10 on: January 25, 2019, 05:16:13 pm »
When I try to debug the Access violation (see reply #3) then I see, that I can't go into Line 44 of include/lclintf.inc, because then the Access violation immediately occurs. Line 44 is:
Code: Pascal  [Select][+][-]
  1. Result:=WidgetSet.AddProcessEventHandler(AHandle, AEventHandler, AData);
That let's me think that there might be a problem with this call itself. The only parameter which could be wrong is 'AEventHandler: TChildExitEvent'.

It should be declared as (see my 1. post):
TChildExitEvent = procedure(AData: PtrInt; AReason: TChildExitReason; AInfo: dword) of object;
But I have declared it as
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyClass = Class(TObject)
  3.   procedure ChildExitEvent(AData: PtrInt; AReason: TChildExitReason; AInfo: dword);
  4.   end;

That means, I dont't have "of object" at the end of my declaration, because the compiler doesn't accept this. Could this be the reason for the Access violation? Does somebody know, how I must declare my procedure ChildExitEvent?

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Who knows function LCLIntf.AddProcessEventHandler() / get Access violation
« Reply #11 on: January 25, 2019, 06:11:08 pm »
That means, I dont't have "of object" at the end of my declaration, because the compiler doesn't accept this. Could this be the reason for the Access violation? Does somebody know, how I must declare my procedure ChildExitEvent?

The "of object" simply means that the type represents a method of an object, not a free-standing procedure/function, so it needs to be declared as a method of a class, just as you have it.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Hartmut

  • Hero Member
  • *****
  • Posts: 742
Re: Who knows function LCLIntf.AddProcessEventHandler() / get Access violation
« Reply #12 on: January 27, 2019, 11:50:22 am »
Thank you lucamar for your reply. Again I learned something.

 

TinyPortal © 2005-2018