Recent

Author Topic: Events not working (in daemon program Linux)  (Read 9195 times)

mrplumber

  • New member
  • *
  • Posts: 8
Events not working (in daemon program Linux)
« on: August 19, 2015, 02:59:53 am »
Hello,

I have problem with EventMonitor and OnFBEvent (procedure writing messages in log triggered by events) implemented in code below - I don't get any information about Firebird events occuring. Procedures I'm using are identical to Wikipedia example http://wiki.freepascal.org/TFBEventMonitor and working without any problems in GUI, same as database and triggers in both projects (7 days of finding bug).
Any ideas?

Code: [Select]
Program Daemon;

{$mode objfpc}{$H+}

uses
  {$DEFINE UseCThreads}
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  SysUtils, BaseUnix, sqldb, IBConnection, FBEventMonitor;

{ TMyEventAlert }                        {c}
type
  TMyEventAlert=class
class procedure OnFBEvent(Sender: TObject; EventName: string; EventCount: longint;
 var CancelAlerts: boolean);
end;

Var
   { vars for daemonizing }
   bHup,
   bTerm : boolean;
   textPolaczenia, textZdarzenia, config : text;
   SlogPolaczenia, SlogZdarzenia,  nazwaHosta, sciezkaBazaDanych, uzytkownik, haslo: string;

   aOld,
   aTerm,
   aHup : pSigActionRec;
   ps1  : psigset;
   sSet : cardinal;
   pid  : pid_t;
   secs : longint;

   zerosigs : sigset_t;
   EventAlert : TMyEventAlert;
   EventsM :TFBEventMonitor;
   //EventAlert: TMyEventAlert;
   BConnection : TIBConnection;
   SQLQuery1: TSQLQuery;
   SQLTransaction1: TSQLTransaction;


   { handle SIGHUP & SIGTERM }
   procedure DoSig(sig : longint);cdecl;
   begin
      case sig of
         SIGHUP : bHup := true;
         SIGTERM : bTerm := true;
      end;
   end;



class procedure TMyEventAlert.OnFBEvent(Sender: TObject; EventName: string;
   EventCount: longint; var CancelAlerts: boolean);
   begin
     //some basic do's
     SlogZdarzenia := 'SlogZdarzenia.log';
     AssignFile(textZdarzenia,SlogZdarzenia);
     Rewrite(textZdarzenia);
     Writeln(textZdarzenia,'Cos sie zdarzylo');
     CloseFile(textZdarzenia);
     end;


Procedure WpisPolaczenie;
Begin
   AssignFile(textPolaczenia,SLogPolaczenia);
   Append(textPolaczenia);
   Writeln(textPolaczenia,'Connected to database at ',formatdatetime('hh:nn:ss',now));
   CloseFile(textPolaczenia);
End;

procedure CreateConnection;

   begin
      BConnection := TIBConnection.Create(nil);


      BConnection.DataBaseName := '/home/pi/bazydanych/aaa';
      BConnection.Hostname := 'localhost';
      BConnection.UserName:='sysdba';
      BConnection.Password:='masterkey';


      EventsM:=TFBEventMonitor.create(nil);
      EventsM.Connection:=BConnection;
      EventsM.Events.Add('baba');
      EventsM.OnEventAlert:=@EventAlert.OnFBEvent;
      EventsM.RegisterEvents;



