Recent

Author Topic: lazdaemon, systemd does not see the correct exit code  (Read 1068 times)

bhaugland

  • Newbie
  • Posts: 2
lazdaemon, systemd does not see the correct exit code
« on: December 28, 2019, 05:29:07 pm »
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

  • Hero Member
  • *****
  • Posts: 2973
Re: lazdaemon, systemd does not see the correct exit code
« Reply #1 on: December 28, 2019, 06:02:30 pm »
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.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

guest65233

  • Guest
Re: lazdaemon, systemd does not see the correct exit code
« Reply #2 on: February 12, 2020, 08:08:52 pm »
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][+][-]
  1. {---------------------------------------------------------------------------
  2.                                  CncWare
  3.                            (c) Copyright 2000
  4.  ---------------------------------------------------------------------------
  5.   Filename..: daemon.pp
  6.   Programmer: Ken J. Wright
  7.   Date......: 03/21/2000
  8.  
  9.   Purpose - Program to demonstrate construction of a Linux daemon.
  10.  
  11.   Usage:
  12.     1) Compile this program.
  13.     2) Run it. You will be immediately returned to a command prompt.
  14.     3) Issue the command: ps ax|grep daemon. This will show you the process
  15.        id of the program "daemon" that you just ran.
  16.     4) Issue the command: tail -f daemon.log. This let's you watch the log file
  17.        being filled with the message in the code below. Press Ctrl/c to break
  18.        out of the tail command.
  19.     5) Issue the command: kill -HUP pid. pid is the process number you saw with
  20.        the ps command above. You will see that a new log file has been created.
  21.     6) Issue the command: kill -TERM pid. This will stop the daemon. Issuing the
  22.        ps command above, you will see that the daemon is no longer running.
  23.  
  24. -------------------------------<< REVISIONS >>--------------------------------
  25.   Ver  |    Date    | Prog | Decription
  26. -------+------------+------+--------------------------------------------------
  27.   1.00 | 03/21/2000 | kjw  | Initial release.
  28.   1.01 | 03/21/2000 | kjw  | Forgot to close input, output, & stderr.
  29. ------------------------------------------------------------------------------
  30. }
  31. Program Daemon;
  32. uses SysUtils,BaseUnix;
  33. Var
  34.    { vars for daemonizing }
  35.    bHup,
  36.    bTerm : boolean;
  37.    fLog : text;
  38.    logname : string;
  39.    aOld,
  40.    aTerm,
  41.    aHup : pSigActionRec;
  42.    ps1  : psigset;
  43.    sSet : cardinal;
  44.    pid  : pid_t;
  45.    secs : longint;
  46.    zerosigs : sigset_t;
  47.    hr,mn,sc,sc100 : word;
  48.  
  49. { handle SIGHUP & SIGTERM }
  50. procedure DoSig(sig : longint);cdecl;
  51. begin
  52.    case sig of
  53.       SIGHUP : bHup := true;
  54.       SIGTERM : bTerm := true;
  55.    end;
  56. end;
  57.  
  58. { open the log file }
  59. Procedure NewLog;
  60. Begin
  61.    Assign(fLog,logname);
  62.    Rewrite(fLog);
  63.    Writeln(flog,'Log created at ',formatdatetime('hh:nn:ss',now));
  64.    Close(fLog);
  65. End;
  66.  
  67. Begin
  68.    logname := 'daemon.log';
  69.    secs := 10;
  70.    fpsigemptyset(zerosigs);
  71.  
  72.    { set global daemon booleans }
  73.    bHup := true; { to open log file }
  74.    bTerm := false;
  75.  
  76.    { block all signals except -HUP & -TERM }
  77.    sSet := $ffffbffe;
  78.    ps1 := @sSet;
  79.    fpsigprocmask(sig_block,ps1,nil);
  80.  
  81.    { setup the signal handlers }
  82.    new(aOld);
  83.    new(aHup);
  84.    new(aTerm);
  85.    aTerm^.sa_handler{.sh} := SigactionHandler(@DoSig);
  86.  
  87.    aTerm^.sa_mask := zerosigs;
  88.    aTerm^.sa_flags := 0;
  89.    {$ifndef BSD}                {Linux'ism}
  90.     aTerm^.sa_restorer := nil;
  91.    {$endif}
  92.    aHup^.sa_handler := SigactionHandler(@DoSig);
  93.    aHup^.sa_mask := zerosigs;
  94.    aHup^.sa_flags := 0;
  95.    {$ifndef BSD}                {Linux'ism}
  96.     aHup^.sa_restorer := nil;
  97.    {$endif}
  98.    fpSigAction(SIGTERM,aTerm,aOld);
  99.    fpSigAction(SIGHUP,aHup,aOld);
  100.  
  101.    { daemonize }
  102.    pid := fpFork;
  103.    Case pid of
  104.       0 : Begin { we are in the child }
  105.          Close(input);  { close standard in }
  106.          Close(output); { close standard out }
  107.          Assign(output,'/dev/null');
  108.          ReWrite(output);
  109.          Close(stderr); { close standard error }
  110.          Assign(stderr,'/dev/null');
  111.          ReWrite(stderr);
  112.       End;
  113.       -1 : secs := 0;     { forking error, so run as non-daemon }
  114.       Else Halt;          { successful fork, so parent dies }
  115.    End;
  116.  
  117.    { begin processing loop }
  118.    Repeat
  119.       If bHup Then Begin
  120.          {$I-}
  121.          Close(fLog);
  122.          {$I+}
  123.          IOResult;
  124.          NewLog;
  125.          bHup := false;
  126.       End;
  127.       {----------------------}
  128.       { Do your daemon stuff }
  129.       Append(flog);
  130.       Writeln(flog,'daemon code activated at ',formatdatetime('hh:nn:ss',now));
  131.       Close(fLog);
  132.       { the following output goes to the bit bucket }
  133.       Writeln('daemon code activated at ',hr:0,':',mn:0,':',sc:0);
  134.       {----------------------}
  135.       If bTerm Then
  136.          BREAK
  137.       Else
  138.          { wait a while }
  139.          fpSelect(0,nil,nil,nil,secs*1000);
  140.    Until bTerm;
  141. End.
  142.  

lucamar

  • Hero Member
  • *****
  • Posts: 2973
Re: lazdaemon, systemd does not see the correct exit code
« Reply #3 on: February 12, 2020, 08:32:48 pm »
cdesim, please, see the wiki page about the Forum to learn how best to share code in the forum.

Thanks ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Renat.Su

  • Full Member
  • ***
  • Posts: 178
    • Renat.Su
Re: lazdaemon, systemd does not see the correct exit code
« Reply #4 on: February 12, 2020, 09:48:38 pm »
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?
Can you tell us more about your code? You probably have a thread that you don't complete when the daemon is stopped

guest65233

  • Guest
Re: lazdaemon, systemd does not see the correct exit code
« Reply #5 on: February 12, 2020, 10:07:06 pm »
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

  • Full Member
  • ***
  • Posts: 178
    • Renat.Su
Re: lazdaemon, systemd does not see the correct exit code
« Reply #6 on: February 13, 2020, 07:54:37 am »
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][+][-]
  1. procedure TWorkersHandler.ServerStop(Sender: TObject);
  2. begin
  3. ... ...
  4.   FTaskWorkerThread.TerminateWorker;
  5. ... ...
  6. end;
  7.  
  8. procedure TgTaskWorkerThread.TerminateWorker;
  9. begin
  10. ...
  11.   Terminate;
  12.   RTLeventSetEvent(FTerminateEvent);
  13. ...
  14. end;
 

PascalDragon

  • Hero Member
  • *****
  • Posts: 1950
  • Compiler Developer
Re: lazdaemon, systemd does not see the correct exit code
« Reply #7 on: February 13, 2020, 09:10:58 am »
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.

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).
« Last Edit: February 14, 2020, 09:28:19 am by PascalDragon »

