class Puppet::Util::Windows::Daemon

The Daemon class, based on the chef/win32-service implementation

Constants

CONTINUE_PENDING

Service has received a signal to resume but is not yet running

CONTROL_CONTINUE

Notifies service that it should resume

CONTROL_INTERROGATE

Notifies service that it should return its current status information

CONTROL_NETBINDADD

Notifies a service that there is a new component for binding

CONTROL_NETBINDDISABLE

Notifies a service that a component for binding has been disabled

CONTROL_NETBINDENABLE

Notifies a service that a component for binding has been enabled

CONTROL_NETBINDREMOVE

Notifies a service that a component for binding has been removed

CONTROL_PARAMCHANGE

Notifies a service that its parameters have changed

CONTROL_PAUSE

Notifies service that it should pause

CONTROL_STOP

Notifies service that it should stop

ERROR_CALL_NOT_IMPLEMENTED
IDLE
IDLE_CONTROL_CODE

Misc

NO_ERROR
PAUSED

Service is paused

PAUSE_PENDING

Service has received a signal to pause but is not yet paused

RUNNING

Service is running

START_PENDING

Service has received a start signal but is not yet running

STOPPED

Service is not running

STOP_PENDING

Service has received a stop signal but is not yet stopped

Service_Ctrl_ex

Handles control signals from the service control manager.

Service_Main

Called by the service control manager after the call to StartServiceCtrlDispatcher.

SetTheServiceStatus

Wraps SetServiceStatus.

ThreadProc
WAIT_FAILED
WAIT_OBJECT_0
WAIT_TIMEOUT

Public Class Methods

mainloop() click to toggle source

This is a shortcut for Daemon.new + Daemon#mainloop.

    # File lib/puppet/util/windows/daemon.rb
212 def self.mainloop
213   self.new.mainloop
214 end

Public Instance Methods

mainloop() click to toggle source

This is the method that actually puts your code into a loop and allows it to run as a service. The code that is actually run while in the mainloop is what you defined in your own Daemon#service_main method.

    # File lib/puppet/util/windows/daemon.rb
220 def mainloop
221   @@waiting_control_code = IDLE_CONTROL_CODE
222   @@dwServiceState = 0
223 
224   # Redirect STDIN, STDOUT and STDERR to the NUL device if they're still
225   # associated with a tty. This helps newbs avoid Errno::EBADF errors.
226   STDIN.reopen('NUL') if STDIN.isatty
227   STDOUT.reopen('NUL') if STDOUT.isatty
228   STDERR.reopen('NUL') if STDERR.isatty
229 
230   # Calling init here so that init failures never even tries to start the
231   # service. Of course that means that init methods must be very quick
232   # because the SCM will be receiving no START_PENDING messages while
233   # init's running.
234   #
235   # TODO: Fix?
236   service_init() if respond_to?('service_init')
237 
238   # Create the event to signal the service to start.
239   @@hStartEvent = CreateEventW(nil, 1, 0, nil)
240 
241   if @@hStartEvent == 0
242     raise SystemCallError.new('CreateEvent', FFI.errno)
243   end
244 
245   # Create the event to signal the service to stop.
246   @@hStopEvent = CreateEventW(nil, 1, 0, nil)
247 
248   if @@hStopEvent == 0
249     raise SystemCallError.new('CreateEvent', FFI.errno)
250   end
251 
252   # Create the event to signal the service that stop has completed
253   @@hStopCompletedEvent = CreateEventW(nil, 1, 0, nil)
254 
255   if @@hStopCompletedEvent == 0
256     raise SystemCallError.new('CreateEvent', FFI.errno)
257   end
258 
259   hThread = CreateThread(nil, 0, ThreadProc, Service_Main, 0, nil)
260 
261   if hThread == 0
262     raise SystemCallError.new('CreateThread', FFI.errno)
263   end
264 
265   events = FFI::MemoryPointer.new(:pointer, 2)
266   events.put_pointer(0, FFI::Pointer.new(hThread))
267   events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent))
268 
269   while ((index = WaitForMultipleObjects(2, events, 0, 1000)) == WAIT_TIMEOUT) do
270   end
271 
272   if index == WAIT_FAILED
273     raise SystemCallError.new('WaitForMultipleObjects', FFI.errno)
274   end
275 
276   # The thread exited, so the show is off.
277   if index == WAIT_OBJECT_0
278     raise "Service_Main thread exited abnormally"
279   end
280 
281   thr = Thread.new do
282     begin
283       while(WaitForSingleObject(@@hStopEvent, 1000) == WAIT_TIMEOUT)
284         # Check to see if anything interesting has been signaled
285         case @@waiting_control_code
286           when SERVICE_CONTROL_PAUSE
287             service_pause() if respond_to?('service_pause')
288           when SERVICE_CONTROL_CONTINUE
289             service_resume() if respond_to?('service_resume')
290           when SERVICE_CONTROL_INTERROGATE
291             service_interrogate() if respond_to?('service_interrogate')
292           when SERVICE_CONTROL_SHUTDOWN
293             service_shutdown() if respond_to?('service_shutdown')
294           when SERVICE_CONTROL_PARAMCHANGE
295             service_paramchange() if respond_to?('service_paramchange')
296           when SERVICE_CONTROL_NETBINDADD
297             service_netbindadd() if respond_to?('service_netbindadd')
298           when SERVICE_CONTROL_NETBINDREMOVE
299             service_netbindremove() if respond_to?('service_netbindremove')
300           when SERVICE_CONTROL_NETBINDENABLE
301             service_netbindenable() if respond_to?('service_netbindenable')
302           when SERVICE_CONTROL_NETBINDDISABLE
303             service_netbinddisable() if respond_to?('service_netbinddisable')
304         end
305         @@waiting_control_code = IDLE_CONTROL_CODE
306       end
307 
308       service_stop() if respond_to?('service_stop')
309     ensure
310       SetEvent(@@hStopCompletedEvent)
311     end
312   end
313 
314   if respond_to?('service_main')
315     service_main(*@@Argv)
316   end
317 
318   thr.join
319 end
running?() click to toggle source

Returns whether or not the service is in a running state, i.e. the service status is either RUNNING, PAUSED or IDLE.

This is typically used within your service_main method to setup the main loop. For example:

class MyDaemon < Daemon
   def service_main
      while running?
         # Your main loop here
      end
   end
end
    # File lib/puppet/util/windows/daemon.rb
356 def running?
357   [SERVICE_RUNNING, SERVICE_PAUSED, 0].include?(@@dwServiceState)
358 end
state() click to toggle source

Returns the state of the service (as an constant integer) which can be any of the service status constants, e.g. RUNNING, PAUSED, etc.

This method is typically used within your service_main method to setup the loop. For example:

class MyDaemon < Daemon
  def service_main
    while state == RUNNING || state == PAUSED || state == IDLE
      # Your main loop here
    end
  end
end

See the Daemon#running? method for an abstraction of the above code.

    # File lib/puppet/util/windows/daemon.rb
337 def state
338   @@dwServiceState
339 end