Begin

   SlogPolaczenia := 'SlogPolaczenia.log';                        {setting up 'connection variables'}
   SlogZdarzenia:= 'SlogZdarzenia.log';
   secs := 15;


   fpsigemptyset(zerosigs);

   { set global daemon booleans }
      bHup := true; { to open log file }
      bTerm := false;

      { block all signals except -HUP & -TERM }
      sSet := $ffffbffe;
      ps1 := @sSet;
      fpsigprocmask(sig_block,ps1,nil);

      { setup the signal handlers }
      new(aOld);
      new(aHup);
      new(aTerm);
      aTerm^.sa_handler{.sh} := SigactionHandler(@DoSig);

      aTerm^.sa_mask := zerosigs;
      aTerm^.sa_flags := 0;
      {$ifndef BSD}                {Linux'ism}
       aTerm^.sa_restorer := nil;
      {$endif}
      aHup^.sa_handler := SigactionHandler(@DoSig);
      aHup^.sa_mask := zerosigs;
      aHup^.sa_flags := 0;
      {$ifndef BSD}                {Linux'ism}
       aHup^.sa_restorer := nil;
      {$endif}
      fpSigAction(SIGTERM,aTerm,aOld);
      fpSigAction(SIGHUP,aHup,aOld);

      { daemonize }
      pid := fpFork;
      Case pid of
         0 : Begin { we are in the child }
            Close(input);  { close standard in }
            Close(output); { close standard out }
            Assign(output,'/dev/null');
            ReWrite(output);
            Close(stderr); { close standard error }
            Assign(stderr,'/dev/null');
            ReWrite(stderr);
         End;
         -1 : secs := 0;     { forking error, so run as non-daemon }
         Else Halt;          { successful fork, so parent dies }
      End;

      { begin processing loop }
      Repeat
         If bHup Then Begin
            {$I-}
            Close(textPolaczenia);
            {$I+}
            IOResult;
         {$I+}
          //UtworzLogi;
         {fggggggd}

         bHup := false;
      End;
      {----------------------}
                                               {'program' part of a daemon}
      CreateConnection;



      {----------------------}
      If bTerm Then
         BREAK
      Else
         { wait a while }
         fpSelect(0,nil,nil,nil,secs*1000);
   Until bTerm;
   End.

tail -f SlogPolaczenie.log // activity log
tail -f SlogEvents.log // events log
ps ax | grep nameofaprogram
kill -TERM processIDListedafterPsAXGrepNameoOfAprogram

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #1 on: August 19, 2015, 12:12:59 pm »
Are you sure your program compiles correctly ?

You have really strange block indentation.
This is your source correctly indented:

Code: [Select]
Program Daemon;

{$mode objfpc}{$H+}

uses
{$DEFINE UseCThreads}
{$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
{$ENDIF}{$ENDIF}
  SysUtils, BaseUnix, sqldb, IBConnection, FBEventMonitor;

{ TMyEventAlert }                        { c }
type
  TMyEventAlert = class
    class procedure OnFBEvent(Sender: TObject; EventName: string; EventCount: longint;
      var CancelAlerts: boolean);
  end;

var
  { vars for daemonizing }
  bHup,
    bTerm: boolean;
  textPolaczenia, textZdarzenia, config: text;
  SlogPolaczenia, SlogZdarzenia, nazwaHosta, sciezkaBazaDanych, uzytkownik, haslo: string;

  aOld,
    aTerm,
    aHup: pSigActionRec;
  ps1: psigset;
  sSet: cardinal;
  pid: pid_t;
  secs: longint;

  zerosigs: sigset_t;
  EventAlert: TMyEventAlert;
  EventsM: TFBEventMonitor;
  // EventAlert: TMyEventAlert;
  BConnection: TIBConnection;
  SQLQuery1: TSQLQuery;
  SQLTransaction1: TSQLTransaction;

  { handle SIGHUP & SIGTERM }
procedure DoSig(sig: longint); cdecl;
begin
  case sig of
    SIGHUP: bHup := true;
    SIGTERM: bTerm := true;
  end;
end;

class procedure TMyEventAlert.OnFBEvent(Sender: TObject; EventName: string;
  EventCount: longint; var CancelAlerts: boolean);
begin
  // some basic do's
  SlogZdarzenia := 'SlogZdarzenia.log';
  AssignFile(textZdarzenia, SlogZdarzenia);
  Rewrite(textZdarzenia);
  Writeln(textZdarzenia, 'Cos sie zdarzylo');
  CloseFile(textZdarzenia);
end;

procedure WpisPolaczenie;
begin
  AssignFile(textPolaczenia, SlogPolaczenia);
  Append(textPolaczenia);
  Writeln(textPolaczenia, 'Connected to database at ', formatdatetime('hh:nn:ss', now));
  CloseFile(textPolaczenia);
end;

procedure CreateConnection;
begin
  BConnection := TIBConnection.Create(nil);

  BConnection.DataBaseName := '/home/pi/bazydanych/aaa';
  BConnection.Hostname := 'localhost';
  BConnection.UserName := 'sysdba';
  BConnection.Password := 'masterkey';

  EventsM := TFBEventMonitor.Create(nil);
  EventsM.Connection := BConnection;
  EventsM.Events.Add('baba');
  EventsM.OnEventAlert := @EventAlert.OnFBEvent;
  EventsM.RegisterEvents;

  begin

    SlogPolaczenia := 'SlogPolaczenia.log'; { setting up 'connection variables' }
    SlogZdarzenia := 'SlogZdarzenia.log';
    secs := 15;

    fpsigemptyset(zerosigs);

    { set global daemon booleans }
    bHup := true; { to open log file }
    bTerm := false;

    { block all signals except -HUP & -TERM }
    sSet := $FFFFBFFE;
    ps1 := @sSet;
    fpsigprocmask(sig_block, ps1, nil);

    { setup the signal handlers }
    new(aOld);
    new(aHup);
    new(aTerm);
    aTerm^.sa_handler { .sh } := SigactionHandler(@DoSig);

    aTerm^.sa_mask := zerosigs;
    aTerm^.sa_flags := 0;
{$IFNDEF BSD}                { Linux'ism }
    aTerm^.sa_restorer := nil;
{$ENDIF}
    aHup^.sa_handler := SigactionHandler(@DoSig);
    aHup^.sa_mask := zerosigs;
    aHup^.sa_flags := 0;
{$IFNDEF BSD}                { Linux'ism }
    aHup^.sa_restorer := nil;
{$ENDIF}
    fpSigAction(SIGTERM, aTerm, aOld);
    fpSigAction(SIGHUP, aHup, aOld);

    { daemonize }
    pid := fpFork;
    case pid of
      0:
        begin { we are in the child }
          Close(input); { close standard in }
          Close(output); { close standard out }
          Assign(output, '/dev/null');
          Rewrite(output);
          Close(stderr); { close standard error }
          Assign(stderr, '/dev/null');
          Rewrite(stderr);
        end;
      -1: secs := 0; { forking error, so run as non-daemon }
    Else Halt; { successful fork, so parent dies }
    end;

    { begin processing loop }
    Repeat
      If bHup Then
      begin
{$I-}
        Close(textPolaczenia);
{$I+}
        IOResult;
{$I+}
        // UtworzLogi;
        { fggggggd }

        bHup := false;
      end;
      { ---------------------- }
      { 'program' part of a daemon }
      CreateConnection;

      { ---------------------- }
      If bTerm Then
          BREAK
      Else
        { wait a while }
          fpSelect(0, nil, nil, nil, secs * 1000);
    Until bTerm;

end.

Am I missing an "end;" after the line "EventsM.RegisterEvents;" ?????

And when and how are you triggering the POST_EVENT 'baba' in your database ?

And are you sure you want CreateConnection in the repeat loop ??

Also... you do a Rewrite(textZdarzenia); in your OnFBEvent. So the logfile keeps getting overwritten.

« Last Edit: August 19, 2015, 12:18:21 pm by rvk »

mrplumber

  • New member
  • *
  • Posts: 8
Re: Events not working (in daemon program Linux)
« Reply #2 on: August 19, 2015, 03:50:55 pm »
Hello rvk,

thank you for for pointing missing 'end' - I've deleted some procedures/functions I don't use from main code to post it here.
I'm posting 'baba' event after connection|insert|update Firebird database/table. In GUI version it works without any problems, database, table, triggers are the same.
Yes, as far as- I know, the connection should be 're-estabilished' after some period of time, usually few hours, in some cases (router issues) it can be only be few minutes.
Updated code (compiling, activity written to log, events not working):

Code: [Select]
Program zeStacka;

{$mode objfpc}{$H+}

uses
{$DEFINE UseCThreads}
{$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
{$ENDIF}{$ENDIF}
  SysUtils, BaseUnix, sqldb, IBConnection, FBEventMonitor;

{ TMyEventAlert }                        { c }
type
  TMyEventAlert = class
    class procedure OnFBEvent(Sender: TObject; EventName: string; EventCount: longint;
      var CancelAlerts: boolean);
  end;

var
  { vars for daemonizing }
  bHup,
    bTerm: boolean;
  textPolaczenia, textZdarzenia, config: text;
  SlogPolaczenia, SlogZdarzenia, nazwaHosta, sciezkaBazaDanych, uzytkownik, haslo: string;

  aOld,
    aTerm,
    aHup: pSigActionRec;
  ps1: psigset;
  sSet: cardinal;
  pid: pid_t;
  secs: longint;

  zerosigs: sigset_t;
  EventAlert: TMyEventAlert;
  EventsM: TFBEventMonitor;
  BConnection: TIBConnection;
  SQLQuery1: TSQLQuery;
  SQLTransaction1: TSQLTransaction;

  { handle SIGHUP & SIGTERM }
procedure DoSig(sig: longint); cdecl;
begin
  case sig of
    SIGHUP: bHup := true;
    SIGTERM: bTerm := true;
  end;
end;

class procedure TMyEventAlert.OnFBEvent(Sender: TObject; EventName: string;
  EventCount: longint; var CancelAlerts: boolean);
begin
  // some basic do's
  SlogZdarzenia := 'SlogZdarzenia.log';
  AssignFile(textZdarzenia, SlogZdarzenia);
  Rewrite(textZdarzenia);
  Writeln(textZdarzenia, 'Cos sie zdarzylo');
  CloseFile(textZdarzenia);
end;

procedure WpisPolaczenie;
begin
  SlogPolaczenia := 'SlogPolaczenia.log';
  AssignFile(textPolaczenia, SlogPolaczenia);
  Append(textPolaczenia);
  Writeln(textPolaczenia, 'Connected to database at ', formatdatetime('hh:nn:ss', now));
  CloseFile(textPolaczenia);
end;

procedure CreateConnection;
begin
  BConnection := TIBConnection.Create(nil);

  BConnection.DataBaseName := '/home/pi/bazydanych/aaa';
  BConnection.Hostname := 'localhost';
  BConnection.UserName := 'sysdba';
  BConnection.Password := 'masterkey';

  EventsM := TFBEventMonitor.Create(nil);
  EventsM.Connection := BConnection;
  EventsM.Events.Add('baba');
  EventsM.OnEventAlert := @EventAlert.OnFBEvent;
  EventsM.RegisterEvents;
  end;

  begin

    secs := 15;

    fpsigemptyset(zerosigs);

    { set global daemon booleans }
    bHup := true; { to open log file }
    bTerm := false;

    { block all signals except -HUP & -TERM }
    sSet := $FFFFBFFE;
    ps1 := @sSet;
    fpsigprocmask(sig_block, ps1, nil);

    { setup the signal handlers }
    new(aOld);
    new(aHup);
    new(aTerm);
    aTerm^.sa_handler { .sh } := SigactionHandler(@DoSig);

    aTerm^.sa_mask := zerosigs;
    aTerm^.sa_flags := 0;
{$IFNDEF BSD}                { Linux'ism }
    aTerm^.sa_restorer := nil;
{$ENDIF}
    aHup^.sa_handler := SigactionHandler(@DoSig);
    aHup^.sa_mask := zerosigs;
    aHup^.sa_flags := 0;
{$IFNDEF BSD}                { Linux'ism }
    aHup^.sa_restorer := nil;
{$ENDIF}
    fpSigAction(SIGTERM, aTerm, aOld);
    fpSigAction(SIGHUP, aHup, aOld);

    { daemonize }
    pid := fpFork;
    case pid of
      0:
        begin { we are in the child }
          Close(input); { close standard in }
          Close(output); { close standard out }
          Assign(output, '/dev/null');
          Rewrite(output);
          Close(stderr); { close standard error }
          Assign(stderr, '/dev/null');
          Rewrite(stderr);
        end;
      -1: secs := 0; { forking error, so run as non-daemon }
    Else Halt; { successful fork, so parent dies }
    end;

    { begin processing loop }
    Repeat
      If bHup Then
      begin
{$I-}
        Close(textPolaczenia);
{$I+}
        IOResult;
{$I+}
        // UtworzLogi;
        { fggggggd }

        bHup := false;
      end;
      { ---------------------- }
      { 'program' part of a daemon }
      CreateConnection;
      WpisPolaczenie;

      { ---------------------- }
      If bTerm Then
          BREAK
      Else
        { wait a while }
          fpSelect(0, nil, nil, nil, secs * 1000);
    Until bTerm;

end.

unfortunately, program can't make logFiles (SlogPolaczenie.log and SlogEvents.log), I have to create them manually in a project folder.

tail -f SlogPolaczenie.log // activity log
tail -f SlogEvents.log // events log
ps ax | grep nameofaprogram (here: zeStacka)
kill -TERM processIDListedafterPsAXGrepNameoOfAprogram

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #3 on: August 19, 2015, 04:41:27 pm »
Although I'm not completly sure about the deamon stuff I think I can help you with some pointers about the rest. (I have a simpler version working here)

First off all your remark:
unfortunately, program can't make logFiles (SlogPolaczenie.log and SlogEvents.log), I have to create them manually in a project folder.
You're program can create the logfiles if you use the correct commands:
I.e.
Code: [Select]
    AssignFile(textZdarzenia, SlogZdarzenia);
    if FileExists(SlogZdarzenia) then
      Append(textZdarzenia)
    else
      Rewrite(textZdarzenia);
    Writeln(textZdarzenia, 'Cos sie zdarzylo');
    CloseFile(textZdarzenia);
It will append if the log-file already exists and create a new one if it does not exist.
I did a deletefile() at the beginning so you start with a clean logfile.

Second, you create a new connection and event monitor every 15 seconds.... while you keep the OLD one active. So it's best before doing a new CreateConnection you destroy the old one (including the monitoring). I would increase the 15 seconds but I guess that's just for testing.

The code below worked for me while doing this in a script editor in IBExpert while connected to the database: (I removed the deamon stuff and ran this in the Lazarus-IDE)
Code: [Select]
EXECUTE BLOCK
AS
BEGIN
  post_event 'baba';
END

Code: [Select]
program zeStacka;

{$mode objfpc}{$H+}

uses {$DEFINE UseCThreads} {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  SysUtils,
  BaseUnix,
  sqldb,
  IBConnection,
  FBEventMonitor;

{ TMyEventAlert }{ c }
type
  TMyEventAlert = class
    class procedure OnFBEvent(Sender: TObject; EventName: string;
      EventCount: longint; var CancelAlerts: boolean);
  end;

var
  { vars for daemonizing }
  textPolaczenia, textZdarzenia: Text;
  SlogPolaczenia, SlogZdarzenia: string;
  secs: longint;

  EventAlert: TMyEventAlert;
  EventsM: TFBEventMonitor;
  BConnection: TIBConnection;

  class procedure TMyEventAlert.OnFBEvent(Sender: TObject; EventName: string;
    EventCount: longint; var CancelAlerts: boolean);
  begin
    // some basic do's
    SlogZdarzenia := 'SlogZdarzenia.log';
    AssignFile(textZdarzenia, SlogZdarzenia);
    if FileExists(SlogZdarzenia) then
      Append(textZdarzenia)
    else
      Rewrite(textZdarzenia);
    Writeln(textZdarzenia, 'Cos sie zdarzylo');
    CloseFile(textZdarzenia);
  end;

  procedure WpisPolaczenie;
  begin
    SlogPolaczenia := 'SlogPolaczenia.log';
    AssignFile(textPolaczenia, SlogPolaczenia);
    if FileExists(SlogPolaczenia) then
      Append(textPolaczenia)
    else
      Rewrite(textPolaczenia);
    Writeln(textPolaczenia, 'Connected to database at ',
      formatdatetime('hh:nn:ss', now));
    CloseFile(textPolaczenia);
  end;

  procedure CreateConnection;
  begin
    BConnection := TIBConnection.Create(nil);
    BConnection.DataBaseName := '/home/pi/bazydanych/aaa';
    BConnection.Hostname := 'localhost';
    BConnection.UserName := 'sysdba';
    BConnection.Password := 'masterkey';
    // BConnection.Connected := True; // <-- not needed (?)

    EventsM := TFBEventMonitor.Create(nil);
    EventsM.Connection := BConnection;
    EventsM.Events.Add('baba');
    EventsM.OnEventAlert := @EventAlert.OnFBEvent;
    EventsM.RegisterEvents;
  end;

begin

  DeleteFile('SlogZdarzenia.log');
  DeleteFile('SlogPolaczenia.log');
  BConnection := nil; // <-- reset the variable at nil
  secs := 15;

  { begin processing loop }
  repeat
    if BConnection <> nil then
    begin
      // if BConnection was <> we need to destroy the EventMonitor and BConnection
      // before creating a new one
      EventsM.UnRegisterEvents;
      FreeAndNil(EventsM);
      FreeAndNil(BConnection);
    end;

    CreateConnection;
    WpisPolaczenie;

    { wait a while }
    fpSelect(0, nil, nil, nil, secs * 1000);

  until False;

end.

mrplumber

  • New member
  • *
  • Posts: 8
Re: Events not working (in daemon program Linux)
« Reply #4 on: August 19, 2015, 08:07:04 pm »
Whoa, thank you rvk!

It seems that your fixes solved bigger part of a problem- EventMonitor register events, but they appear only after when a 'child' becomes forked - so maximum delay between an event and onEventProcedure is 'secs' value. Do you hava any ideas why it became so?

ttomas

  • Full Member
  • ***
  • Posts: 245
Re: Events not working (in daemon program Linux)
« Reply #5 on: August 19, 2015, 10:46:07 pm »
I don't know if this is related! I have a problem with TThread.Syncronize in daemon. This is not resolved bug in FPC. Syncronize in GUI and Console works fine but not in daemon. More  info
http://forum.lazarus.freepascal.org/index.php/topic,21152.msg182508.html#msg182508
TFBEventsThread use Syncronize for events.
I resolve my problem with UIB component and TUIBEvents.SyncMainThread:=False;
OnEvent just signal my working thread where i do all the work and never use Syncronize in daemon. I use Windows service (daemon) and don't know if Linux work OK.

mrplumber

  • New member
  • *
  • Posts: 8
Re: Events not working (in daemon program Linux)
« Reply #6 on: August 20, 2015, 12:01:46 am »
Hello ttomas, thank you for your reply, but I cannot find any method likie syncronize in Linux-like cthread unit. FBEvent also doesnt't have any method similar to syncMainThread unfortunately.

ttomas

  • Full Member
  • ***
  • Posts: 245
Re: Events not working (in daemon program Linux)
« Reply #7 on: August 20, 2015, 12:33:42 am »
Hello ttomas, thank you for your reply, but I cannot find any method likie syncronize in Linux-like cthread unit. FBEvent also doesnt't have any method similar to syncMainThread unfortunately.
Fbervent use thread for events, in execute method use synchronize for onevent execution.
Syncmainthread is property in Uib event componet (unified interbase componet).
http://sourceforge.net/projects/uib/
« Last Edit: August 20, 2015, 12:43:11 am by ttomas »

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #8 on: August 20, 2015, 04:56:55 pm »
Mmmm, as far as I can see the event doesn't need to call Synchronize because it doesn't do anything with a GUI and doesn't need to use anything from the main thread. It just needs to write to a file (which it opens and closed), standalone.

I'm wondering if a forked process (with fpfork) can create and use new threads. Does the cthreads create a ("dummy"-)thread on startup? When using fpfork only the current thread/process is cloned so maybe the facilities to call/create a new thread are not present anymore in that cloned process.

http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

Maybe the thread-initialization needs to be done again after forking?
(because the fork/child continues execution at the moment of fpFork and the initialization of threading could be lost?)


Edit: Nope, it's not that either. TThread seems to be working fine in a forked process.

(you see i'm a newbie with threads and forking on linux :))
« Last Edit: August 20, 2015, 05:06:25 pm by rvk »

mrplumber

  • New member
  • *
  • Posts: 8
Re: Events not working (in daemon program Linux)
« Reply #9 on: August 20, 2015, 11:20:54 pm »
@rvk
Same as me, so unfortunately I can't say if it has the possibility of creating new thread in this case:) I may be wrong, but as I have read FBEvents unit's code it seems to be a forking function assigned to 'listening' thread. Interesting that listener acts just like a normal function in deamon (doesn't crash despite being unable to create thread(?)).

@ttomas:
Thank you for an idea, I will check it out soon, after handling Lazarus's error on installing any units (v.1.4.2).
« Last Edit: August 20, 2015, 11:24:13 pm by mrplumber »

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #10 on: August 20, 2015, 11:53:23 pm »
With my limited knowledge about this... I've have the following feeling:

Forking and threading are two different things.
FBEvents uses a thread where events are captured. When an event is captured it calls the OnFBEvent in your main thread. For this it uses Synchronize() (I checked). But... my feeling is that it calls the mainthread that's already terminated because you forked the main-process/thread to another.

Or does forking mean the thread itself is exactly the same? (maybe someone with forking knowledge can shed some light on that)

I'll try to create a simple forking example with a thread calling a main thread-procedure with sync() and see if that works. (tomorrow)

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #11 on: August 21, 2015, 10:28:23 am »
Okay, I've found the problem (after some quick learning about threads, forks etc... :))

You have a TFBEventMonitor which creates a thread. In that thread Synchronize is called to execute a procedure. But this needs to Synchronize with the main thread. In a LCL-application (or VCL on Delphi) this is not so much of a problem. But you have a console program which, in its loop, does basically nothing. No check on the running thread, nothing.

The solution is really simple. You have a loop where you check something with fpSelect (not sure what, I didn't come that far :)). But when you replace the fpSelect with a CheckSynchronize; it all works. The TMyEventAlert.OnFBEvent is called at the proper interval and the logfile gets written to.

I would place the CreateConnection; WpisPolaczenie; outside the loop and make the delay (sleep) smaller. So small as you want you'r program to react to the alert.

(If you want you could do the CreateConnection at some specific interval inside the loop but you need a second counter-variable for that.

This worked for me:
Code: [Select]
  CreateConnection;
  WpisPolaczenie;

  { begin processing loop }
  repeat
    { ---------------------- }
    { 'program' part of a daemon }
    { ---------------------- }

    Sleep(1000);
    CheckSynchronize; // <-- this does the magic for allowing the thread to synchronize it's procedure.

    //if not bTerm then { wait a while }
    //  fpSelect(0, nil, nil, nil, secs * 1000);

  until bTerm;

You need to adjust it a bit to include the bTerm again, but basically this would work (I tested it on Linux).

mrplumber

  • New member
  • *
  • Posts: 8
Re: Events not working (in daemon program Linux)
« Reply #12 on: August 22, 2015, 10:05:39 am »
I don't know what to say rvk!

I have also spent some time on that, but I haven't got such good idea as you did:) Does it mean that main thread was 'suspended' for the rest of period of time between two procedures and fpSelect?
Yeah, I will add counter to re-establish the connection to avoid 'silent disconnection'.

Thank you once again for your time and help rvk:)

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Events not working (in daemon program Linux)
« Reply #13 on: August 22, 2015, 10:47:31 am »
Does it mean that main thread was 'suspended' for the rest of period of time between two procedures and fpSelect?
The main thread is only suspended in the sleep function. Not sure if the fpSelect (Select in Linux) also suspends the thread. I'm also not sure what's better in this case. Using Sleep() or fpSelect(). There are a lot of discussions about this on the net but I haven't found a real downside to Sleep() only that it's not as accurate, but when talking about seconds it might not matter.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Events not working (in daemon program Linux)
« Reply #14 on: August 22, 2015, 02:49:56 pm »
You can pass some filedescriptor to select and use that to abort the sleep, lowering latency if something must be done.

Just like you would add an event to waitmultiple on Windows.

 

TinyPortal © 2005-2018