Recent

Author Topic: Windows service, self stop on condition  (Read 6332 times)

cris75

  • New Member
  • *
  • Posts: 24
Windows service, self stop on condition
« on: August 11, 2021, 12:27:01 pm »
Hi,
with the help of the wiki and this (quite old) discussion https://forum.lazarus.freepascal.org/index.php/topic,20274.0.html, I successfully wrote some windows services, and they work as expected;
as a base of developing I used the approach by Udo Schmal here, https://www.gocher.me/Daemon in which he sets the FreeOnTerminate property of the thread to true when he starts the service;
when the service is started, I usually check for the existence of a config file from which I retrieve a handful of settings to be used in the execution;
as of today, if the config file does not exist I just don't go on and terminate the thread, but a thing I thought it was easy to do, that I've been not able to (and would like), is to "stop" (automatically) the service if this condition is met; probably I'm missing something..
if I'm not getting confused, I saw more than one time an "example" of what I'm saying, of a windows service that once started (by pressing "start" or with "net start servicename") automatically stops (for some reason, obviously), how could I reproduce this behavior?
Do you think it's possible?
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #1 on: August 12, 2021, 09:50:36 am »
..no reply of any kind until now to my post.. I'm wondering if my question is silly or poorly asked.. If so forgive me in advance.. :'(
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

Bart

  • Hero Member
  • *****
  • Posts: 4515
    • Bart en Mariska's Webstek
Re: Windows service, self stop on condition
« Reply #2 on: August 12, 2021, 10:30:06 am »
It's a program, so you can stop it like any other program.
If it's derived from TCustomApplication then Application.Terminate should do.
And, of course, you could always do Halt();

You must have the OS configered not to restart this service when it stops.

Bart

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #3 on: August 12, 2021, 12:28:52 pm »
Quote
You must have the OS configered not to restart this service when it stops

I don't think the operating system will restart the service if this one is "stopped" as you would usually do via services manager or by shell command "net stop service"..
but I assume maybe I don't understand what you're trying to explain me..  ::)

to be clear, this is the execute method of the thread:

Code: Pascal  [Select][+][-]
  1. procedure TDaemonThread.Execute;
  2. var i: integer;
  3. begin
  4.   Parent.EventLog1.Info('Begin of Main thread');
  5.  
  6.   i:= 0;
  7.   Application.Log(etDebug, 'Thread.Execute');
  8.   try
  9.     repeat
  10.       Sleep(1000); //milliseconds
  11.       inc(i);
  12.       Application.Log(etDebug, 'Thread.Loop ' + Format('Tick :%d', [i]));
  13.       if i = 5 then Terminate;  // this is an example condition for which the thread will be terminated
  14.     until Terminated;  // the loop will be exited because of the thread terminated
  15.   finally
  16.     Application.Log(etDebug, 'Thread.LoopStopped');
  17.   end;
  18.   { at this point how could I stop the service? }
  19. end;

I suppose that to get the behavior I want, the daemon has to know about the termination of the thread and somehow "stop" itself;
I use "Parent" declared in line 24 (see attached code) for EventLog, I thought "Parent.Stop" could have done it (stop the service) but i was wrong..
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

GetMem

  • Hero Member
  • *****
  • Posts: 3516
Re: Windows service, self stop on condition
« Reply #4 on: August 12, 2021, 01:21:43 pm »
You should pass GenericDaemon to DaemonThread via the constructor. Something like this(not tested):

Code: Pascal  [Select][+][-]
  1.   TGenericDaemon = class; //forward declaration
  2.  
  3.   TDaemonThread = class(TThread)
  4.     Parent: TGenericDaemon;
  5.     FGenericDaemon: TGenericDaemon;  //add this
  6.     procedure SetParent(AOwner: TGenericDaemon);
  7.   protected
  8.     procedure Execute; override; //execute should be in protected section
  9.   public
  10.     constructor Create(AGenericDaemon: TGenericDaemon);   //add this                                                          
  11.     destructor Destroy; override;
  12.   end;

Then on constructor create, assign GenericDaemon to a local variable:
Code: Pascal  [Select][+][-]
  1. constructor TDaemonThread.Create(AGenericDaemon: TGenericDaemon);
  2. begin
  3.   inherited Create(True);
  4.   FGenericDaemon := AGenericDaemon;
  5. end;    

On Daemon start:
Code: Pascal  [Select][+][-]
  1.   //...
  2.   FThread:= TDaemonThread.Create(Self); //add this
  3.   FThread.SetParent(self);
  4.   FThread.FreeOnTerminate:= true;
  5.   FThread.Start;

