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