lazdaemon, systemd does not see the correct exit code lazarus / 32-Linux ---------------------------------------------------------------------- bhaugland · 2019-12-28 16:29 I've been playing around with lazdaemon and ran across a problem under linux. For some reason when I issue a stop command from systemctl to my service the service sees the SIGTERM and exits.  I force a exit code of 0. However systemd is not seeing the exit code or is ignoring it and issues a sigkill after a timeout period. I'm having a hard time seeing if my program is truly exiting or if somehow systemd is actually seeing a different exit code. Has anyone seen anything similar? ---------------------------------------------------------------------- lucamar · 2019-12-28 17:02 I don't know about daemons but normal FP/Lazarus programs see neither sig_term or sig_kill; the system just force-shuts them down. ---------------------------------------------------------------------- guest65233 · 2020-02-12 19:08 I saw a web page that detailed how to write a linux daemon with free pascal http://www.cncware.com/ The website reads "Copyright CnCWare" and states "This is a functional program that can be run and observed. Then simply modify it to suit your own specific requirements". Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {---------- -----------------------------------------------------------------                               CncWare                           (c) Copyright 2000 ------------------------------------------------------- --------------------  Filename..: daemon.pp  Programmer: Ken J. Wright  Date......: 03/21/2000   Purpose - Program to demonstrate construction of a Linux daemon.   Usage:    1) Compile this program.  2) Run it. You will be immediately returned to a command prompt.    3) Issue the command: ps ax|grep daemon. This will show you the process       id of the program "daemon" that you just ran.    4) Issue the command: tail -f daemon.log. This let's you watch the log file       being filled with the message in the code below. Press Ctrl/c to break       out of the tail command.    5) Issue the command: kill -HUP pid. pid is the process number you saw with       the ps command above. You will see that a new log file has been created.    6) Issue the command: kill -TERM pid. This will stop the daemon. Issuing the       ps command above, you will see that the daemon is no longer running. -------------------------------<< REVISIONS >>--------------------------------  Ver  |    Date    | Prog | Decription-------+------------+------+------------------------------ --------------------  1.00 | 03/21/2000 | kjw  | Initial release.  1.01 | 03/21/2000 | kjw  | Forgot to close input, output, & stderr.--- ---------------------------------------------------------------------- -----}Program Daemon;uses SysUtils,BaseUnix;Var   { vars for daemonizing }   bHup,   bTerm : boolean;   fLog : text;   logname : string;   aOld,   aTerm,   aHup : pSigActionRec;   ps1  : psigset;   sSet : cardinal;   pid  : pid_t;   secs : longint;   zerosigs : sigset_t;   hr,mn,sc,sc100 : word; { handle SIGHUP & SIGTERM }procedure DoSig(sig : longint);cdecl;begin   case sig of      SIGHUP : bHup := true;      SIGTERM : bTerm := true;   end;end; { open the log file }Procedure NewLog;Begin   Assign(fLog,logname);   Rewrite(fLog);   Writeln(flog,'Log created at ',formatdatetime('hh:nn:ss',now));   Close(fLog);End; Begin   logname := 'daemon.log';   secs := 10;   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(fLog);         {$I+}         IOResult;         NewLog;         bHup := false;      End;      {----------------------}      { Do your daemon stuff }      Append(flog);      Writeln(flog,'daemon code activated at ',formatdatetime('hh:nn:ss',now));      Close(fLog);    { the following output goes to the bit bucket }      Writeln('daemon code activated at ',hr:0,':',mn:0,':',sc:0);      {----------------------}      If bTerm Then         BREAK      Else       { wait a while }         fpSelect(0,nil,nil,nil,secs*1000);   Until bTerm;End. ---------------------------------------------------------------------- lucamar · 2020-02-12 19:32 cdesim, please, see the wiki page about the Forum to learn how best to share code in the forum. Thanks ---------------------------------------------------------------------- Renat.Su · 2020-02-12 20:48 Quote from: bhaugland on December 28, 2019, 05:29:07 pmI've been playing around with lazdaemon and ran across a problem under linux. For some reason when I issue a stop command from systemctl to my service the service sees the SIGTERM and exits.  I force a exit code of 0. However systemd is not seeing the exit code or is ignoring it and issues a sigkill after a timeout period. I'm having a hard time seeing if my program is truly exiting or if somehow systemd is actually seeing a different exit code. Has anyone seen anything similar? Can you tell us more about your code? You probably have a thread that you don't complete when the daemon is stopped ---------------------------------------------------------------------- guest65233 · 2020-02-12 21:07 Yeah, I think that was the point - the program was not receiving the signal to terminate. The example I cited shows how to listen for these signals by setting up a SigActionHandler (defined in the baseunix unit). I've used the lazdaemon package and I saw the same thing our OP saw. Setting up a SigActionHandler to listen for SIGTERM will solve the problem. Create a thread and when the signal arrives terminate it... Does the lazdaemon package do this? ---------------------------------------------------------------------- Renat.Su · 2020-02-13 06:54 Yes. I use the heirs of TLazDaemon. Therefore, you must handle SIGnal (stop or other) or complete any worker thread without delay. For example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TWorkersHandler.ServerStop(Sender: TObject);begin... ...  FTaskWorkerThread.TerminateWorker;... ...end;  procedure TgTaskWorkerThread.TerminateWorker;begin...  Terminate;  RTLeventSetEvent(FTerminateEvent);...end; ---------------------------------------------------------------------- PascalDragon · 2020-02-13 08:10 Quote from: lucamar on December 28, 2019, 06:02:30 pmI don't know about daemons but normal FP/Lazarus programs see neither sig_term or sig_kill; the system just force-shuts them down. This is not entirely correct. It's just that a normal FPC/Lazarus program (or in fact any program) just does not react to SIGTERM and thus the system uses the default handling, which is to simply terminate the program (SIGKILL can't be intercepted; it's a last resort signal after all). There is nothing stopping a FPC/Lazarus program from reacting to that signal in some meaningful way (e.g. save files and then terminate). In fact for daemons this is handled by FPC's default implementation (see SysInitDaemonApp in $fpcdir/packages/fcl- extra/src/unix/daemonapp.inc). ---------------------------------------------------------------------- guest65233 · 2020-02-13 17:59 QuoteIn fact for daemons this is handled by FPC's default implementation (see SysInitDaemonApp in $fpcdir/packages/fcl- extra/src/unix/daemonapp.inc). But it is not handled in daemons written with the lazdaemon package on an Ubuntu 18 installation with systemd As the OP said: QuoteHowever systemd is not seeing the exit code or is ignoring it and issues a sigkill after a timeout period. Perhaps I am doing it wrong. I would appreciate very much if anyone might spare a few minutes to review the attached minimal example using the lazdameon and discuss any errors or omissions: ---------------------------------------------------------------------- Cyrax · 2020-02-13 23:18 Quote from: cdesim on February 13, 2020, 06:59:26 pmQuoteIn fact for daemons this is handled by FPC's default implementation (see SysInitDaemonApp in $fpcdir/packages/fcl- extra/src/unix/daemonapp.inc). But it is not handled in daemons written with the lazdaemon package on an Ubuntu 18 installation with systemd As the OP said: QuoteHowever systemd is not seeing the exit code or is ignoring it and issues a sigkill after a timeout period. Perhaps I am doing it wrong. I would appreciate very much if anyone might spare a few minutes to review the attached minimal example using the lazdameon and discuss any errors or omissions: Can you test your daemon app by compiling it using FPC trunk? There was problem how signal handling were set up : https://bugs.freepascal.org/view.php?id=32172 ---------------------------------------------------------------------- PascalDragon · 2020-02-14 08:30 Quote from: cdesim on February 13, 2020, 06:59:26 pmQuoteIn fact for daemons this is handled by FPC's default implementation (see SysInitDaemonApp in $fpcdir/packages/fcl- extra/src/unix/daemonapp.inc). But it is not handled in daemons written with the lazdaemon package on an Ubuntu 18 installation with systemd Turns out I only looked at trunk. In FPC 3.0.4 that might indeed be true. Use FPC 3.2 instead then it should work. ---------------------------------------------------------------------- guest65233 · 2020-02-14 14:07 Yes, I am using FPC 3.0.4 - thank you, everybody, for your assistance. I appreciate it! Despite whatever incongruity systemd may have introduced we can avoid 3.0.4's lazdeamon package altogether if we want to write a daemon for a linux box: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program daemond; uses  cthreads,  BaseUnix,  SomeOtherUnit; var  bTerm: boolean;  aTerm: pSigActionRec;  aThread: TThreadDefinedInSomeOtherUnit;   procedure ProcessSig(sig: longint); cdecl;  begin    bTerm := (bTerm) or (sig = SIGTERM);  end; begin  bTerm := False;  New(aTerm);  aTerm^.sa_handler := SigActionHandler(@ProcessSig);  FillChar(aTerm^.sa_mask, SizeOf(aTerm^.sa_mask), #0);  aTerm^.sa_flags := 0;  {$IFDEF LINUX}  aTerm^.sa_restorer := nil;  {$ENDIF}  fpSigAction(SIGTERM, aTerm, nil);  if fpFork = 0 then  begin    Close(input);    Close(output);  Assign(output, '/dev/null');    ReWrite(output);    Close(stderr);    Assign(stderr, '/dev/null');    ReWrite(stderr);    aThread := TThreadDefinedInSomeOtherUnit.Create;    try      repeat        fpSleep(1);      until bTerm;    finally      aThread.Terminate;      aThread.WaitFor;      aThread.Free;    end;  end;  Dispose(aTerm);end.