guest65233

  • Guest
Re: lazdaemon, systemd does not see the correct exit code
« Reply #8 on: February 13, 2020, 06:59:26 pm »
Quote
In 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:

Quote
However 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

  • Hero Member
  • *****
  • Posts: 829
Re: lazdaemon, systemd does not see the correct exit code
« Reply #9 on: February 14, 2020, 12:18:38 am »
Quote
In 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:

Quote
However 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

  • Hero Member
  • *****
  • Posts: 1950
  • Compiler Developer
Re: lazdaemon, systemd does not see the correct exit code
« Reply #10 on: February 14, 2020, 09:30:06 am »
Quote
In 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

  • Guest
Re: lazdaemon, systemd does not see the correct exit code
« Reply #11 on: February 14, 2020, 03:07:44 pm »
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][+][-]
  1. program daemond;
  2.  
  3. uses
  4.   cthreads,
  5.   BaseUnix,
  6.   SomeOtherUnit;
  7.  
  8. var
  9.   bTerm: boolean;
  10.   aTerm: pSigActionRec;
  11.   aThread: TThreadDefinedInSomeOtherUnit;
  12.  
  13.   procedure ProcessSig(sig: longint); cdecl;
  14.   begin
  15.     bTerm := (bTerm) or (sig = SIGTERM);
  16.   end;
  17.  
  18. begin
  19.   bTerm := False;
  20.   New(aTerm);
  21.   aTerm^.sa_handler := SigActionHandler(@ProcessSig);
  22.   FillChar(aTerm^.sa_mask, SizeOf(aTerm^.sa_mask), #0);
  23.   aTerm^.sa_flags := 0;
  24.   {$IFDEF LINUX}
  25.   aTerm^.sa_restorer := nil;
  26.   {$ENDIF}
  27.   fpSigAction(SIGTERM, aTerm, nil);
  28.   if fpFork = 0 then
  29.   begin
  30.     Close(input);
  31.     Close(output);
  32.     Assign(output, '/dev/null');
  33.     ReWrite(output);
  34.     Close(stderr);
  35.     Assign(stderr, '/dev/null');
  36.     ReWrite(stderr);
  37.     aThread := TThreadDefinedInSomeOtherUnit.Create;
  38.     try
  39.       repeat
  40.         fpSleep(1);
  41.       until bTerm;
  42.     finally
  43.       aThread.Terminate;
  44.       aThread.WaitFor;
  45.       aThread.Free;
  46.     end;
  47.   end;
  48.   Dispose(aTerm);
  49. end.
  50.  

 

TinyPortal © 2005-2018