Finally on thread execute:
Code: Pascal  [Select][+][-]
  1. procedure TDaemonThread.Execute;
  2. var i: integer;
  3. begin
  4.   Parent.EventLog1.Info('Begin of Main thread');
  5.  
  6.   i:= 0;
  7.   Application.Log(etDebug, 'Thread.Execute');
  8.   try
  9.     repeat
  10.       Sleep(1000); //milliseconds
  11.       inc(i);
  12.       Application.Log(etDebug, 'Thread.Loop ' + Format('Tick :%d', [i]));
  13.       if i = 5 then FGenericDaemon.Stop;//add this
  14.     until Terminated;  // the loop will be exited because of the thread terminated
  15.   finally
  16.     Application.Log(etDebug, 'Thread.LoopStopped');
  17.   end;
  18.   { at this point how could I stop the service? }
  19. end;
  20.  

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #5 on: August 12, 2021, 02:16:26 pm »
Thank you.
It compiles and run, but it seems it doesn't work, in windows services manager it is not shown as stopped (as I expected)  :'(
attached screenshot;
btw.. I can't manually stop the service anymore, I have to kill genericdaemon.exe process to uninstall the service now..

this is the log:
Code: [Select]
genericdaemon [2021-08-12 13:55:58.714 Debug] DaemonMapper.Create
genericdaemon [2021-08-12 13:55:58.715 Debug] DaemonMapper.Createted
genericdaemon [2021-08-12 13:55:58.715 Debug] DaemonMapper.Run
genericdaemon [2021-08-12 13:55:58.718 Debug] Daemon.Start: true
genericdaemon [2021-08-12 13:55:58.718 Debug] Daemon.Execute: false
genericdaemon [2021-08-12 13:55:58.718 Debug] Thread.Execute
genericdaemon [2021-08-12 13:55:59.734 Debug] Thread.Loop Tick :1
genericdaemon [2021-08-12 13:56:00.736 Debug] Thread.Loop Tick :2
genericdaemon [2021-08-12 13:56:01.739 Debug] Thread.Loop Tick :3
genericdaemon [2021-08-12 13:56:02.749 Debug] Thread.Loop Tick :4
genericdaemon [2021-08-12 13:56:03.749 Debug] Thread.Loop Tick :5
genericdaemon [2021-08-12 13:56:03.749 Debug] Daemon.Stop: true
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

GetMem

  • Hero Member
  • *****
  • Posts: 3516
Re: Windows service, self stop on condition
« Reply #6 on: August 12, 2021, 02:20:40 pm »
According to your log, the Service stopped. Please try to add:
Code: Pascal  [Select][+][-]
  1. function TGenericDaemon.Stop: boolean;
  2. begin
  3.   result:= inherited Stop;
  4.   Application.Log(etDebug, 'Daemon.Stop: ' + BoolToStr(result));
  5.  
  6.   FThread.Terminate;
  7.   FThread.WaitFor;
  8.  
  9.   FThread:= nil;
  10.   FreeAndNil(EventLog1);
  11.   Application.Terminate; //<-This line
  12. end;

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #7 on: August 12, 2021, 02:30:53 pm »
yes, you are right, the log say so..
..but the process is still there running..
and services manager still shows it running

tried your last suggestion, no change for me  :'(

p.s.
still can't manually stop it, have to kill the process
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #8 on: August 12, 2021, 08:15:01 pm »
I double-checked everything, it seems okay, can't understand why the process doesn't close.. and why manually stopping the service hangs and return an error..

Does somebody have a clue..?
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1690
  • Former Delphi 1-7, 10.2 user
Re: Windows service, self stop on condition
« Reply #9 on: August 13, 2021, 01:47:42 am »
Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 x86_64 Xcode 13.1
Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 aarch64 Xcode 13.1
Lazarus 2.3, FPC 3.2.2 FreeBSD 13.0 amd64 VM
Lazarus 2.3, FPC 3.2.2 FreeBSD 12.2 amd64 VM
Lazarus 2.1 r61574 FPC 3.0.4 Ubuntu 20.04 VM
Lazarus 2.0.10 FPC 3.2.0 Win10 VM

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #10 on: August 13, 2021, 09:49:44 am »
Thank you all for your time;
thank you @trev, I'm going to give a look..
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

cris75

  • New Member
  • *
  • Posts: 24
Re: Windows service, self stop on condition
« Reply #11 on: August 13, 2021, 12:56:48 pm »
@trev I checked the link, thank you
..if I understood correctly, it should be done via ServiceManager
my approach was to add a private method to TGenericDaemon to connect to the service control manager and invoke the "stop" via TServiceManager method StopService
I assumed that my service is certainly running at the moment of the "self-stop service" invocation,
I limited to modify slightly the "IsServiceRunning" function in the Wiki for ServiceManager here https://wiki.freepascal.org/ServiceManager
now it works, but was asking myself if the approach is ok and/or I did it correctly or the result is a mess of code that produces a functioning result for a matter of luck...
if someone has some spare time to give a look at the code and/or review it i'd be glad, thank you all
the code is attached  :-[
Lazarus: 2.0.10
FPC: 3.2.0
32+64bit
Current OS: Win10 64bit

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1690
  • Former Delphi 1-7, 10.2 user
Re: Windows service, self stop on condition
« Reply #12 on: August 13, 2021, 01:18:27 pm »
You're welcome. I'm glad it helped.
Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 x86_64 Xcode 13.1
Lazarus 2.3, FPC 3.3.1 macOS 12.0.1 aarch64 Xcode 13.1
Lazarus 2.3, FPC 3.2.2 FreeBSD 13.0 amd64 VM
Lazarus 2.3, FPC 3.2.2 FreeBSD 12.2 amd64 VM
Lazarus 2.1 r61574 FPC 3.0.4 Ubuntu 20.04 VM
Lazarus 2.0.10 FPC 3.2.0 Win10 VM

 

TinyPortal © 2005-2018